Skip to content

Commit cce8765

Browse files
author
Andrei Neagu
committed
refactor position
1 parent 911bcdf commit cce8765

File tree

6 files changed

+101
-99
lines changed

6 files changed

+101
-99
lines changed

packages/service-library/src/servicelib/docker_utils.py

Lines changed: 2 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,17 @@
1-
import asyncio
21
import logging
3-
from collections.abc import AsyncIterator, Awaitable, Callable
2+
from collections.abc import Awaitable, Callable
43
from contextlib import AsyncExitStack
54
from dataclasses import dataclass
65
from datetime import datetime
76
from functools import cached_property
87
from typing import Any, Final, Literal
98

109
import aiodocker
11-
import aiohttp
1210
import arrow
13-
import tenacity
14-
from aiohttp import ClientSession
15-
from fastapi import FastAPI
16-
from fastapi_lifespan_manager import State
1711
from models_library.docker import DockerGenericTag
1812
from models_library.generated_models.docker_rest_api import ProgressDetail
1913
from models_library.utils.change_case import snake_to_camel
20-
from pydantic import (
21-
BaseModel,
22-
ByteSize,
23-
ConfigDict,
24-
NonNegativeInt,
25-
TypeAdapter,
26-
ValidationError,
27-
)
28-
from servicelib.fastapi.lifespan_utils import LifespanGenerator
29-
from settings_library.docker_api_proxy import DockerApiProxysettings
14+
from pydantic import BaseModel, ByteSize, ConfigDict, TypeAdapter, ValidationError
3015
from settings_library.docker_registry import RegistrySettings
3116
from yarl import URL
3217

@@ -35,8 +20,6 @@
3520

3621
_logger = logging.getLogger(__name__)
3722

38-
_DEFAULT_DOCKER_API_PROXY_HEALTH_TIMEOUT: Final[NonNegativeInt] = 5
39-
4023

4124
def to_datetime(docker_timestamp: str) -> datetime:
4225
# docker follows RFC3339Nano timestamp which is based on ISO 8601
@@ -298,79 +281,3 @@ async def pull_image(
298281
f"pulling {image_short_name}: {pull_progress}...",
299282
logging.DEBUG,
300283
)
301-
302-
303-
def get_lifespan_remote_docker_client(
304-
docker_api_proxy_settings_property_name: str,
305-
) -> LifespanGenerator:
306-
"""Ensures `setup` and `teardown` for the remote docker client.
307-
308-
Arguments:
309-
docker_api_proxy_settings_property_name -- if the name is `PROP_NAME`
310-
then it should be accessible as `app.state.settings.PROP_NAME`
311-
312-
Returns:
313-
docker client lifespan manager
314-
"""
315-
316-
async def _(app: FastAPI) -> AsyncIterator[State]:
317-
settings: DockerApiProxysettings = getattr(
318-
app.state.settings, docker_api_proxy_settings_property_name
319-
)
320-
321-
session: ClientSession | None = None
322-
if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD:
323-
session = ClientSession(
324-
auth=aiohttp.BasicAuth(
325-
login=settings.DOCKER_API_PROXY_USER,
326-
password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(),
327-
)
328-
)
329-
330-
async with AsyncExitStack() as exit_stack:
331-
if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD:
332-
await exit_stack.enter_async_context(
333-
ClientSession(
334-
auth=aiohttp.BasicAuth(
335-
login=settings.DOCKER_API_PROXY_USER,
336-
password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(),
337-
)
338-
)
339-
)
340-
341-
client = await exit_stack.enter_async_context(
342-
aiodocker.Docker(url=settings.base_url, session=session)
343-
)
344-
345-
app.state.remote_docker_client = client
346-
347-
await wait_till_docker_api_proxy_is_responsive(app)
348-
349-
yield {}
350-
351-
return _
352-
353-
354-
@tenacity.retry(
355-
wait=tenacity.wait_fixed(5),
356-
stop=tenacity.stop_after_delay(60),
357-
before_sleep=tenacity.before_sleep_log(_logger, logging.INFO),
358-
reraise=True,
359-
)
360-
async def wait_till_docker_api_proxy_is_responsive(app: FastAPI) -> None:
361-
await is_docker_api_proxy_ready(app)
362-
363-
364-
async def is_docker_api_proxy_ready(
365-
app: FastAPI, *, timeout=_DEFAULT_DOCKER_API_PROXY_HEALTH_TIMEOUT # noqa: ASYNC109
366-
) -> bool:
367-
try:
368-
await asyncio.wait_for(get_remote_docker_client(app).version(), timeout=timeout)
369-
except (aiodocker.DockerError, TimeoutError):
370-
return False
371-
return True
372-
373-
374-
def get_remote_docker_client(app: FastAPI) -> aiodocker.Docker:
375-
assert isinstance(app.state.remote_docker_client, aiodocker.Docker) # nosec
376-
return app.state.remote_docker_client
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import asyncio
2+
import logging
3+
from collections.abc import AsyncIterator
4+
from contextlib import AsyncExitStack
5+
from typing import Final
6+
7+
import aiodocker
8+
import aiohttp
9+
import tenacity
10+
from aiohttp import ClientSession
11+
from fastapi import FastAPI
12+
from fastapi_lifespan_manager import State
13+
from pydantic import NonNegativeInt
14+
from servicelib.fastapi.lifespan_utils import LifespanGenerator
15+
from settings_library.docker_api_proxy import DockerApiProxysettings
16+
17+
_logger = logging.getLogger(__name__)
18+
19+
_DEFAULT_DOCKER_API_PROXY_HEALTH_TIMEOUT: Final[NonNegativeInt] = 5
20+
21+
22+
def get_lifespan_remote_docker_client(
23+
docker_api_proxy_settings_property_name: str,
24+
) -> LifespanGenerator:
25+
"""Ensures `setup` and `teardown` for the remote docker client.
26+
27+
Arguments:
28+
docker_api_proxy_settings_property_name -- if the name is `PROP_NAME`
29+
then it should be accessible as `app.state.settings.PROP_NAME`
30+
31+
Returns:
32+
docker client lifespan manager
33+
"""
34+
35+
async def _(app: FastAPI) -> AsyncIterator[State]:
36+
settings: DockerApiProxysettings = getattr(
37+
app.state.settings, docker_api_proxy_settings_property_name
38+
)
39+
40+
session: ClientSession | None = None
41+
if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD:
42+
session = ClientSession(
43+
auth=aiohttp.BasicAuth(
44+
login=settings.DOCKER_API_PROXY_USER,
45+
password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(),
46+
)
47+
)
48+
49+
async with AsyncExitStack() as exit_stack:
50+
if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD:
51+
await exit_stack.enter_async_context(
52+
ClientSession(
53+
auth=aiohttp.BasicAuth(
54+
login=settings.DOCKER_API_PROXY_USER,
55+
password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(),
56+
)
57+
)
58+
)
59+
60+
client = await exit_stack.enter_async_context(
61+
aiodocker.Docker(url=settings.base_url, session=session)
62+
)
63+
64+
app.state.remote_docker_client = client
65+
66+
await wait_till_docker_api_proxy_is_responsive(app)
67+
68+
yield {}
69+
70+
return _
71+
72+
73+
@tenacity.retry(
74+
wait=tenacity.wait_fixed(5),
75+
stop=tenacity.stop_after_delay(60),
76+
before_sleep=tenacity.before_sleep_log(_logger, logging.INFO),
77+
reraise=True,
78+
)
79+
async def wait_till_docker_api_proxy_is_responsive(app: FastAPI) -> None:
80+
await is_docker_api_proxy_ready(app)
81+
82+
83+
async def is_docker_api_proxy_ready(
84+
app: FastAPI, *, timeout=_DEFAULT_DOCKER_API_PROXY_HEALTH_TIMEOUT # noqa: ASYNC109
85+
) -> bool:
86+
try:
87+
await asyncio.wait_for(get_remote_docker_client(app).version(), timeout=timeout)
88+
except (aiodocker.DockerError, TimeoutError):
89+
return False
90+
return True
91+
92+
93+
def get_remote_docker_client(app: FastAPI) -> aiodocker.Docker:
94+
assert isinstance(app.state.remote_docker_client, aiodocker.Docker) # nosec
95+
return app.state.remote_docker_client

services/docker-api-proxy/tests/integration/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from fastapi import FastAPI
1111
from pydantic import Field
1212
from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict
13-
from servicelib.docker_utils import (
13+
from servicelib.fastapi.docker import (
1414
get_lifespan_remote_docker_client,
1515
get_remote_docker_client,
1616
)

services/docker-api-proxy/tests/integration/test_docker_api_proxy_autenticated.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def caddy_file() -> str:
4848

4949
@pytest.fixture
5050
def mock_wait_till_docker_api_proxy_is_responsive(mocker: MockerFixture) -> None:
51-
mocker.patch("servicelib.docker_utils.wait_till_docker_api_proxy_is_responsive")
51+
mocker.patch("servicelib.fastapi.docker.wait_till_docker_api_proxy_is_responsive")
5252

5353

5454
@pytest.fixture

services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/api/rest/_health.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
RABBITMQ_CLIENT_UNHEALTHY_MSG,
99
REDIS_CLIENT_UNHEALTHY_MSG,
1010
)
11-
from servicelib.docker_utils import is_docker_api_proxy_ready
11+
from servicelib.fastapi.docker import is_docker_api_proxy_ready
1212
from servicelib.rabbitmq import RabbitMQClient, RabbitMQRPCClient
1313
from servicelib.redis import RedisClientSDK
1414
from settings_library.redis import RedisDatabase

services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from fastapi import FastAPI
44
from fastapi_lifespan_manager import State
5-
from servicelib.docker_utils import get_lifespan_remote_docker_client
5+
from servicelib.fastapi.docker import get_lifespan_remote_docker_client
66
from servicelib.fastapi.lifespan_utils import LifespanGenerator, combine_lifespans
77
from servicelib.fastapi.openapi import override_fastapi_openapi_method
88
from servicelib.fastapi.profiler import initialize_profiler

0 commit comments

Comments
 (0)