Skip to content

Commit c552e46

Browse files
🐛 Generate API base URL by active product ⚠️ (#7619)
1 parent 5ff7809 commit c552e46

File tree

54 files changed

+597
-145
lines changed

Some content is hidden

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

54 files changed

+597
-145
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
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

services/director-v2/.env-devel

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ DIRECTOR_V2_SELF_SIGNED_SSL_SECRET_ID=1234
2525
DIRECTOR_V2_SELF_SIGNED_SSL_SECRET_NAME=1234
2626
DIRECTOR_V2_SELF_SIGNED_SSL_FILENAME=filename
2727

28-
DIRECTOR_V2_PUBLIC_API_BASE_URL=http://127.0.0.1:8006
29-
3028
DIRECTOR_V2_GENERIC_RESOURCE_PLACEMENT_CONSTRAINTS_SUBSTITUTIONS='{}'
3129

3230
LOG_LEVEL=DEBUG

services/director-v2/openapi.json

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,13 @@
12911291
"type": "string",
12921292
"title": "Product Name"
12931293
},
1294+
"product_api_base_url": {
1295+
"type": "string",
1296+
"minLength": 1,
1297+
"format": "uri",
1298+
"title": "Product Api Base Url",
1299+
"description": "Base url of the product"
1300+
},
12941301
"subgraph": {
12951302
"anyOf": [
12961303
{
@@ -1347,7 +1354,8 @@
13471354
"required": [
13481355
"user_id",
13491356
"project_id",
1350-
"product_name"
1357+
"product_name",
1358+
"product_api_base_url"
13511359
],
13521360
"title": "ComputationCreate"
13531361
},
@@ -1789,6 +1797,11 @@
17891797
"title": "Product Name",
17901798
"description": "Current product name"
17911799
},
1800+
"product_api_base_url": {
1801+
"type": "string",
1802+
"title": "Product Api Base Url",
1803+
"description": "Current product API base URL"
1804+
},
17921805
"can_save": {
17931806
"type": "boolean",
17941807
"title": "Can Save",
@@ -1825,7 +1838,7 @@
18251838
"type": "null"
18261839
}
18271840
],
1828-
"description": "contains harware information (ex. aws_ec2_instances)"
1841+
"description": "contains hardware information (ex. aws_ec2_instances)"
18291842
}
18301843
},
18311844
"type": "object",
@@ -1837,6 +1850,7 @@
18371850
"service_uuid",
18381851
"service_resources",
18391852
"product_name",
1853+
"product_api_base_url",
18401854
"can_save"
18411855
],
18421856
"title": "DynamicServiceCreate",
@@ -1855,6 +1869,7 @@
18551869
"pricing_unit_cost_id": 1,
18561870
"pricing_unit_id": 1
18571871
},
1872+
"product_api_base_url": "https://api.local/",
18581873
"product_name": "osparc",
18591874
"project_id": "dd1d04d9-d704-4f7e-8f0f-1ca60cc771fe",
18601875
"service_resources": {
@@ -3002,6 +3017,18 @@
30023017
],
30033018
"title": "Product Name",
30043019
"description": "Current product upon which this service is scheduledIf set to None, the current product is undefined. Mostly for backwards compatibility"
3020+
},
3021+
"product_api_base_url": {
3022+
"anyOf": [
3023+
{
3024+
"type": "string"
3025+
},
3026+
{
3027+
"type": "null"
3028+
}
3029+
],
3030+
"title": "Product Api Base Url",
3031+
"description": "Base URL for the current product's API."
30053032
}
30063033
},
30073034
"additionalProperties": true,

services/director-v2/src/simcore_service_director_v2/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@
2424

2525
UNDEFINED_STR_METADATA = "undefined-metadata"
2626
UNDEFINED_DOCKER_LABEL = "undefined-label"
27+
UNDEFINED_API_BASE_URL = "https://api.local"

0 commit comments

Comments
 (0)