Skip to content

Commit a2fd96f

Browse files
author
Andrei Neagu
committed
Merge remote-tracking branch 'upstream/is4481/upgrade-services' into upgrade-dynamic-sceduler
2 parents 1732564 + 3f781e6 commit a2fd96f

File tree

10 files changed

+101
-72
lines changed

10 files changed

+101
-72
lines changed

packages/aws-library/src/aws_library/ec2/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from ._client import SimcoreEC2API
22
from ._errors import EC2AccessError, EC2NotConnectedError, EC2RuntimeError
33
from ._models import (
4+
AWS_TAG_KEY_MAX_LENGTH,
5+
AWS_TAG_KEY_MIN_LENGTH,
6+
AWS_TAG_VALUE_MAX_LENGTH,
7+
AWS_TAG_VALUE_MIN_LENGTH,
48
AWSTagKey,
59
AWSTagValue,
610
EC2InstanceBootSpecific,
@@ -14,6 +18,10 @@
1418
__all__: tuple[str, ...] = (
1519
"AWSTagKey",
1620
"AWSTagValue",
21+
"AWS_TAG_KEY_MIN_LENGTH",
22+
"AWS_TAG_KEY_MAX_LENGTH",
23+
"AWS_TAG_VALUE_MIN_LENGTH",
24+
"AWS_TAG_VALUE_MAX_LENGTH",
1725
"EC2AccessError",
1826
"EC2InstanceBootSpecific",
1927
"EC2InstanceConfig",

packages/aws-library/src/aws_library/ec2/_models.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import re
33
import tempfile
44
from dataclasses import dataclass
5-
from typing import Annotated, TypeAlias
5+
from typing import Annotated, Final, TypeAlias
66

77
import sh # type: ignore[import-untyped]
88
from models_library.docker import DockerGenericTag
@@ -68,17 +68,21 @@ class EC2InstanceType:
6868
InstancePrivateDNSName: TypeAlias = str
6969

7070

71+
AWS_TAG_KEY_MIN_LENGTH: Final[int] = 1
72+
AWS_TAG_KEY_MAX_LENGTH: Final[int] = 128
7173
AWSTagKey: TypeAlias = Annotated[
7274
# see [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#tag-restrictions]
7375
str,
7476
StringConstraints(
75-
min_length=1,
76-
max_length=128,
77+
min_length=AWS_TAG_KEY_MIN_LENGTH,
78+
max_length=AWS_TAG_KEY_MAX_LENGTH,
7779
pattern=re.compile(r"^(?!(_index|\.{1,2})$)[a-zA-Z0-9\+\-=\._:@]+$"),
7880
),
7981
]
8082

8183

84+
AWS_TAG_VALUE_MIN_LENGTH: Final[int] = 0
85+
AWS_TAG_VALUE_MAX_LENGTH: Final[int] = 256
8286
AWSTagValue: TypeAlias = Annotated[
8387
# see [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#tag-restrictions]
8488
# quotes []{} were added as it allows to json encode. it seems to be accepted as a value

packages/models-library/src/models_library/errors_classes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ def __missing__(self, key):
1010

1111
class OsparcErrorMixin(PydanticErrorMixin):
1212
msg_template: str
13+
code: str # type: ignore[assignment]
1314

1415
def __new__(cls, *_args, **_kwargs):
1516
if not hasattr(cls, "code"):
16-
cls.code = cls._get_full_class_name() # type: ignore[assignment]
17+
cls.code = cls._get_full_class_name()
1718
return super().__new__(cls)
1819

1920
def __init__(self, **ctx: Any) -> None:
2021
self.__dict__ = ctx
21-
super().__init__(message=self._build_message(), code=self.code)
22+
super().__init__(message=self._build_message(), code=self.code) # type: ignore[arg-type]
2223

2324
def __str__(self) -> str:
2425
return self._build_message()

services/autoscaling/src/simcore_service_autoscaling/_meta.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import Final
22

3+
from pydantic import TypeAdapter
4+
35
from models_library.basic_types import VersionStr, VersionTag
46
from packaging.version import Version
57
from servicelib.utils_meta import PackageInfo
@@ -10,7 +12,7 @@
1012
APP_NAME: Final[str] = info.project_name
1113
API_VERSION: Final[VersionStr] = info.__version__
1214
VERSION: Final[Version] = info.version
13-
API_VTAG: Final[VersionTag] = VersionTag(info.api_prefix_path_tag)
15+
API_VTAG: Final[VersionTag] = TypeAdapter(VersionTag).validate_python(info.api_prefix_path_tag)
1416
SUMMARY: Final[str] = info.get_summary()
1517

1618

services/autoscaling/src/simcore_service_autoscaling/constants.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,34 @@
22
from typing import Final
33

44
from aws_library.ec2._models import AWSTagKey, AWSTagValue, EC2Tags
5-
from pydantic import parse_obj_as
5+
from pydantic import TypeAdapter
66

7-
BUFFER_MACHINE_PULLING_EC2_TAG_KEY: Final[AWSTagKey] = parse_obj_as(
8-
AWSTagKey, "pulling"
7+
BUFFER_MACHINE_PULLING_EC2_TAG_KEY: Final[AWSTagKey] = TypeAdapter(AWSTagKey).validate_python(
8+
"pulling"
99
)
10-
BUFFER_MACHINE_PULLING_COMMAND_ID_EC2_TAG_KEY: Final[AWSTagKey] = parse_obj_as(
11-
AWSTagKey, "ssm-command-id"
10+
BUFFER_MACHINE_PULLING_COMMAND_ID_EC2_TAG_KEY: Final[AWSTagKey] = TypeAdapter(AWSTagKey).validate_python(
11+
"ssm-command-id"
1212
)
1313
PREPULL_COMMAND_NAME: Final[str] = "docker images pulling"
1414

1515
DOCKER_PULL_COMMAND: Final[
1616
str
1717
] = "docker compose -f /docker-pull.compose.yml -p buffering pull"
1818

19-
PRE_PULLED_IMAGES_EC2_TAG_KEY: Final[AWSTagKey] = parse_obj_as(
20-
AWSTagKey, "io.simcore.autoscaling.pre_pulled_images"
19+
PRE_PULLED_IMAGES_EC2_TAG_KEY: Final[AWSTagKey] = TypeAdapter(AWSTagKey).validate_python(
20+
"io.simcore.autoscaling.pre_pulled_images"
2121
)
2222

23-
BUFFER_MACHINE_TAG_KEY: Final[AWSTagKey] = parse_obj_as(
24-
AWSTagKey, "io.simcore.autoscaling.buffer_machine"
23+
BUFFER_MACHINE_TAG_KEY: Final[AWSTagKey] = TypeAdapter(AWSTagKey).validate_python(
24+
"io.simcore.autoscaling.buffer_machine"
2525
)
2626
DEACTIVATED_BUFFER_MACHINE_EC2_TAGS: Final[EC2Tags] = {
27-
BUFFER_MACHINE_TAG_KEY: parse_obj_as(AWSTagValue, "true")
27+
BUFFER_MACHINE_TAG_KEY: TypeAdapter(AWSTagValue).validate_python(
28+
"true"
29+
)
2830
}
2931
ACTIVATED_BUFFER_MACHINE_EC2_TAGS: Final[EC2Tags] = {
30-
BUFFER_MACHINE_TAG_KEY: parse_obj_as(AWSTagValue, "false")
32+
BUFFER_MACHINE_TAG_KEY: TypeAdapter(AWSTagValue).validate_python("false")
3133
}
3234
PRE_PULLED_IMAGES_RE: Final[re.Pattern] = re.compile(
3335
rf"{PRE_PULLED_IMAGES_EC2_TAG_KEY}_\((\d+)\)"

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
from typing import Any
2-
31
from models_library.errors_classes import OsparcErrorMixin
42

53

64
class AutoscalingRuntimeError(OsparcErrorMixin, RuntimeError):
7-
def __init__(self, **ctx: Any) -> None:
8-
super().__init__(**ctx)
9-
105
msg_template: str = "Autoscaling unexpected error"
116

127

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime
22
from functools import cached_property
3-
from typing import Final, cast
3+
from typing import Annotated, Final, cast
44

55
from aws_library.ec2 import EC2InstanceBootSpecific, EC2Tags
66
from fastapi import FastAPI
@@ -183,7 +183,7 @@ class NodesMonitoringSettings(BaseCustomSettings):
183183

184184

185185
class DaskMonitoringSettings(BaseCustomSettings):
186-
DASK_MONITORING_URL: AnyUrl = Field(
186+
DASK_MONITORING_URL: Annotated[str, AnyUrl] = Field(
187187
..., description="the url to the osparc-dask-scheduler"
188188
)
189189
DASK_SCHEDULER_AUTH: InternalClusterAuthentication = Field(

services/autoscaling/src/simcore_service_autoscaling/utils/buffer_machines_pool_core.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from collections.abc import Iterable
22
from operator import itemgetter
33

4-
from aws_library.ec2 import AWSTagKey, AWSTagValue, EC2Tags
4+
from aws_library.ec2 import AWS_TAG_VALUE_MAX_LENGTH, AWSTagKey, AWSTagValue, EC2Tags
55
from fastapi import FastAPI
66
from models_library.docker import DockerGenericTag
77
from models_library.utils.json_serialization import json_dumps
8-
from pydantic import parse_obj_as, parse_raw_as
8+
from pydantic import TypeAdapter
99

1010
from ..constants import (
1111
ACTIVATED_BUFFER_MACHINE_EC2_TAGS,
@@ -29,8 +29,10 @@ def get_deactivated_buffer_ec2_tags(
2929
base_ec2_tags = (
3030
auto_scaling_mode.get_ec2_tags(app) | DEACTIVATED_BUFFER_MACHINE_EC2_TAGS
3131
)
32-
base_ec2_tags[AWSTagKey("Name")] = AWSTagValue(
33-
f"{base_ec2_tags[AWSTagKey('Name')]}-buffer"
32+
base_ec2_tags[TypeAdapter(AWSTagKey).validate_python("Name")] = TypeAdapter(
33+
AWSTagValue
34+
).validate_python(
35+
f"{base_ec2_tags[TypeAdapter(AWSTagKey).validate_python('Name')]}-buffer"
3436
)
3537
return base_ec2_tags
3638

@@ -43,28 +45,36 @@ def dump_pre_pulled_images_as_tags(images: Iterable[DockerGenericTag]) -> EC2Tag
4345
# AWS Tag Values are limited to 256 characaters so we chunk the images
4446
# into smaller chunks
4547
jsonized_images = json_dumps(images)
46-
assert AWSTagValue.max_length # nosec
47-
if len(jsonized_images) > AWSTagValue.max_length:
48+
assert AWS_TAG_VALUE_MAX_LENGTH # nosec
49+
if len(jsonized_images) > AWS_TAG_VALUE_MAX_LENGTH:
4850
# let's chunk the string
49-
chunk_size = AWSTagValue.max_length
51+
chunk_size = AWS_TAG_VALUE_MAX_LENGTH
5052
chunks = [
5153
jsonized_images[i : i + chunk_size]
5254
for i in range(0, len(jsonized_images), chunk_size)
5355
]
5456
return {
55-
AWSTagKey(f"{PRE_PULLED_IMAGES_EC2_TAG_KEY}_({i})"): AWSTagValue(c)
57+
TypeAdapter(AWSTagKey)
58+
.validate_python(f"{PRE_PULLED_IMAGES_EC2_TAG_KEY}_({i})"): TypeAdapter(
59+
AWSTagValue
60+
)
61+
.validate_python(c)
5662
for i, c in enumerate(chunks)
5763
}
5864
return {
59-
PRE_PULLED_IMAGES_EC2_TAG_KEY: parse_obj_as(AWSTagValue, json_dumps(images))
65+
PRE_PULLED_IMAGES_EC2_TAG_KEY: TypeAdapter(AWSTagValue).validate_python(
66+
json_dumps(images)
67+
)
6068
}
6169

6270

6371
def load_pre_pulled_images_from_tags(tags: EC2Tags) -> list[DockerGenericTag]:
6472
# AWS Tag values are limited to 256 characters so we chunk the images
6573
if PRE_PULLED_IMAGES_EC2_TAG_KEY in tags:
6674
# read directly
67-
return parse_raw_as(list[DockerGenericTag], tags[PRE_PULLED_IMAGES_EC2_TAG_KEY])
75+
return TypeAdapter(list[DockerGenericTag]).validate_json(
76+
tags[PRE_PULLED_IMAGES_EC2_TAG_KEY]
77+
)
6878

6979
assembled_json = "".join(
7080
map(
@@ -80,5 +90,5 @@ def load_pre_pulled_images_from_tags(tags: EC2Tags) -> list[DockerGenericTag]:
8090
)
8191
)
8292
if assembled_json:
83-
return parse_raw_as(list[DockerGenericTag], assembled_json)
93+
return TypeAdapter(list[DockerGenericTag]).validate_json(assembled_json)
8494
return []

services/autoscaling/tests/unit/test_utils_rabbitmq.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
ProgressRabbitMessageNode,
1919
ProgressType,
2020
)
21-
from pydantic import parse_obj_as
21+
from pydantic import TypeAdapter
2222
from pytest_mock.plugin import MockerFixture
2323
from servicelib.rabbitmq import BIND_TO_ALL_TOPICS, RabbitMQClient
2424
from settings_library.rabbit import RabbitSettings
@@ -78,8 +78,7 @@ async def test_post_task_log_message(
7878
"running",
7979
)
8080
assert service_with_labels.Spec
81-
service_tasks = parse_obj_as(
82-
list[Task],
81+
service_tasks = TypeAdapter(list[Task]).validate_python(
8382
await async_docker_client.tasks.list(
8483
filters={"service": service_with_labels.Spec.Name}
8584
),
@@ -103,7 +102,7 @@ async def test_post_task_log_message(
103102
messages=[f"[cluster] {log_message}"],
104103
log_level=0,
105104
)
106-
.json()
105+
.model_dump_json()
107106
.encode()
108107
)
109108
print("... message received")
@@ -125,8 +124,7 @@ async def test_post_task_log_message_does_not_raise_if_service_has_no_labels(
125124
):
126125
service_without_labels = await create_service(task_template, {}, "running")
127126
assert service_without_labels.Spec
128-
service_tasks = parse_obj_as(
129-
list[Task],
127+
service_tasks = TypeAdapter(list[Task]).validate_python(
130128
await async_docker_client.tasks.list(
131129
filters={"service": service_without_labels.Spec.Name}
132130
),
@@ -170,8 +168,7 @@ async def test_post_task_progress_message(
170168
"running",
171169
)
172170
assert service_with_labels.Spec
173-
service_tasks = parse_obj_as(
174-
list[Task],
171+
service_tasks = TypeAdapter(list[Task]).validate_python(
175172
await async_docker_client.tasks.list(
176173
filters={"service": service_with_labels.Spec.Name}
177174
),
@@ -195,7 +192,7 @@ async def test_post_task_progress_message(
195192
progress_type=ProgressType.CLUSTER_UP_SCALING,
196193
report=ProgressReport(actual_value=progress_value, total=1),
197194
)
198-
.json()
195+
.model_dump_json()
199196
.encode()
200197
)
201198
print("... message received")
@@ -217,8 +214,7 @@ async def test_post_task_progress_does_not_raise_if_service_has_no_labels(
217214
):
218215
service_without_labels = await create_service(task_template, {}, "running")
219216
assert service_without_labels.Spec
220-
service_tasks = parse_obj_as(
221-
list[Task],
217+
service_tasks = TypeAdapter(list[Task]).validate_python(
222218
await async_docker_client.tasks.list(
223219
filters={"service": service_without_labels.Spec.Name}
224220
),

0 commit comments

Comments
 (0)