Skip to content

Commit ed6da73

Browse files
authored
♻️ Autoscaling: refactor before 1st draft of computational autoscaling (⚠️ devops) (#4874)
1 parent f2c5bb0 commit ed6da73

32 files changed

+1286
-831
lines changed

.coveragerc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ exclude_lines =
2424
if __name__ == .__main__.:
2525

2626
# Don't complain about abstract methods, they aren't run:
27-
@(abc\.)?abstractmethod
27+
@(abc\.)?abstract(((class|static)?method)|property)
2828

2929
ignore_errors = True
3030
show_missing = True

packages/pytest-simcore/src/pytest_simcore/dask_gateway.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from dask_gateway_server.app import DaskGateway
1111
from dask_gateway_server.backends.local import UnsafeLocalBackend
1212
from distributed import Client
13+
from faker import Faker
1314

1415

1516
@pytest.fixture
@@ -70,17 +71,31 @@ async def local_dask_gateway_server(
7071
print("...done")
7172

7273

74+
@pytest.fixture
75+
def gateway_username(faker: Faker) -> str:
76+
return faker.user_name()
77+
78+
79+
@pytest.fixture
80+
def gateway_auth(
81+
local_dask_gateway_server: DaskGatewayServer, gateway_username: str
82+
) -> auth.BasicAuth:
83+
return auth.BasicAuth(gateway_username, local_dask_gateway_server.password)
84+
85+
7386
@pytest.fixture
7487
async def dask_gateway(
75-
local_dask_gateway_server: DaskGatewayServer,
88+
local_dask_gateway_server: DaskGatewayServer, gateway_auth: auth.BasicAuth
7689
) -> Gateway:
7790
async with Gateway(
7891
local_dask_gateway_server.address,
7992
local_dask_gateway_server.proxy_address,
8093
asynchronous=True,
81-
auth=auth.BasicAuth("pytest_user", local_dask_gateway_server.password),
94+
auth=gateway_auth,
8295
) as gateway:
83-
print(f"--> {gateway=} created")
96+
print(
97+
f"--> {gateway=} created, with {gateway_auth.username=}/{gateway_auth.password=}"
98+
)
8499
cluster_options = await gateway.cluster_options()
85100
gateway_versions = await gateway.get_versions()
86101
clusters_list = await gateway.list_clusters()

packages/pytest-simcore/src/pytest_simcore/dask_scheduler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# pylint: disable=unused-variable
44

55

6-
from collections.abc import AsyncIterable, Callable
7-
from typing import Any, AsyncIterator
6+
from collections.abc import AsyncIterable, AsyncIterator, Callable
7+
from typing import Any
88

99
import distributed
1010
import pytest
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import datetime
2+
3+
_TIME_FORMAT = "{:02d}:{:02d}" # format for minutes:seconds
4+
5+
6+
def timedelta_as_minute_second(delta: datetime.timedelta) -> str:
7+
total_seconds = round(delta.total_seconds())
8+
minutes, seconds = divmod(abs(total_seconds), 60)
9+
sign = "-" if total_seconds < 0 else ""
10+
return f"{sign}{_TIME_FORMAT.format(minutes, seconds)}"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from datetime import timedelta
2+
3+
import pytest
4+
from servicelib.utils_formatting import timedelta_as_minute_second
5+
6+
7+
@pytest.mark.parametrize(
8+
"input_timedelta, expected_formatting",
9+
[
10+
(timedelta(), "00:00"),
11+
(timedelta(seconds=23), "00:23"),
12+
(timedelta(days=2, seconds=23), f"{2*24*60}:23"),
13+
(timedelta(seconds=-23), "-00:23"),
14+
(timedelta(seconds=-83), "-01:23"),
15+
],
16+
)
17+
def test_timedelta_as_minute_second(
18+
input_timedelta: timedelta, expected_formatting: str
19+
):
20+
assert timedelta_as_minute_second(input_timedelta) == expected_formatting

services/autoscaling/requirements/_test.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ pytest-cov
2626
pytest-mock
2727
pytest-runner
2828
python-dotenv
29+
pytest-icdiff
2930
respx

services/autoscaling/requirements/_test.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ httpx==0.24.0
106106
# -c requirements/_base.txt
107107
# -r requirements/_test.in
108108
# respx
109+
icdiff==2.0.7
110+
# via pytest-icdiff
109111
idna==3.4
110112
# via
111113
# -c requirements/_base.txt
@@ -174,6 +176,8 @@ pbr==5.11.1
174176
# sarif-om
175177
pluggy==1.3.0
176178
# via pytest
179+
pprintpp==0.4.0
180+
# via pytest-icdiff
177181
psutil==5.9.5
178182
# via -r requirements/_test.in
179183
py-partiql-parser==0.3.6
@@ -200,11 +204,14 @@ pytest==7.4.2
200204
# -r requirements/_test.in
201205
# pytest-asyncio
202206
# pytest-cov
207+
# pytest-icdiff
203208
# pytest-mock
204209
pytest-asyncio==0.21.1
205210
# via -r requirements/_test.in
206211
pytest-cov==4.1.0
207212
# via -r requirements/_test.in
213+
pytest-icdiff==0.8
214+
# via -r requirements/_test.in
208215
pytest-mock==3.11.1
209216
# via -r requirements/_test.in
210217
pytest-runner==6.0.0
@@ -218,7 +225,9 @@ python-dateutil==2.8.2
218225
python-dotenv==1.0.0
219226
# via -r requirements/_test.in
220227
python-jose==3.3.0
221-
# via moto
228+
# via
229+
# moto
230+
# python-jose
222231
pyyaml==6.0.1
223232
# via
224233
# -c requirements/../../../requirements/constraints.txt
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
from ._meta import __version__
Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,17 @@
1-
""" Application's metadata
2-
3-
"""
4-
from contextlib import suppress
51
from typing import Final
62

7-
import pkg_resources
3+
from models_library.basic_types import VersionTag
84
from packaging.version import Version
5+
from servicelib.utils_meta import PackageInfo
96

10-
_current_distribution = pkg_resources.get_distribution("simcore-service-autoscaling")
11-
12-
__version__: str = _current_distribution.version
13-
14-
15-
APP_NAME: Final[str] = _current_distribution.project_name
16-
API_VERSION: Final[str] = __version__
17-
VERSION: Final[Version] = Version(__version__)
18-
API_VTAG: Final[str] = f"v{VERSION.major}"
19-
20-
21-
def get_summary() -> str:
22-
with suppress(Exception):
23-
try:
24-
metadata = _current_distribution.get_metadata_lines("METADATA")
25-
except FileNotFoundError:
26-
metadata = _current_distribution.get_metadata_lines("PKG-INFO")
7+
info: Final = PackageInfo(package_name="simcore-service-autoscaling")
8+
__version__: Final[str] = info.__version__
279

28-
return next(x.split(":") for x in metadata if x.startswith("Summary:"))[-1]
29-
return "" # pragma: no cover
30-
31-
32-
SUMMARY: Final[str] = get_summary()
10+
APP_NAME: Final[str] = info.project_name
11+
API_VERSION: Final[str] = info.__version__
12+
VERSION: Final[Version] = info.version
13+
API_VTAG: Final[VersionTag] = VersionTag(info.api_prefix_path_tag)
14+
SUMMARY: Final[str] = info.get_summary()
3315

3416

3517
# https://patorjk.com/software/taag/#p=testall&f=Avatar&t=Autoscaling
@@ -47,6 +29,24 @@ def get_summary() -> str:
4729
)
4830

4931

50-
APP_FINISHED_BANNER_MSG = "{:=^100}".format(
51-
f"🎉 App {APP_NAME}=={__version__} shutdown completed 🎉"
52-
)
32+
APP_STARTED_DYNAMIC_BANNER_MSG = r"""
33+
_ _
34+
| | (_)
35+
__| | _ _ _ __ __ _ _ __ ___ _ ___
36+
/ _` || | | || '_ \ / _` || '_ ` _ \ | | / __|
37+
| (_| || |_| || | | || (_| || | | | | || || (__
38+
\__,_| \__, ||_| |_| \__,_||_| |_| |_||_| \___|
39+
__/ |
40+
|___/
41+
"""
42+
43+
APP_STARTED_DISABLED_BANNER_MSG = r"""
44+
_ _ _ _ _
45+
| |(_) | | | | | |
46+
__| | _ ___ __ _ | |__ | | ___ __| |
47+
/ _` || |/ __| / _` || '_ \ | | / _ \ / _` |
48+
| (_| || |\__ \| (_| || |_) || || __/| (_| |
49+
\__,_||_||___/ \__,_||_.__/ |_| \___| \__,_|
50+
"""
51+
52+
APP_FINISHED_BANNER_MSG = info.get_finished_banner()

services/autoscaling/src/simcore_service_autoscaling/core/application.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
APP_FINISHED_BANNER_MSG,
99
APP_NAME,
1010
APP_STARTED_BANNER_MSG,
11+
APP_STARTED_DISABLED_BANNER_MSG,
12+
APP_STARTED_DYNAMIC_BANNER_MSG,
1113
)
1214
from ..api.routes import setup_api_routes
1315
from ..modules.auto_scaling_task import setup as setup_background_task
@@ -49,10 +51,14 @@ def create_app(settings: ApplicationSettings) -> FastAPI:
4951

5052
# EVENTS
5153
async def _on_startup() -> None:
52-
print(APP_STARTED_BANNER_MSG, flush=True)
54+
print(APP_STARTED_BANNER_MSG, flush=True) # noqa: T201
55+
if settings.AUTOSCALING_NODES_MONITORING:
56+
print(APP_STARTED_DYNAMIC_BANNER_MSG, flush=True) # noqa: T201
57+
else:
58+
print(APP_STARTED_DISABLED_BANNER_MSG, flush=True) # noqa: T201
5359

5460
async def _on_shutdown() -> None:
55-
print(APP_FINISHED_BANNER_MSG, flush=True)
61+
print(APP_FINISHED_BANNER_MSG, flush=True) # noqa: T201
5662

5763
app.add_event_handler("startup", _on_startup)
5864
app.add_event_handler("shutdown", _on_shutdown)

services/autoscaling/src/simcore_service_autoscaling/core/settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,17 @@ def check_valid_intance_names(cls, value):
119119

120120
class NodesMonitoringSettings(BaseCustomSettings):
121121
NODES_MONITORING_NODE_LABELS: list[DockerLabelKey] = Field(
122-
default_factory=list,
122+
...,
123123
description="autoscaling will only monitor nodes with the given labels (if empty all nodes will be monitored), these labels will be added to the new created nodes by default",
124124
)
125125

126126
NODES_MONITORING_SERVICE_LABELS: list[DockerLabelKey] = Field(
127-
default_factory=list,
127+
...,
128128
description="autoscaling will only monitor services with the given labels (if empty all services will be monitored)",
129129
)
130130

131131
NODES_MONITORING_NEW_NODES_LABELS: list[DockerLabelKey] = Field(
132-
default=["io.simcore.autoscaled-node"],
132+
...,
133133
description="autoscaling will add these labels to any new node it creates (additional to the ones in NODES_MONITORING_NODE_LABELS",
134134
)
135135

services/autoscaling/src/simcore_service_autoscaling/models.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,19 @@ def __add__(self, other: "Resources") -> "Resources":
2121
return Resources.construct(
2222
**{
2323
key: a + b
24-
for (key, a), b in zip(self.dict().items(), other.dict().values())
24+
for (key, a), b in zip(
25+
self.dict().items(), other.dict().values(), strict=True
26+
)
2527
}
2628
)
2729

2830
def __sub__(self, other: "Resources") -> "Resources":
2931
return Resources.construct(
3032
**{
3133
key: a - b
32-
for (key, a), b in zip(self.dict().items(), other.dict().values())
34+
for (key, a), b in zip(
35+
self.dict().items(), other.dict().values(), strict=True
36+
)
3337
}
3438
)
3539

0 commit comments

Comments
 (0)