Skip to content

Commit 75ddf7e

Browse files
GitHKAndrei Neagu
andauthored
boot options injected to all containers (ITISFoundation#3102)
Co-authored-by: Andrei Neagu <[email protected]>
1 parent 90ec142 commit 75ddf7e

File tree

4 files changed

+62
-60
lines changed

4 files changed

+62
-60
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from enum import Enum
55
from functools import cached_property
66
from pathlib import Path
7-
from typing import Any, Dict, Literal, Optional
7+
from typing import Any, Literal, Optional
88

99
from pydantic import BaseModel, Extra, Field, Json, PrivateAttr, validator
1010

@@ -44,7 +44,7 @@ class SimcoreServiceSettingLabelEntry(BaseModel):
4444
Specifically the section under ``TaskTemplate``
4545
"""
4646

47-
_destination_container: str = PrivateAttr()
47+
_destination_containers: list[str] = PrivateAttr()
4848
name: str = Field(..., description="The name of the service setting")
4949
setting_type: Literal[
5050
"string",
@@ -162,7 +162,7 @@ class Config(_BaseConfig):
162162
}
163163

164164

165-
ComposeSpecLabel = Dict[str, Any]
165+
ComposeSpecLabel = dict[str, Any]
166166

167167

168168
class RestartPolicy(str, Enum):

packages/models-library/tests/test_service_settings_labels.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections import namedtuple
77
from copy import deepcopy
88
from pprint import pformat
9-
from typing import Any, Dict, Type
9+
from typing import Any, Type
1010

1111
import pytest
1212
from models_library.service_settings_labels import (
@@ -50,7 +50,7 @@
5050
ids=[x.id for x in SIMCORE_SERVICE_EXAMPLES],
5151
)
5252
def test_simcore_service_labels(
53-
example: Dict, items: int, uses_dynamic_sidecar: bool
53+
example: dict, items: int, uses_dynamic_sidecar: bool
5454
) -> None:
5555
simcore_service_labels = SimcoreServiceLabels.parse_obj(example)
5656

@@ -72,7 +72,7 @@ def test_service_settings() -> None:
7272
# ensure private attribute assignment
7373
for service_setting in simcore_settings_settings_label:
7474
# pylint: disable=protected-access
75-
service_setting._destination_container = "random_value"
75+
service_setting._destination_containers = ["random_value1", "random_value2"]
7676

7777

7878
@pytest.mark.parametrize(
@@ -84,7 +84,7 @@ def test_service_settings() -> None:
8484
),
8585
)
8686
def test_service_settings_model_examples(
87-
model_cls: Type[BaseModel], model_cls_examples: Dict[str, Dict[str, Any]]
87+
model_cls: Type[BaseModel], model_cls_examples: dict[str, dict[str, Any]]
8888
) -> None:
8989
for name, example in model_cls_examples.items():
9090
print(name, ":", pformat(example))
@@ -97,7 +97,7 @@ def test_service_settings_model_examples(
9797
(SimcoreServiceLabels,),
9898
)
9999
def test_correctly_detect_dynamic_sidecar_boot(
100-
model_cls: Type[BaseModel], model_cls_examples: Dict[str, Dict[str, Any]]
100+
model_cls: Type[BaseModel], model_cls_examples: dict[str, dict[str, Any]]
101101
) -> None:
102102
for name, example in model_cls_examples.items():
103103
print(name, ":", pformat(example))
@@ -108,7 +108,7 @@ def test_correctly_detect_dynamic_sidecar_boot(
108108

109109

110110
def test_raises_error_if_http_entrypoint_is_missing() -> None:
111-
simcore_service_labels: Dict[str, Any] = deepcopy(
111+
simcore_service_labels: dict[str, Any] = deepcopy(
112112
SimcoreServiceLabels.Config.schema_extra["examples"][2]
113113
)
114114
del simcore_service_labels["simcore.service.container-http-entrypoint"]
@@ -141,7 +141,7 @@ def test_simcore_services_labels_compose_spec_null_container_http_entry_provided
141141

142142

143143
def test_raises_error_wrong_restart_policy() -> None:
144-
simcore_service_labels: Dict[str, Any] = deepcopy(
144+
simcore_service_labels: dict[str, Any] = deepcopy(
145145
SimcoreServiceLabels.Config.schema_extra["examples"][2]
146146
)
147147
simcore_service_labels["simcore.service.restart-policy"] = "__not_a_valid_policy__"

services/director-v2/src/simcore_service_director_v2/modules/dynamic_sidecar/docker_service_specs/settings.py

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import logging
33
from collections import deque
4-
from typing import Any, Deque, Dict, List, Optional, cast
4+
from typing import Any, Optional, cast
55

66
from models_library.boot_options import BootOption, EnvVarKey
77
from models_library.service_settings_labels import (
@@ -33,7 +33,7 @@
3333
log = logging.getLogger(__name__)
3434

3535

36-
def _parse_mount_settings(settings: List[Dict]) -> List[Dict]:
36+
def _parse_mount_settings(settings: list[dict]) -> list[dict]:
3737
mounts = []
3838
for s in settings:
3939
log.debug("Retrieved mount settings %s", s)
@@ -57,7 +57,7 @@ def _parse_mount_settings(settings: List[Dict]) -> List[Dict]:
5757
return mounts
5858

5959

60-
def _parse_env_settings(settings: List[str]) -> Dict:
60+
def _parse_env_settings(settings: list[str]) -> dict:
6161
envs = {}
6262
for s in settings:
6363
log.debug("Retrieved env settings %s", s)
@@ -76,7 +76,7 @@ def _parse_env_settings(settings: List[str]) -> Dict:
7676
# TODO: PC->ANE: i tend to agree with pylint, perhaps we can refactor this together
7777
def update_service_params_from_settings(
7878
labels_service_settings: SimcoreServiceSettingsLabel,
79-
create_service_params: Dict[str, Any],
79+
create_service_params: dict[str, Any],
8080
) -> None:
8181
for param in labels_service_settings:
8282
param: SimcoreServiceSettingLabelEntry = param
@@ -143,7 +143,7 @@ def update_service_params_from_settings(
143143
)
144144
elif param.name == "mount":
145145
log.debug("Found mount parameter %s", param.value)
146-
mount_settings: List[Dict] = _parse_mount_settings(param.value)
146+
mount_settings: list[dict] = _parse_mount_settings(param.value)
147147
if mount_settings:
148148
create_service_params["task_template"]["ContainerSpec"][
149149
"Mounts"
@@ -175,7 +175,7 @@ async def _extract_osparc_involved_service_labels(
175175
service_key: str,
176176
service_tag: str,
177177
service_labels: SimcoreServiceLabels,
178-
) -> Dict[str, SimcoreServiceLabels]:
178+
) -> dict[str, SimcoreServiceLabels]:
179179
"""
180180
Returns all the involved oSPARC services from the provided service labels.
181181
@@ -188,13 +188,13 @@ async def _extract_osparc_involved_service_labels(
188188
# initialize with existing labels
189189
# stores labels mapped by image_name service:tag
190190
_default_key = _assemble_key(service_key=service_key, service_tag=service_tag)
191-
docker_image_name_by_services: Dict[str, SimcoreServiceLabels] = {
191+
docker_image_name_by_services: dict[str, SimcoreServiceLabels] = {
192192
_default_key: service_labels
193193
}
194194
# maps form image_name to compose_spec key
195-
reverse_mapping: Dict[str, str] = {_default_key: DEFAULT_SINGLE_SERVICE_NAME}
195+
reverse_mapping: dict[str, str] = {_default_key: DEFAULT_SINGLE_SERVICE_NAME}
196196

197-
def remap_to_compose_spec_key() -> Dict[str, str]:
197+
def remap_to_compose_spec_key() -> dict[str, str]:
198198
# remaps from image_name as key to compose_spec key
199199
return {reverse_mapping[k]: v for k, v in docker_image_name_by_services.items()}
200200

@@ -252,27 +252,27 @@ def remap_to_compose_spec_key() -> Dict[str, str]:
252252
return remap_to_compose_spec_key()
253253

254254

255-
def _add_compose_destination_container_to_settings_entries(
256-
settings: SimcoreServiceSettingsLabel, destination_container: str
257-
) -> List[SimcoreServiceSettingLabelEntry]:
255+
def _add_compose_destination_containers_to_settings_entries(
256+
settings: SimcoreServiceSettingsLabel, destination_containers: list[str]
257+
) -> list[SimcoreServiceSettingLabelEntry]:
258258
def _inject_destination_container(
259259
item: SimcoreServiceSettingLabelEntry,
260260
) -> SimcoreServiceSettingLabelEntry:
261261
# pylint: disable=protected-access
262-
item._destination_container = destination_container
262+
item._destination_containers = destination_containers
263263
return item
264264

265265
return [_inject_destination_container(x) for x in settings]
266266

267267

268268
def _merge_resources_in_settings(
269-
settings: Deque[SimcoreServiceSettingLabelEntry],
269+
settings: deque[SimcoreServiceSettingLabelEntry],
270270
service_resources: ServiceResourcesDict,
271-
) -> Deque[SimcoreServiceSettingLabelEntry]:
271+
) -> deque[SimcoreServiceSettingLabelEntry]:
272272
"""All oSPARC services which have defined resource requirements will be added"""
273273
log.debug("MERGING\n%s\nAND\n%s", f"{settings=}", f"{service_resources}")
274274

275-
result: Deque[SimcoreServiceSettingLabelEntry] = deque()
275+
result: deque[SimcoreServiceSettingLabelEntry] = deque()
276276

277277
for entry in settings:
278278
entry: SimcoreServiceSettingLabelEntry = entry
@@ -343,14 +343,14 @@ def _merge_resources_in_settings(
343343

344344

345345
def _patch_target_service_into_env_vars(
346-
settings: Deque[SimcoreServiceSettingLabelEntry],
347-
) -> Deque[SimcoreServiceSettingLabelEntry]:
346+
settings: deque[SimcoreServiceSettingLabelEntry],
347+
) -> deque[SimcoreServiceSettingLabelEntry]:
348348
"""NOTE: this method will modify settings in place"""
349349

350-
def _format_env_var(env_var: str, destination_container: str) -> str:
350+
def _format_env_var(env_var: str, destination_container: list[str]) -> str:
351351
var_name, var_payload = env_var.split("=")
352352
json_encoded = json.dumps(
353-
dict(destination_container=destination_container, env_var=var_payload)
353+
dict(destination_containers=destination_container, env_var=var_payload)
354354
)
355355
return f"{var_name}={json_encoded}"
356356

@@ -361,21 +361,21 @@ def _format_env_var(env_var: str, destination_container: str) -> str:
361361
list_of_env_vars = entry.value if entry.value else []
362362

363363
# pylint: disable=protected-access
364-
destination_container = entry._destination_container
364+
destination_containers: list[str] = entry._destination_containers
365365

366366
# transforms settings defined environment variables
367367
# from `ENV_VAR=PAYLOAD`
368-
# to `ENV_VAR={"destination_container": "destination_container", "env_var": "PAYLOAD"}`
368+
# to `ENV_VAR={"destination_container": ["destination_container"], "env_var": "PAYLOAD"}`
369369
entry.value = [
370-
_format_env_var(x, destination_container) for x in list_of_env_vars
370+
_format_env_var(x, destination_containers) for x in list_of_env_vars
371371
]
372372

373373
return settings
374374

375375

376376
def _get_boot_options(
377377
service_labels: SimcoreServiceLabels,
378-
) -> Optional[Dict[EnvVarKey, BootOption]]:
378+
) -> Optional[dict[EnvVarKey, BootOption]]:
379379
as_dict = service_labels.dict()
380380
boot_options_encoded = as_dict.get("io.simcore.boot-options", None)
381381
if boot_options_encoded is None:
@@ -387,11 +387,11 @@ def _get_boot_options(
387387

388388

389389
def _assemble_env_vars_for_boot_options(
390-
boot_options: Dict[EnvVarKey, BootOption],
391-
service_user_selection_boot_options: Dict[EnvVarKey, str],
390+
boot_options: dict[EnvVarKey, BootOption],
391+
service_user_selection_boot_options: dict[EnvVarKey, str],
392392
) -> SimcoreServiceSettingsLabel:
393393

394-
env_vars: Deque[str] = deque()
394+
env_vars: deque[str] = deque()
395395
for env_var_key, boot_option in boot_options.items():
396396
# fetch value selected by the user or use default if not present
397397
value = service_user_selection_boot_options.get(
@@ -411,7 +411,7 @@ def _assemble_env_vars_for_boot_options(
411411

412412
async def get_labels_for_involved_services(
413413
director_v0_client: DirectorV0Client, service_key: str, service_tag: str
414-
) -> Dict[str, SimcoreServiceLabels]:
414+
) -> dict[str, SimcoreServiceLabels]:
415415
simcore_service_labels: SimcoreServiceLabels = (
416416
await director_v0_client.get_service_labels(
417417
service=ServiceKeyVersion(key=service_key, version=service_tag)
@@ -424,7 +424,7 @@ async def get_labels_for_involved_services(
424424
# paths_mapping express how to map dynamic-sidecar paths to the compose-spec volumes
425425
# where the service expects to find its certain folders
426426

427-
labels_for_involved_services: Dict[
427+
labels_for_involved_services: dict[
428428
str, SimcoreServiceLabels
429429
] = await _extract_osparc_involved_service_labels(
430430
director_v0_client=director_v0_client,
@@ -440,7 +440,7 @@ async def merge_settings_before_use(
440440
director_v0_client: DirectorV0Client,
441441
service_key: str,
442442
service_tag: str,
443-
service_user_selection_boot_options: Dict[EnvVarKey, str],
443+
service_user_selection_boot_options: dict[EnvVarKey, str],
444444
service_resources: ServiceResourcesDict,
445445
) -> SimcoreServiceSettingsLabel:
446446
labels_for_involved_services = await get_labels_for_involved_services(
@@ -449,34 +449,36 @@ async def merge_settings_before_use(
449449
service_tag=service_tag,
450450
)
451451

452-
# merge the settings from the all the involved services
453-
settings: Deque[SimcoreServiceSettingLabelEntry] = deque() # TODO: fix typing here
454-
for compose_spec_key, service_labels in labels_for_involved_services.items():
455-
service_settings: SimcoreServiceSettingsLabel = cast(
456-
SimcoreServiceSettingsLabel, service_labels.settings
457-
)
452+
settings: deque[SimcoreServiceSettingLabelEntry] = deque() # TODO: fix typing here
458453

459-
settings.extend(
460-
# inject compose spec key, used to target container specific services
461-
_add_compose_destination_container_to_settings_entries(
462-
settings=service_settings, destination_container=compose_spec_key
463-
)
464-
)
465-
466-
# inject boot options as env vars
454+
boot_options_settings_env_vars: Optional[SimcoreServiceSettingsLabel] = None
455+
# search for boot options first and inject to all containers
456+
for compose_spec_key, service_labels in labels_for_involved_services.items():
467457
labels_boot_options = _get_boot_options(service_labels)
468458
if labels_boot_options:
469-
# create a new setting from SimcoreServiceSettingsLabel as env var to pass to target container
459+
# create a new setting from SimcoreServiceSettingsLabel as env var
470460
boot_options_settings_env_vars = _assemble_env_vars_for_boot_options(
471461
labels_boot_options, service_user_selection_boot_options
472462
)
473463
settings.extend(
474-
# inject compose spec key, used to target container specific services
475-
_add_compose_destination_container_to_settings_entries(
464+
_add_compose_destination_containers_to_settings_entries(
476465
settings=boot_options_settings_env_vars,
477-
destination_container=compose_spec_key,
466+
destination_containers=list(labels_for_involved_services.keys()),
478467
)
479468
)
469+
break
470+
471+
# merge the settings from the all the involved services
472+
for compose_spec_key, service_labels in labels_for_involved_services.items():
473+
service_settings: SimcoreServiceSettingsLabel = cast(
474+
SimcoreServiceSettingsLabel, service_labels.settings
475+
)
476+
settings.extend(
477+
# inject compose spec key, used to target container specific services
478+
_add_compose_destination_containers_to_settings_entries(
479+
settings=service_settings, destination_containers=[compose_spec_key]
480+
)
481+
)
480482

481483
settings = _merge_resources_in_settings(settings, service_resources)
482484
settings = _patch_target_service_into_env_vars(settings)

services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/validation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ def _get_forwarded_env_vars(container_key: str) -> List[str]:
4949
if key.startswith("FORWARD_ENV_"):
5050
new_entry_key = key.replace("FORWARD_ENV_", "")
5151

52-
# parsing `VAR={"destination_container": "destination_container", "env_var": "PAYLOAD"}`
52+
# parsing `VAR={"destination_containers": ["destination_container"], "env_var": "PAYLOAD"}`
5353
new_entry_payload = json.loads(os.environ[key])
54-
if new_entry_payload["destination_container"] != container_key:
54+
if container_key not in new_entry_payload["destination_containers"]:
5555
continue
5656

5757
new_entry_value = new_entry_payload["env_var"]

0 commit comments

Comments
 (0)