Skip to content

Commit 2081202

Browse files
Merge branch 'master' into fix-invitation-url
2 parents 25b3ef8 + a703f56 commit 2081202

File tree

10 files changed

+146
-70
lines changed

10 files changed

+146
-70
lines changed

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pydantic import ConfigDict, Field, field_validator
1+
from pydantic import Field, field_validator
22

33
from .generated_models.docker_rest_api import (
44
ContainerSpec,
@@ -7,7 +7,6 @@
77
ServiceSpec,
88
TaskSpec,
99
)
10-
from .utils.change_case import camel_to_snake
1110

1211

1312
class AioDockerContainerSpec(ContainerSpec):
@@ -38,8 +37,6 @@ class AioDockerResources1(Resources1):
3837
None, description="Define resources reservation.", alias="Reservations"
3938
)
4039

41-
model_config = ConfigDict(populate_by_name=True)
42-
4340

4441
class AioDockerTaskSpec(TaskSpec):
4542
container_spec: AioDockerContainerSpec | None = Field(
@@ -51,5 +48,3 @@ class AioDockerTaskSpec(TaskSpec):
5148

5249
class AioDockerServiceSpec(ServiceSpec):
5350
task_template: AioDockerTaskSpec | None = Field(default=None, alias="TaskTemplate")
54-
55-
model_config = ConfigDict(populate_by_name=True, alias_generator=camel_to_snake)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def validate_volume_limits(cls, v, info: ValidationInfo) -> str | None:
226226
"outputs_path": "/tmp/outputs", # noqa: S108 nosec
227227
"inputs_path": "/tmp/inputs", # noqa: S108 nosec
228228
"state_paths": ["/tmp/save_1", "/tmp_save_2"], # noqa: S108 nosec
229-
"state_exclude": ["/tmp/strip_me/*", "*.py"], # noqa: S108 nosec
229+
"state_exclude": ["/tmp/strip_me/*"], # noqa: S108 nosec
230230
},
231231
{
232232
"outputs_path": "/t_out",

packages/models-library/tests/test_service_settings_labels.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ def test_container_outgoing_permit_list_and_container_allow_internet_without_com
291291
)
292292
},
293293
):
294-
assert TypeAdapter(DynamicSidecarServiceLabels).validate_json(json.dumps(dict_data))
294+
assert TypeAdapter(DynamicSidecarServiceLabels).validate_json(
295+
json.dumps(dict_data)
296+
)
295297

296298

297299
def test_container_allow_internet_no_compose_spec_not_ok():
@@ -414,7 +416,7 @@ def service_labels() -> dict[str, str]:
414416
"inputs_path": "/tmp/inputs", # noqa: S108
415417
"outputs_path": "/tmp/outputs", # noqa: S108
416418
"state_paths": ["/tmp/save_1", "/tmp_save_2"], # noqa: S108
417-
"state_exclude": ["/tmp/strip_me/*", "*.py"], # noqa: S108
419+
"state_exclude": ["/tmp/strip_me/*"], # noqa: S108
418420
}
419421
),
420422
"simcore.service.compose-spec": json.dumps(

services/director-v2/src/simcore_service_director_v2/modules/dynamic_sidecar/scheduler/_core/_event_create_sidecars.py

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,34 @@
5858

5959
_DYNAMIC_SIDECAR_SERVICE_EXTENDABLE_SPECS: Final[tuple[list[str], ...]] = (
6060
["labels"],
61-
["task_template", "Resources", "Limits"],
62-
["task_template", "Resources", "Reservation", "MemoryBytes"],
63-
["task_template", "Resources", "Reservation", "NanoCPUs"],
64-
["task_template", "Placement", "Constraints"],
65-
["task_template", "ContainerSpec", "Env"],
66-
["task_template", "Resources", "Reservation", "GenericResources"],
61+
["task_template", "container_spec", "env"],
62+
["task_template", "placement", "constraints"],
63+
["task_template", "resources", "reservation", "generic_resources"],
64+
["task_template", "resources", "limits"],
65+
["task_template", "resources", "reservation", "memory_bytes"],
66+
["task_template", "resources", "reservation", "nano_cp_us"],
6767
)
6868

6969

70+
def _merge_service_base_and_user_specs(
71+
dynamic_sidecar_service_spec_base: AioDockerServiceSpec,
72+
user_specific_service_spec: AioDockerServiceSpec,
73+
) -> AioDockerServiceSpec:
74+
# NOTE: since user_specific_service_spec follows Docker Service Spec and not Aio
75+
# we do not use aliases when exporting dynamic_sidecar_service_spec_base
76+
return AioDockerServiceSpec.model_validate(
77+
nested_update(
78+
jsonable_encoder(
79+
dynamic_sidecar_service_spec_base, exclude_unset=True, by_alias=False
80+
),
81+
jsonable_encoder(
82+
user_specific_service_spec, exclude_unset=True, by_alias=False
83+
),
84+
include=_DYNAMIC_SIDECAR_SERVICE_EXTENDABLE_SPECS,
85+
)
86+
)
87+
88+
7089
async def _create_proxy_service(
7190
app,
7291
*,
@@ -245,14 +264,8 @@ async def action(cls, app: FastAPI, scheduler_data: SchedulerData) -> None:
245264
user_specific_service_spec = AioDockerServiceSpec.model_validate(
246265
user_specific_service_spec
247266
)
248-
# NOTE: since user_specific_service_spec follows Docker Service Spec and not Aio
249-
# we do not use aliases when exporting dynamic_sidecar_service_spec_base
250-
dynamic_sidecar_service_final_spec = AioDockerServiceSpec.model_validate(
251-
nested_update(
252-
jsonable_encoder(dynamic_sidecar_service_spec_base, exclude_unset=True),
253-
jsonable_encoder(user_specific_service_spec, exclude_unset=True),
254-
include=_DYNAMIC_SIDECAR_SERVICE_EXTENDABLE_SPECS,
255-
)
267+
dynamic_sidecar_service_final_spec = _merge_service_base_and_user_specs(
268+
dynamic_sidecar_service_spec_base, user_specific_service_spec
256269
)
257270
rabbit_message = ProgressRabbitMessageNode.model_construct(
258271
user_id=scheduler_data.user_id,

services/director-v2/tests/unit/with_dbs/test_modules_dynamic_sidecar_docker_service_specs.py

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
from simcore_service_director_v2.modules.dynamic_sidecar.docker_service_specs import (
4444
get_dynamic_sidecar_spec,
4545
)
46+
from simcore_service_director_v2.modules.dynamic_sidecar.scheduler._core._event_create_sidecars import (
47+
_DYNAMIC_SIDECAR_SERVICE_EXTENDABLE_SPECS,
48+
_merge_service_base_and_user_specs,
49+
)
4650
from simcore_service_director_v2.utils.dict_utils import nested_update
4751

4852

@@ -180,7 +184,7 @@ def expected_dynamic_sidecar_spec(
180184
"paths_mapping": {
181185
"inputs_path": "/tmp/inputs", # noqa: S108
182186
"outputs_path": "/tmp/outputs", # noqa: S108
183-
"state_exclude": ["/tmp/strip_me/*", "*.py"], # noqa: S108
187+
"state_exclude": ["/tmp/strip_me/*"], # noqa: S108
184188
"state_paths": ["/tmp/save_1", "/tmp_save_2"], # noqa: S108
185189
},
186190
"callbacks_mapping": CallbacksMapping.model_config[
@@ -239,7 +243,7 @@ def expected_dynamic_sidecar_spec(
239243
"DY_SIDECAR_PATH_OUTPUTS": "/tmp/outputs", # noqa: S108
240244
"DY_SIDECAR_PROJECT_ID": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
241245
"DY_SIDECAR_STATE_EXCLUDE": json_dumps(
242-
["*.py", "/tmp/strip_me/*"] # noqa: S108
246+
["/tmp/strip_me/*"] # noqa: S108
243247
),
244248
"DY_SIDECAR_STATE_PATHS": json_dumps(
245249
["/tmp/save_1", "/tmp_save_2"] # noqa: S108
@@ -614,14 +618,66 @@ async def test_merge_dynamic_sidecar_specs_with_user_specific_specs(
614618
another_merged_dict = nested_update(
615619
orig_dict,
616620
user_dict,
617-
include=(
618-
["labels"],
619-
["task_template", "Resources", "Limits"],
620-
["task_template", "Resources", "Reservation", "MemoryBytes"],
621-
["task_template", "Resources", "Reservation", "NanoCPUs"],
622-
["task_template", "Placement", "Constraints"],
623-
["task_template", "ContainerSpec", "Env"],
624-
["task_template", "Resources", "Reservation", "GenericResources"],
625-
),
621+
include=_DYNAMIC_SIDECAR_SERVICE_EXTENDABLE_SPECS,
626622
)
627623
assert another_merged_dict
624+
625+
626+
def test_regression__merge_service_base_and_user_specs():
627+
mock_service_spec = AioDockerServiceSpec.model_validate(
628+
{"Labels": {"l1": "false", "l0": "a"}}
629+
)
630+
mock_catalog_constraints = AioDockerServiceSpec.model_validate(
631+
{
632+
"Labels": {"l1": "true", "l2": "a"},
633+
"TaskTemplate": {
634+
"Placement": {
635+
"Constraints": [
636+
"c1==true",
637+
"c2==true",
638+
],
639+
},
640+
"Resources": {
641+
"Limits": {"MemoryBytes": 1, "NanoCPUs": 1},
642+
"Reservations": {
643+
"GenericResources": [
644+
{"DiscreteResourceSpec": {"Kind": "VRAM", "Value": 1}}
645+
],
646+
"MemoryBytes": 2,
647+
"NanoCPUs": 2,
648+
},
649+
},
650+
"ContainerSpec": {
651+
"Env": [
652+
"key-1=value-1",
653+
"key2-value2=a",
654+
]
655+
},
656+
},
657+
}
658+
)
659+
result = _merge_service_base_and_user_specs(
660+
mock_service_spec, mock_catalog_constraints
661+
)
662+
assert result.model_dump(by_alias=True, exclude_unset=True) == {
663+
"Labels": {"l1": "true", "l2": "a", "l0": "a"},
664+
"TaskTemplate": {
665+
"Placement": {
666+
"Constraints": [
667+
"c1==true",
668+
"c2==true",
669+
],
670+
},
671+
"Resources": {
672+
"Limits": {"MemoryBytes": 1, "NanoCPUs": 1},
673+
"Reservations": {
674+
"GenericResources": [
675+
{"DiscreteResourceSpec": {"Kind": "VRAM", "Value": 1}}
676+
],
677+
"MemoryBytes": 2,
678+
"NanoCPUs": 2,
679+
},
680+
},
681+
"ContainerSpec": {"Env": {"key-1": "value-1", "key2-value2": "a"}},
682+
},
683+
}

tests/performance/Makefile

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export LOCUST_VERSION
99
ENV_FILE=$(shell pwd)/.env
1010
export ENV_FILE
1111

12+
KERNEL_NAME=$(shell uname -s)
13+
1214
NETWORK_NAME=dashboards_timenet
1315

1416
# UTILS
@@ -44,22 +46,17 @@ build: ## builds distributed osparc locust docker image
4446
push:
4547
docker push itisfoundation/locust:$(LOCUST_VERSION)
4648

47-
48-
49-
.PHONY: down
50-
down: ## stops and removes osparc locust containers
51-
docker compose --file docker-compose.yml down
52-
53-
.PHONY: test
54-
test: ## runs osparc locust. Locust and test configuration are specified in ENV_FILE
49+
.PHONY: test-up test-down
50+
test-up: ## runs osparc locust. Locust and test configuration are specified in ENV_FILE
5551
@if [ ! -f $${ENV_FILE} ]; then echo "You must generate a .env file before running tests!!! See the README..." && exit 1; fi;
5652
@if ! docker network ls | grep -q $(NETWORK_NAME); then \
5753
docker network create $(NETWORK_NAME); \
5854
echo "Created docker network $(NETWORK_NAME)"; \
5955
fi
6056
docker compose --file docker-compose.yml up --scale worker=4 --exit-code-from=master
6157

62-
58+
test-down: ## stops and removes osparc locust containers
59+
@docker compose --file docker-compose.yml down
6360

6461
.PHONY: dashboards-up dashboards-down
6562

@@ -69,12 +66,14 @@ dashboards-up: ## Create Grafana dashboard for inspecting locust results. See da
6966
docker network rm $(NETWORK_NAME); \
7067
echo "Removed docker network $(NETWORK_NAME)"; \
7168
fi
69+
@if [[ "$(KERNEL_NAME)" == "Linux" ]]; then \
70+
( sleep 3 && xdg-open http://localhost:3000 ) & \
71+
fi
7272
@locust-compose up
7373

74-
dashboards-down:
75-
@locust-compose down
76-
7774

75+
dashboards-down: ## stops and removes Grafana dashboard and Timescale postgress containers
76+
@locust-compose down
7877

7978
.PHONY: install-ci install-dev
8079

@@ -86,6 +85,6 @@ install-ci:
8685

8786

8887
.PHONY: config
89-
config:
88+
config: ## Create config for your locust tests
9089
@$(call check_defined, input, please define inputs when calling $@ - e.g. ```make $@ input="--help"```)
9190
@uv run locust_settings.py $(input) | tee "${ENV_FILE}"

tests/performance/README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,18 @@ make config input="--LOCUST_HOST=https://api.osparc-master.speag.com
1515
```
1616
This will validate your settings and you should be good to go once you see a the settings printed in your terminal.
1717

18-
2. Add settings related to your locust file. E.g. if your file expects to find an environment variable `MYENVVAR` you add it to `.env`:
18+
2. Once you have all settings setup you run your test script using the Make `test` recipe:
1919
```bash
20-
echo "MYENVVAR=thisismyenvvar" >> .env
20+
make test-up
2121
```
2222

23-
3. Once you have all settings setup you uun your test script using the Make `test` recipe:
24-
```bash
25-
make test
26-
```
23+
3. If you want to clean up after your tests (remove docker containers) you run `make test-down`
2724

2825
## Dashboards for visualization
2926
- You can visualize the results of your tests (in real time) in a collection of beautiful [Grafana dashboards](https://github.com/SvenskaSpel/locust-plugins/tree/master/locust_plugins/dashboards).
30-
- To do this, run `make dashboards-up` and go to `localhost:3000` to view the dashboards. The way you tell locust to send test results to the database/grafana is by ensuring `LOCUST_TIMESCALE=1` (see how to generate settings in [usage](#usage))
27+
- To do this, run `make dashboards-up`. If you are on linux you should see your browser opening `localhost:3000`, where you can view the dashboards. If the browser doesn't open automatically, do it manually and navigate to `localhost:3000`.The way you tell locust to send test results to the database/grafana is by ensuring `LOCUST_TIMESCALE=1` (see how to generate settings in [usage](#usage))
3128
- When you are done you run `make dashboards-down` to clean up.
32-
- If you are using VPN you will need to forward port 300 to your local machine to view the dashboard.
29+
- If you are using VPN you will need to forward port 3000 to your local machine to view the dashboard.
3330

3431

3532
## Tricky settings 🚨

tests/performance/locust_files/metamodeling/workflow.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from locust import HttpUser, task
88
from pydantic import Field
9-
from pydantic_settings import BaseSettings
9+
from pydantic_settings import BaseSettings, SettingsConfigDict
1010
from requests.auth import HTTPBasicAuth
1111
from tenacity import (
1212
Retrying,
@@ -27,6 +27,7 @@
2727

2828

2929
class UserSettings(BaseSettings):
30+
model_config = SettingsConfigDict(extra="ignore")
3031
OSPARC_API_KEY: str = Field(default=...)
3132
OSPARC_API_SECRET: str = Field(default=...)
3233

tests/performance/locust_files/platform_ping_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from locust import task
99
from locust.contrib.fasthttp import FastHttpUser
1010
from pydantic import Field
11-
from pydantic_settings import BaseSettings
11+
from pydantic_settings import BaseSettings, SettingsConfigDict
1212

1313
logging.basicConfig(level=logging.INFO)
1414

@@ -20,6 +20,7 @@
2020

2121

2222
class MonitoringBasicAuth(BaseSettings):
23+
model_config = SettingsConfigDict(extra="ignore")
2324
SC_USER_NAME: str = Field(default=..., examples=["<your username>"])
2425
SC_PASSWORD: str = Field(default=..., examples=["<your password>"])
2526

0 commit comments

Comments
 (0)