Skip to content

Commit b61d3c8

Browse files
authored
Merge branch 'master' into functions_draft
2 parents 1942489 + c552e46 commit b61d3c8

File tree

76 files changed

+1589
-325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1589
-325
lines changed

.env-devel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ DIRECTOR_V2_LOGLEVEL=INFO
119119
DIRECTOR_V2_NODE_PORTS_STORAGE_AUTH=null
120120
DIRECTOR_V2_PORT=8000
121121
DIRECTOR_V2_PROFILING=1
122-
DIRECTOR_V2_PUBLIC_API_BASE_URL=http://127.0.0.1:8006
123122
DIRECTOR_V2_SERVICES_CUSTOM_CONSTRAINTS=[]
124123
DIRECTOR_V2_DOCKER_HUB_REGISTRY=null
125124
DYNAMIC_SIDECAR_ENABLE_VOLUME_LIMITS=False

api/specs/web-server/_computations.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
from _common import as_query
44
from fastapi import APIRouter, Depends, status
5+
from fastapi_pagination import Page
56
from models_library.api_schemas_webserver.computations import (
67
ComputationGet,
78
ComputationPathParams,
9+
ComputationRunPathParams,
810
ComputationRunRestGet,
11+
ComputationRunWithFiltersListQueryParams,
912
ComputationStart,
1013
ComputationStarted,
1114
ComputationTaskRestGet,
@@ -65,16 +68,26 @@ async def stop_computation(_path: Annotated[ComputationPathParams, Depends()]):
6568

6669
@router.get(
6770
"/computations/-/iterations/latest",
68-
response_model=Envelope[list[ComputationRunRestGet]],
71+
response_model=Page[ComputationRunRestGet],
6972
)
7073
async def list_computations_latest_iteration(
74+
_query: Annotated[as_query(ComputationRunWithFiltersListQueryParams), Depends()],
75+
): ...
76+
77+
78+
@router.get(
79+
"/computations/{project_id}/iterations",
80+
response_model=Page[ComputationRunRestGet],
81+
)
82+
async def list_computation_iterations(
7183
_query: Annotated[as_query(ComputationRunListQueryParams), Depends()],
84+
_path: Annotated[ComputationRunPathParams, Depends()],
7285
): ...
7386

7487

7588
@router.get(
7689
"/computations/{project_id}/iterations/latest/tasks",
77-
response_model=Envelope[list[ComputationTaskRestGet]],
90+
response_model=Page[ComputationTaskRestGet],
7891
)
7992
async def list_computations_latest_iteration_tasks(
8093
_query: Annotated[as_query(ComputationTaskListQueryParams), Depends()],
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import ipaddress
2+
3+
4+
def is_ip_address(host: str) -> bool:
5+
try:
6+
ipaddress.ip_address(host)
7+
return True
8+
except ValueError:
9+
return False
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
from common_library.network import is_ip_address
3+
4+
5+
@pytest.mark.parametrize(
6+
"host, expected",
7+
[
8+
("127.0.0.1", True),
9+
("::1", True),
10+
("192.168.1.1", True),
11+
("2001:0db8:85a3:0000:0000:8a2e:0370:7334", True),
12+
("256.256.256.256", False),
13+
("invalid_host", False),
14+
("", False),
15+
("1234:5678:9abc:def0:1234:5678:9abc:defg", False),
16+
],
17+
)
18+
def test_is_ip_address(host: str, expected: bool):
19+
assert is_ip_address(host) == expected

packages/models-library/src/models_library/api_schemas_directorv2/computations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ class ComputationCreate(BaseModel):
4444
Field(description="if True the computation pipeline will start right away"),
4545
] = False
4646
product_name: Annotated[str, Field()]
47+
product_api_base_url: Annotated[
48+
AnyHttpUrl,
49+
Field(description="Base url of the product"),
50+
]
4751
subgraph: Annotated[
4852
list[NodeID] | None,
4953
Field(

packages/models-library/src/models_library/api_schemas_directorv2/dynamic_services.py

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from typing import TypeAlias
1+
from typing import Annotated, TypeAlias
22

3-
from pydantic import BaseModel, ByteSize, ConfigDict, Field
3+
from pydantic import AnyHttpUrl, BaseModel, BeforeValidator, ByteSize, ConfigDict, Field
4+
from pydantic.config import JsonDict
45

56
from ..resource_tracker import HardwareInfo, PricingInfo
67
from ..services import ServicePortKey
@@ -38,39 +39,61 @@ def from_transferred_bytes(
3839
class DynamicServiceCreate(ServiceDetails):
3940
service_resources: ServiceResourcesDict
4041

41-
product_name: str = Field(..., description="Current product name")
42-
can_save: bool = Field(
43-
..., description="the service data must be saved when closing"
44-
)
45-
wallet_info: WalletInfo | None = Field(
46-
default=None,
47-
description="contains information about the wallet used to bill the running service",
48-
)
49-
pricing_info: PricingInfo | None = Field(
50-
default=None,
51-
description="contains pricing information (ex. pricing plan and unit ids)",
52-
)
53-
hardware_info: HardwareInfo | None = Field(
54-
default=None,
55-
description="contains harware information (ex. aws_ec2_instances)",
56-
)
57-
model_config = ConfigDict(
58-
json_schema_extra={
59-
"example": {
60-
"key": "simcore/services/dynamic/3dviewer",
61-
"version": "2.4.5",
62-
"user_id": 234,
63-
"project_id": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
64-
"node_uuid": "75c7f3f4-18f9-4678-8610-54a2ade78eaa",
65-
"basepath": "/x/75c7f3f4-18f9-4678-8610-54a2ade78eaa",
66-
"product_name": "osparc",
67-
"can_save": True,
68-
"service_resources": ServiceResourcesDictHelpers.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
69-
"wallet_info": WalletInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
70-
"pricing_info": PricingInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
71-
"hardware_info": HardwareInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
42+
product_name: Annotated[str, Field(..., description="Current product name")]
43+
product_api_base_url: Annotated[
44+
str,
45+
BeforeValidator(lambda v: f"{AnyHttpUrl(v)}"),
46+
Field(..., description="Current product API base URL"),
47+
]
48+
can_save: Annotated[
49+
bool, Field(..., description="the service data must be saved when closing")
50+
]
51+
wallet_info: Annotated[
52+
WalletInfo | None,
53+
Field(
54+
default=None,
55+
description="contains information about the wallet used to bill the running service",
56+
),
57+
]
58+
pricing_info: Annotated[
59+
PricingInfo | None,
60+
Field(
61+
default=None,
62+
description="contains pricing information (ex. pricing plan and unit ids)",
63+
),
64+
]
65+
hardware_info: Annotated[
66+
HardwareInfo | None,
67+
Field(
68+
default=None,
69+
description="contains hardware information (ex. aws_ec2_instances)",
70+
),
71+
]
72+
73+
@staticmethod
74+
def _update_json_schema_extra(schema: JsonDict) -> None:
75+
schema.update(
76+
{
77+
"example": {
78+
"key": "simcore/services/dynamic/3dviewer",
79+
"version": "2.4.5",
80+
"user_id": 234,
81+
"project_id": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
82+
"node_uuid": "75c7f3f4-18f9-4678-8610-54a2ade78eaa",
83+
"basepath": "/x/75c7f3f4-18f9-4678-8610-54a2ade78eaa",
84+
"product_name": "osparc",
85+
"product_api_base_url": "https://api.local/",
86+
"can_save": True,
87+
"service_resources": ServiceResourcesDictHelpers.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
88+
"wallet_info": WalletInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
89+
"pricing_info": PricingInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
90+
"hardware_info": HardwareInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
91+
}
7292
}
73-
}
93+
)
94+
95+
model_config = ConfigDict(
96+
json_schema_extra=_update_json_schema_extra,
7497
)
7598

7699

packages/models-library/src/models_library/api_schemas_dynamic_scheduler/dynamic_services.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,39 @@
66
from models_library.users import UserID
77
from models_library.wallets import WalletInfo
88
from pydantic import BaseModel, ConfigDict
9+
from pydantic.config import JsonDict
910

1011

1112
class DynamicServiceStart(DynamicServiceCreate):
1213
request_dns: str
1314
request_scheme: str
1415
simcore_user_agent: str
1516

16-
model_config = ConfigDict(
17-
json_schema_extra={
18-
"example": {
19-
"product_name": "osparc",
20-
"can_save": True,
21-
"user_id": 234,
22-
"project_id": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
23-
"service_key": "simcore/services/dynamic/3dviewer",
24-
"service_version": "2.4.5",
25-
"service_uuid": "75c7f3f4-18f9-4678-8610-54a2ade78eaa",
26-
"request_dns": "some.local",
27-
"request_scheme": "http",
28-
"simcore_user_agent": "",
29-
"service_resources": ServiceResourcesDictHelpers.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
30-
"wallet_info": WalletInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
31-
"pricing_info": PricingInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
32-
"hardware_info": HardwareInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
17+
@staticmethod
18+
def _update_json_schema_extra(schema: JsonDict) -> None:
19+
schema.update(
20+
{
21+
"example": {
22+
"product_name": "osparc",
23+
"product_api_base_url": "https://api.local",
24+
"can_save": True,
25+
"user_id": 234,
26+
"project_id": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
27+
"service_key": "simcore/services/dynamic/3dviewer",
28+
"service_version": "2.4.5",
29+
"service_uuid": "75c7f3f4-18f9-4678-8610-54a2ade78eaa",
30+
"request_dns": "some.local",
31+
"request_scheme": "http",
32+
"simcore_user_agent": "",
33+
"service_resources": ServiceResourcesDictHelpers.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
34+
"wallet_info": WalletInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
35+
"pricing_info": PricingInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
36+
"hardware_info": HardwareInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
37+
}
3338
}
34-
}
35-
)
39+
)
40+
41+
model_config = ConfigDict(json_schema_extra=_update_json_schema_extra)
3642

3743

3844
class DynamicServiceStop(BaseModel):

packages/models-library/src/models_library/api_schemas_webserver/auth.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ class UnregisterCheck(InputSchema):
5555

5656
class ApiKeyCreateRequest(InputSchema):
5757
display_name: Annotated[str, Field(..., min_length=3)]
58-
expiration: timedelta | None = Field(
59-
None,
60-
description="Time delta from creation time to expiration. If None, then it does not expire.",
61-
)
58+
expiration: Annotated[
59+
timedelta | None,
60+
Field(
61+
None,
62+
description="Time delta from creation time to expiration. If None, then it does not expire.",
63+
),
64+
]
6265

6366
model_config = ConfigDict(
6467
alias_generator=AliasGenerator(
@@ -86,11 +89,14 @@ class ApiKeyCreateRequest(InputSchema):
8689
class ApiKeyCreateResponse(OutputSchema):
8790
id: IDStr
8891
display_name: Annotated[str, Field(..., min_length=3)]
89-
expiration: timedelta | None = Field(
90-
None,
91-
description="Time delta from creation time to expiration. If None, then it does not expire.",
92-
)
93-
api_base_url: HttpUrl
92+
expiration: Annotated[
93+
timedelta | None,
94+
Field(
95+
None,
96+
description="Time delta from creation time to expiration. If None, then it does not expire.",
97+
),
98+
]
99+
api_base_url: HttpUrl | None = None
94100
api_key: str
95101
api_secret: str
96102

packages/models-library/src/models_library/api_schemas_webserver/computations.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ class ComputationStarted(OutputSchemaWithoutCamelCase):
8181
class ComputationRunListQueryParams(
8282
PageQueryParameters,
8383
ComputationRunListOrderParams, # type: ignore[misc, valid-type]
84-
):
84+
): ...
85+
86+
87+
class ComputationRunWithFiltersListQueryParams(ComputationRunListQueryParams):
8588
filter_only_running: bool = Field(
8689
default=False,
8790
description="If true, only running computations are returned",
@@ -100,6 +103,11 @@ class ComputationRunRestGet(OutputSchema):
100103
project_custom_metadata: dict[str, Any]
101104

102105

106+
class ComputationRunPathParams(BaseModel):
107+
project_id: ProjectID
108+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
109+
110+
103111
### Computation Task
104112

105113

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

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

2424

2525
@pytest.fixture()
26-
def registered_user(
26+
def create_registered_user(
2727
postgres_db: sa.engine.Engine, faker: Faker
2828
) -> Iterator[Callable[..., dict]]:
2929
created_user_ids = []

0 commit comments

Comments
 (0)