Skip to content

Commit

Permalink
Allow retrieving logs of apps in crashed state (#14419)
Browse files Browse the repository at this point in the history
  • Loading branch information
Qubad786 authored Sep 5, 2024
1 parent 82e0a76 commit f59e87a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 12 deletions.
3 changes: 2 additions & 1 deletion src/middlewared/middlewared/plugins/apps/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .ix_apps.path import get_installed_app_path, get_installed_app_version_path
from .ix_apps.query import list_apps
from .ix_apps.setup import setup_install_app_dir
from .ix_apps.utils import AppState
from .version_utils import get_latest_version_from_app_versions


Expand All @@ -33,7 +34,7 @@ class Config:
'app_entry',
Str('name'),
Str('id'),
Str('state', enum=['STOPPED', 'DEPLOYING', 'RUNNING']),
Str('state', enum=[state.value for state in AppState]),
Bool('upgrade_available'),
Str('human_version'),
Str('version'),
Expand Down
25 changes: 17 additions & 8 deletions src/middlewared/middlewared/plugins/apps/ix_apps/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .metadata import get_collective_config, get_collective_metadata
from .lifecycle import get_current_app_config
from .path import get_app_parent_config_path
from .utils import get_app_name_from_project_name, normalize_reference, PROJECT_PREFIX
from .utils import AppState, ContainerState, get_app_name_from_project_name, normalize_reference, PROJECT_PREFIX


COMPOSE_SERVICE_KEY: str = 'com.docker.compose.service'
Expand Down Expand Up @@ -86,12 +86,18 @@ def list_apps(
# When we stop docker service and start it again - the containers can be in exited
# state which means we need to account for this.
state = 'STOPPED'
exited_containers = 0
for container in workloads['container_details']:
if container['state'] == 'starting':
state = 'DEPLOYING'
if container['state'] == ContainerState.STARTING.value:
state = AppState.DEPLOYING.value
break
elif container['state'] == 'running':
state = 'RUNNING'
elif container['state'] == ContainerState.RUNNING.value:
state = AppState.RUNNING.value
elif container['state'] == ContainerState.EXITED.value:
exited_containers += 1
else:
if exited_containers != 0 and exited_containers == len(workloads['container_details']):
state = AppState.CRASHED.value

app_metadata = metadata[app_name]
active_workloads = get_default_workload_values() if state == 'STOPPED' else workloads
Expand Down Expand Up @@ -127,7 +133,7 @@ def list_apps(
'name': entry.name,
'id': entry.name,
'active_workloads': get_default_workload_values(),
'state': 'STOPPED',
'state': AppState.STOPPED.value,
'upgrade_available': upgrade_available_for_app(train_to_apps_version_mapping, app_metadata),
'image_updates_available': False,
**app_metadata | {'portals': normalize_portal_uris(app_metadata['portals'], host_ip)}
Expand Down Expand Up @@ -187,9 +193,12 @@ def translate_resources_to_desired_workflow(app_resources: dict) -> dict:

if container['State']['Status'].lower() == 'running':
if health_config := container['State'].get('Health'):
state = 'running' if health_config['Status'] == 'healthy' else 'starting'
if health_config['Status'] == 'healthy':
state = ContainerState.RUNNING.value
else:
state = ContainerState.STARTING.value
else:
state = 'running'
state = ContainerState.RUNNING.value
else:
state = 'exited'

Expand Down
15 changes: 15 additions & 0 deletions src/middlewared/middlewared/plugins/apps/ix_apps/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import enum

from catalog_reader.library import RE_VERSION # noqa
from middlewared.plugins.apps_images.utils import normalize_reference # noqa
from middlewared.plugins.apps.schema_utils import CONTEXT_KEY_NAME # noqa
from middlewared.plugins.apps.utils import IX_APPS_MOUNT_PATH, PROJECT_PREFIX, run # noqa


class AppState(enum.Enum):
CRASHED = 'CRASHED'
DEPLOYING = 'DEPLOYING'
RUNNING = 'RUNNING'
STOPPED = 'STOPPED'


class ContainerState(enum.Enum):
EXITED = 'exited'
RUNNING = 'running'
STARTING = 'starting'


def get_app_name_from_project_name(project_name: str) -> str:
return project_name[len(PROJECT_PREFIX):]
5 changes: 3 additions & 2 deletions src/middlewared/middlewared/plugins/apps/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from middlewared.service import CallError
from middlewared.validators import Range

from .ix_apps.utils import AppState
from .ix_apps.docker.utils import get_docker_client


Expand Down Expand Up @@ -38,8 +39,8 @@ def __init__(self, *args, **kwargs):

def validate_log_args(self, app_name, container_id):
app = self.middleware.call_sync('app.get_instance', app_name)
if app['state'] not in ('RUNNING', 'DEPLOYING'):
raise CallError(f'App "{app_name}" is not running')
if app['state'] not in (AppState.CRASHED.value, AppState.RUNNING.value, AppState.DEPLOYING.value):
raise CallError(f'Unable to retrieve logs of stopped {app_name!r} app')

if not any(c['id'] == container_id for c in app['active_workloads']['container_details']):
raise CallError(f'Container "{container_id}" not found in app "{app_name}"', errno=errno.ENOENT)
Expand Down
5 changes: 4 additions & 1 deletion src/middlewared/middlewared/plugins/apps/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from middlewared.utils.gpu import get_nvidia_gpus

from .ix_apps.utils import ContainerState
from .resources_utils import get_normalized_gpu_choices


Expand Down Expand Up @@ -43,7 +44,9 @@ async def container_ids(self, app_name, options):
'id': c['id'],
} for c in (
await self.middleware.call('app.get_instance', app_name)
)['active_workloads']['container_details'] if (options['alive_only'] is False or c['state'] == 'running')
)['active_workloads']['container_details'] if (
options['alive_only'] is False or ContainerState(c['state']) == ContainerState.RUNNING
)
}

@accepts(Str('app_name'), roles=['APPS_READ'])
Expand Down

0 comments on commit f59e87a

Please sign in to comment.