11# pylint: disable=too-many-arguments
22
33import logging
4- from asyncio import Lock
5- from typing import Annotated , Any , Final
4+ from typing import Any
65
7- from aiodocker import DockerError
8- from common_library .json_serialization import json_loads
9- from fastapi import APIRouter , Depends , HTTPException
6+ from fastapi import APIRouter , HTTPException
107from fastapi import Path as PathParam
118from fastapi import Query , Request , status
129from models_library .api_schemas_directorv2 .dynamic_services import ContainersComposeSpec
1310from models_library .api_schemas_dynamic_sidecar .containers import (
14- ActivityInfo ,
1511 ActivityInfoOrNone ,
1612)
17- from pydantic import TypeAdapter , ValidationError
18- from servicelib .container_utils import (
19- ContainerExecCommandFailedError ,
20- ContainerExecContainerNotFoundError ,
21- ContainerExecTimeoutError ,
22- run_command_in_container ,
23- )
2413from servicelib .fastapi .requests_decorators import cancel_on_disconnect
2514
26- from ...core .docker_utils import docker_client
27- from ...core .settings import ApplicationSettings
28- from ...core .validation import parse_compose_spec
29- from ...models .shared_store import SharedStore
3015from ...services import containers
31- from ._dependencies import get_container_restart_lock , get_settings , get_shared_store
32-
33- _INACTIVE_FOR_LONG_TIME : Final [int ] = 2 ** 63 - 1
16+ from ...services .containers import ContainerIsMissingError
3417
3518_logger = logging .getLogger (__name__ )
3619
@@ -77,8 +60,6 @@ async def store_compose_spec(
7760@cancel_on_disconnect
7861async def containers_docker_inspect (
7962 request : Request ,
80- shared_store : Annotated [SharedStore , Depends (get_shared_store )],
81- container_restart_lock : Annotated [Lock , Depends (get_container_restart_lock )],
8263 only_status : bool = Query ( # noqa: FBT001
8364 default = False , description = "if True only show the status of the container"
8465 ),
@@ -88,92 +69,18 @@ async def containers_docker_inspect(
8869 the status of the containers is returned
8970 """
9071 _ = request
91-
92- def _format_result (container_inspect : dict [str , Any ]) -> dict [str , Any ]:
93- if only_status :
94- container_state = container_inspect .get ("State" , {})
95-
96- # pending is another fake state use to share more information with the frontend
97- return {
98- "Status" : container_state .get ("Status" , "pending" ),
99- "Error" : container_state .get ("Error" , "" ),
100- }
101-
102- return container_inspect
103-
104- async with container_restart_lock , docker_client () as docker :
105- container_names = shared_store .container_names
106-
107- results = {}
108-
109- for container in container_names :
110- container_instance = await docker .containers .get (container )
111- container_inspect = await container_instance .show ()
112- results [container ] = _format_result (container_inspect )
113-
114- return results
72+ return await containers .containers_docker_inspect (
73+ app = request .app , only_status = only_status
74+ )
11575
11676
11777@router .get (
11878 "/containers/activity" ,
11979)
12080@cancel_on_disconnect
121- async def get_containers_activity (
122- request : Request ,
123- settings : Annotated [ApplicationSettings , Depends (get_settings )],
124- shared_store : Annotated [SharedStore , Depends (get_shared_store )],
125- ) -> ActivityInfoOrNone :
81+ async def get_containers_activity (request : Request ) -> ActivityInfoOrNone :
12682 _ = request
127- inactivity_command = settings .DY_SIDECAR_CALLBACKS_MAPPING .inactivity
128- if inactivity_command is None :
129- return None
130-
131- container_name = inactivity_command .service
132-
133- try :
134- inactivity_response = await run_command_in_container (
135- shared_store .original_to_container_names [inactivity_command .service ],
136- command = inactivity_command .command ,
137- timeout = inactivity_command .timeout ,
138- )
139- except (
140- ContainerExecContainerNotFoundError ,
141- ContainerExecCommandFailedError ,
142- ContainerExecTimeoutError ,
143- DockerError ,
144- ):
145- _logger .warning (
146- "Could not run inactivity command '%s' in container '%s'" ,
147- inactivity_command .command ,
148- container_name ,
149- exc_info = True ,
150- )
151- return ActivityInfo (seconds_inactive = _INACTIVE_FOR_LONG_TIME )
152-
153- try :
154- return TypeAdapter (ActivityInfo ).validate_json (inactivity_response )
155- except ValidationError :
156- _logger .warning (
157- "Could not parse command result '%s' as '%s'" ,
158- inactivity_response ,
159- ActivityInfo .__name__ ,
160- exc_info = True ,
161- )
162-
163- return ActivityInfo (seconds_inactive = _INACTIVE_FOR_LONG_TIME )
164-
165-
166- # Some of the operations and sub-resources on containers are implemented as long-running tasks.
167- # Handlers for these operations can be found in:
168- #
169- # POST /containers : SEE containers_long_running_tasks::create_service_containers_task
170- # POST /containers:down : SEE containers_long_running_tasks::runs_docker_compose_down_task
171- # POST /containers/state:restore : SEE containers_long_running_tasks::state_restore_task
172- # POST /containers/state:save : SEE containers_long_running_tasks::state_save_task
173- # POST /containers/ports/inputs:pull : SEE containers_long_running_tasks::ports_inputs_pull_task
174- # POST /containers/ports/outputs:pull : SEE containers_long_running_tasks::ports_outputs_pull_task
175- # POST /containers/ports/outputs:push : SEE containers_long_running_tasks::ports_outputs_push_task
176- #
83+ return await containers .get_containers_activity (app = request .app )
17784
17885
17986@router .get (
@@ -190,7 +97,6 @@ async def get_containers_activity(
19097@cancel_on_disconnect
19198async def get_containers_name (
19299 request : Request ,
193- shared_store : Annotated [SharedStore , Depends (get_shared_store )],
194100 filters : str = Query (
195101 ...,
196102 description = (
@@ -211,43 +117,7 @@ async def get_containers_name(
211117 """
212118 _ = request
213119
214- filters_dict : dict [str , str ] = json_loads (filters )
215- if not isinstance (filters_dict , dict ):
216- raise HTTPException (
217- status .HTTP_422_UNPROCESSABLE_ENTITY ,
218- detail = f"Provided filters, could not parsed { filters_dict } " ,
219- )
220- network_name : str | None = filters_dict .get ("network" , None )
221- exclude : str | None = filters_dict .get ("exclude" , None )
222-
223- stored_compose_content = shared_store .compose_spec
224- if stored_compose_content is None :
225- raise HTTPException (
226- status .HTTP_404_NOT_FOUND ,
227- detail = "No spec for docker compose down was found" ,
228- )
229-
230- compose_spec = parse_compose_spec (stored_compose_content )
231-
232- container_name = None
233-
234- spec_services = compose_spec ["services" ]
235- for service in spec_services :
236- service_content = spec_services [service ]
237- if network_name in service_content .get ("networks" , {}):
238- if exclude is not None and exclude in service_content ["container_name" ]:
239- # removing this container from results
240- continue
241- container_name = service_content ["container_name" ]
242- break
243-
244- if container_name is None :
245- raise HTTPException (
246- status .HTTP_404_NOT_FOUND ,
247- detail = f"No container found for network={ network_name } " ,
248- )
249-
250- return f"{ container_name } "
120+ return await containers .get_containers_name (app = request .app , filters = filters )
251121
252122
253123@router .get (
@@ -259,16 +129,14 @@ async def get_containers_name(
259129)
260130@cancel_on_disconnect
261131async def inspect_container (
262- request : Request ,
263- shared_store : Annotated [SharedStore , Depends (get_shared_store )],
264- container_id : str = PathParam (..., alias = "id" ),
132+ request : Request , container_id : str = PathParam (..., alias = "id" )
265133) -> dict [str , Any ]:
266134 """Returns information about the container, like docker inspect command"""
267135 _ = request
268136
269- _raise_if_container_is_missing ( container_id , shared_store . container_names )
270-
271- async with docker_client () as docker :
272- container_instance = await docker . containers . get ( container_id )
273- inspect_result : dict [ str , Any ] = await container_instance . show ()
274- return inspect_result
137+ try :
138+ return await containers . inspect_container (
139+ app = request . app , container_id = container_id
140+ )
141+ except ContainerIsMissingError as e :
142+ raise HTTPException ( status . HTTP_404_NOT_FOUND , detail = f" { e } " ) from e
0 commit comments