dstack 0.19.27__py3-none-any.whl → 0.19.28__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dstack might be problematic. Click here for more details.
- dstack/_internal/cli/commands/__init__.py +11 -8
- dstack/_internal/cli/commands/apply.py +6 -3
- dstack/_internal/cli/commands/completion.py +3 -1
- dstack/_internal/cli/commands/config.py +1 -0
- dstack/_internal/cli/commands/init.py +2 -2
- dstack/_internal/cli/commands/offer.py +1 -1
- dstack/_internal/cli/commands/project.py +1 -0
- dstack/_internal/cli/commands/server.py +2 -2
- dstack/_internal/cli/main.py +1 -1
- dstack/_internal/cli/services/configurators/base.py +2 -4
- dstack/_internal/cli/services/configurators/fleet.py +4 -5
- dstack/_internal/cli/services/configurators/gateway.py +3 -5
- dstack/_internal/cli/services/configurators/run.py +51 -27
- dstack/_internal/cli/services/configurators/volume.py +3 -5
- dstack/_internal/core/compatibility/runs.py +2 -0
- dstack/_internal/core/models/common.py +67 -43
- dstack/_internal/core/models/configurations.py +88 -62
- dstack/_internal/core/models/fleets.py +41 -24
- dstack/_internal/core/models/instances.py +5 -5
- dstack/_internal/core/models/profiles.py +66 -47
- dstack/_internal/core/models/repos/remote.py +21 -16
- dstack/_internal/core/models/resources.py +69 -65
- dstack/_internal/core/models/runs.py +17 -9
- dstack/_internal/server/app.py +5 -0
- dstack/_internal/server/background/tasks/process_fleets.py +8 -0
- dstack/_internal/server/background/tasks/process_submitted_jobs.py +32 -12
- dstack/_internal/server/models.py +6 -5
- dstack/_internal/server/schemas/gateways.py +10 -9
- dstack/_internal/server/services/backends/handlers.py +2 -0
- dstack/_internal/server/services/docker.py +8 -7
- dstack/_internal/server/services/projects.py +52 -1
- dstack/_internal/server/settings.py +46 -0
- dstack/_internal/server/statics/index.html +1 -1
- dstack/_internal/server/statics/{main-56191c63d516fd0041c4.css → main-5e0d56245c4bd241ec27.css} +1 -1
- dstack/_internal/server/statics/{main-4eecc75fbe64067eb1bc.js → main-a2a16772fbf11a14d191.js} +70 -100
- dstack/_internal/server/statics/{main-4eecc75fbe64067eb1bc.js.map → main-a2a16772fbf11a14d191.js.map} +1 -1
- dstack/_internal/utils/env.py +85 -11
- dstack/version.py +1 -1
- {dstack-0.19.27.dist-info → dstack-0.19.28.dist-info}/METADATA +1 -1
- {dstack-0.19.27.dist-info → dstack-0.19.28.dist-info}/RECORD +43 -44
- dstack/_internal/server/statics/static/media/github.1f7102513534c83a9d8d735d2b8c12a2.svg +0 -3
- {dstack-0.19.27.dist-info → dstack-0.19.28.dist-info}/WHEEL +0 -0
- {dstack-0.19.27.dist-info → dstack-0.19.28.dist-info}/entry_points.txt +0 -0
- {dstack-0.19.27.dist-info → dstack-0.19.28.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -10,12 +10,23 @@ from pydantic import Field, ValidationError, conint, constr, root_validator, val
|
|
|
10
10
|
from typing_extensions import Self
|
|
11
11
|
|
|
12
12
|
from dstack._internal.core.errors import ConfigurationError
|
|
13
|
-
from dstack._internal.core.models.common import
|
|
13
|
+
from dstack._internal.core.models.common import (
|
|
14
|
+
CoreConfig,
|
|
15
|
+
CoreModel,
|
|
16
|
+
Duration,
|
|
17
|
+
RegistryAuth,
|
|
18
|
+
generate_dual_core_model,
|
|
19
|
+
)
|
|
14
20
|
from dstack._internal.core.models.envs import Env
|
|
15
21
|
from dstack._internal.core.models.files import FilePathMapping
|
|
16
22
|
from dstack._internal.core.models.fleets import FleetConfiguration
|
|
17
23
|
from dstack._internal.core.models.gateways import GatewayConfiguration
|
|
18
|
-
from dstack._internal.core.models.profiles import
|
|
24
|
+
from dstack._internal.core.models.profiles import (
|
|
25
|
+
ProfileParams,
|
|
26
|
+
ProfileParamsConfig,
|
|
27
|
+
parse_duration,
|
|
28
|
+
parse_off_duration,
|
|
29
|
+
)
|
|
19
30
|
from dstack._internal.core.models.resources import Range, ResourcesSpec
|
|
20
31
|
from dstack._internal.core.models.services import AnyModel, OpenAIChatModel
|
|
21
32
|
from dstack._internal.core.models.unix import UnixUser
|
|
@@ -276,7 +287,20 @@ class HTTPHeaderSpec(CoreModel):
|
|
|
276
287
|
]
|
|
277
288
|
|
|
278
289
|
|
|
279
|
-
class
|
|
290
|
+
class ProbeConfigConfig(CoreConfig):
|
|
291
|
+
@staticmethod
|
|
292
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
293
|
+
add_extra_schema_types(
|
|
294
|
+
schema["properties"]["timeout"],
|
|
295
|
+
extra_types=[{"type": "string"}],
|
|
296
|
+
)
|
|
297
|
+
add_extra_schema_types(
|
|
298
|
+
schema["properties"]["interval"],
|
|
299
|
+
extra_types=[{"type": "string"}],
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class ProbeConfig(generate_dual_core_model(ProbeConfigConfig)):
|
|
280
304
|
type: Literal["http"] # expect other probe types in the future, namely `exec`
|
|
281
305
|
url: Annotated[
|
|
282
306
|
Optional[str], Field(description=f"The URL to request. Defaults to `{DEFAULT_PROBE_URL}`")
|
|
@@ -331,18 +355,6 @@ class ProbeConfig(CoreModel):
|
|
|
331
355
|
),
|
|
332
356
|
] = None
|
|
333
357
|
|
|
334
|
-
class Config(CoreModel.Config):
|
|
335
|
-
@staticmethod
|
|
336
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
337
|
-
add_extra_schema_types(
|
|
338
|
-
schema["properties"]["timeout"],
|
|
339
|
-
extra_types=[{"type": "string"}],
|
|
340
|
-
)
|
|
341
|
-
add_extra_schema_types(
|
|
342
|
-
schema["properties"]["interval"],
|
|
343
|
-
extra_types=[{"type": "string"}],
|
|
344
|
-
)
|
|
345
|
-
|
|
346
358
|
@validator("timeout", pre=True)
|
|
347
359
|
def parse_timeout(cls, v: Optional[Union[int, str]]) -> Optional[int]:
|
|
348
360
|
if v is None:
|
|
@@ -381,6 +393,19 @@ class ProbeConfig(CoreModel):
|
|
|
381
393
|
return values
|
|
382
394
|
|
|
383
395
|
|
|
396
|
+
class BaseRunConfigurationConfig(CoreConfig):
|
|
397
|
+
@staticmethod
|
|
398
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
399
|
+
add_extra_schema_types(
|
|
400
|
+
schema["properties"]["volumes"]["items"],
|
|
401
|
+
extra_types=[{"type": "string"}],
|
|
402
|
+
)
|
|
403
|
+
add_extra_schema_types(
|
|
404
|
+
schema["properties"]["files"]["items"],
|
|
405
|
+
extra_types=[{"type": "string"}],
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
384
409
|
class BaseRunConfiguration(CoreModel):
|
|
385
410
|
type: Literal["none"]
|
|
386
411
|
name: Annotated[
|
|
@@ -484,18 +509,6 @@ class BaseRunConfiguration(CoreModel):
|
|
|
484
509
|
# deprecated since 0.18.31; task, service -- no effect; dev-environment -- executed right before `init`
|
|
485
510
|
setup: CommandsList = []
|
|
486
511
|
|
|
487
|
-
class Config(CoreModel.Config):
|
|
488
|
-
@staticmethod
|
|
489
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
490
|
-
add_extra_schema_types(
|
|
491
|
-
schema["properties"]["volumes"]["items"],
|
|
492
|
-
extra_types=[{"type": "string"}],
|
|
493
|
-
)
|
|
494
|
-
add_extra_schema_types(
|
|
495
|
-
schema["properties"]["files"]["items"],
|
|
496
|
-
extra_types=[{"type": "string"}],
|
|
497
|
-
)
|
|
498
|
-
|
|
499
512
|
@validator("python", pre=True, always=True)
|
|
500
513
|
def convert_python(cls, v, values) -> Optional[PythonVersion]:
|
|
501
514
|
if v is not None and values.get("image"):
|
|
@@ -621,20 +634,25 @@ class DevEnvironmentConfigurationParams(CoreModel):
|
|
|
621
634
|
return None
|
|
622
635
|
|
|
623
636
|
|
|
637
|
+
class DevEnvironmentConfigurationConfig(
|
|
638
|
+
ProfileParamsConfig,
|
|
639
|
+
BaseRunConfigurationConfig,
|
|
640
|
+
):
|
|
641
|
+
@staticmethod
|
|
642
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
643
|
+
ProfileParamsConfig.schema_extra(schema)
|
|
644
|
+
BaseRunConfigurationConfig.schema_extra(schema)
|
|
645
|
+
|
|
646
|
+
|
|
624
647
|
class DevEnvironmentConfiguration(
|
|
625
648
|
ProfileParams,
|
|
626
649
|
BaseRunConfiguration,
|
|
627
650
|
ConfigurationWithPortsParams,
|
|
628
651
|
DevEnvironmentConfigurationParams,
|
|
652
|
+
generate_dual_core_model(DevEnvironmentConfigurationConfig),
|
|
629
653
|
):
|
|
630
654
|
type: Literal["dev-environment"] = "dev-environment"
|
|
631
655
|
|
|
632
|
-
class Config(ProfileParams.Config, BaseRunConfiguration.Config):
|
|
633
|
-
@staticmethod
|
|
634
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
635
|
-
ProfileParams.Config.schema_extra(schema)
|
|
636
|
-
BaseRunConfiguration.Config.schema_extra(schema)
|
|
637
|
-
|
|
638
656
|
@validator("entrypoint")
|
|
639
657
|
def validate_entrypoint(cls, v: Optional[str]) -> Optional[str]:
|
|
640
658
|
if v is not None:
|
|
@@ -646,20 +664,38 @@ class TaskConfigurationParams(CoreModel):
|
|
|
646
664
|
nodes: Annotated[int, Field(description="Number of nodes", ge=1)] = 1
|
|
647
665
|
|
|
648
666
|
|
|
667
|
+
class TaskConfigurationConfig(
|
|
668
|
+
ProfileParamsConfig,
|
|
669
|
+
BaseRunConfigurationConfig,
|
|
670
|
+
):
|
|
671
|
+
@staticmethod
|
|
672
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
673
|
+
ProfileParamsConfig.schema_extra(schema)
|
|
674
|
+
BaseRunConfigurationConfig.schema_extra(schema)
|
|
675
|
+
|
|
676
|
+
|
|
649
677
|
class TaskConfiguration(
|
|
650
678
|
ProfileParams,
|
|
651
679
|
BaseRunConfiguration,
|
|
652
680
|
ConfigurationWithCommandsParams,
|
|
653
681
|
ConfigurationWithPortsParams,
|
|
654
682
|
TaskConfigurationParams,
|
|
683
|
+
generate_dual_core_model(TaskConfigurationConfig),
|
|
655
684
|
):
|
|
656
685
|
type: Literal["task"] = "task"
|
|
657
686
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
687
|
+
|
|
688
|
+
class ServiceConfigurationParamsConfig(CoreConfig):
|
|
689
|
+
@staticmethod
|
|
690
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
691
|
+
add_extra_schema_types(
|
|
692
|
+
schema["properties"]["replicas"],
|
|
693
|
+
extra_types=[{"type": "integer"}, {"type": "string"}],
|
|
694
|
+
)
|
|
695
|
+
add_extra_schema_types(
|
|
696
|
+
schema["properties"]["model"],
|
|
697
|
+
extra_types=[{"type": "string"}],
|
|
698
|
+
)
|
|
663
699
|
|
|
664
700
|
|
|
665
701
|
class ServiceConfigurationParams(CoreModel):
|
|
@@ -719,18 +755,6 @@ class ServiceConfigurationParams(CoreModel):
|
|
|
719
755
|
Field(description="List of probes used to determine job health"),
|
|
720
756
|
] = []
|
|
721
757
|
|
|
722
|
-
class Config(CoreModel.Config):
|
|
723
|
-
@staticmethod
|
|
724
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
725
|
-
add_extra_schema_types(
|
|
726
|
-
schema["properties"]["replicas"],
|
|
727
|
-
extra_types=[{"type": "integer"}, {"type": "string"}],
|
|
728
|
-
)
|
|
729
|
-
add_extra_schema_types(
|
|
730
|
-
schema["properties"]["model"],
|
|
731
|
-
extra_types=[{"type": "string"}],
|
|
732
|
-
)
|
|
733
|
-
|
|
734
758
|
@validator("port")
|
|
735
759
|
def convert_port(cls, v) -> PortMapping:
|
|
736
760
|
if isinstance(v, int):
|
|
@@ -797,25 +821,27 @@ class ServiceConfigurationParams(CoreModel):
|
|
|
797
821
|
return v
|
|
798
822
|
|
|
799
823
|
|
|
824
|
+
class ServiceConfigurationConfig(
|
|
825
|
+
ProfileParamsConfig,
|
|
826
|
+
BaseRunConfigurationConfig,
|
|
827
|
+
ServiceConfigurationParamsConfig,
|
|
828
|
+
):
|
|
829
|
+
@staticmethod
|
|
830
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
831
|
+
ProfileParamsConfig.schema_extra(schema)
|
|
832
|
+
BaseRunConfigurationConfig.schema_extra(schema)
|
|
833
|
+
ServiceConfigurationParamsConfig.schema_extra(schema)
|
|
834
|
+
|
|
835
|
+
|
|
800
836
|
class ServiceConfiguration(
|
|
801
837
|
ProfileParams,
|
|
802
838
|
BaseRunConfiguration,
|
|
803
839
|
ConfigurationWithCommandsParams,
|
|
804
840
|
ServiceConfigurationParams,
|
|
841
|
+
generate_dual_core_model(ServiceConfigurationConfig),
|
|
805
842
|
):
|
|
806
843
|
type: Literal["service"] = "service"
|
|
807
844
|
|
|
808
|
-
class Config(
|
|
809
|
-
ProfileParams.Config,
|
|
810
|
-
BaseRunConfiguration.Config,
|
|
811
|
-
ServiceConfigurationParams.Config,
|
|
812
|
-
):
|
|
813
|
-
@staticmethod
|
|
814
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
815
|
-
ProfileParams.Config.schema_extra(schema)
|
|
816
|
-
BaseRunConfiguration.Config.schema_extra(schema)
|
|
817
|
-
ServiceConfigurationParams.Config.schema_extra(schema)
|
|
818
|
-
|
|
819
845
|
|
|
820
846
|
AnyRunConfiguration = Union[DevEnvironmentConfiguration, TaskConfiguration, ServiceConfiguration]
|
|
821
847
|
|
|
@@ -876,7 +902,7 @@ class DstackConfiguration(CoreModel):
|
|
|
876
902
|
Field(discriminator="type"),
|
|
877
903
|
]
|
|
878
904
|
|
|
879
|
-
class Config(
|
|
905
|
+
class Config(CoreConfig):
|
|
880
906
|
json_loads = orjson.loads
|
|
881
907
|
json_dumps = pydantic_orjson_dumps_with_indent
|
|
882
908
|
|
|
@@ -2,13 +2,18 @@ import ipaddress
|
|
|
2
2
|
import uuid
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Any, Dict, List, Optional,
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
6
|
|
|
7
7
|
from pydantic import Field, root_validator, validator
|
|
8
8
|
from typing_extensions import Annotated, Literal
|
|
9
9
|
|
|
10
10
|
from dstack._internal.core.models.backends.base import BackendType
|
|
11
|
-
from dstack._internal.core.models.common import
|
|
11
|
+
from dstack._internal.core.models.common import (
|
|
12
|
+
ApplyAction,
|
|
13
|
+
CoreConfig,
|
|
14
|
+
CoreModel,
|
|
15
|
+
generate_dual_core_model,
|
|
16
|
+
)
|
|
12
17
|
from dstack._internal.core.models.envs import Env
|
|
13
18
|
from dstack._internal.core.models.instances import Instance, InstanceOfferWithAvailability, SSHKey
|
|
14
19
|
from dstack._internal.core.models.profiles import (
|
|
@@ -202,6 +207,21 @@ class FleetNodesSpec(CoreModel):
|
|
|
202
207
|
return values
|
|
203
208
|
|
|
204
209
|
|
|
210
|
+
class InstanceGroupParamsConfig(CoreConfig):
|
|
211
|
+
@staticmethod
|
|
212
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
213
|
+
del schema["properties"]["termination_policy"]
|
|
214
|
+
del schema["properties"]["termination_idle_time"]
|
|
215
|
+
add_extra_schema_types(
|
|
216
|
+
schema["properties"]["nodes"],
|
|
217
|
+
extra_types=[{"type": "integer"}, {"type": "string"}],
|
|
218
|
+
)
|
|
219
|
+
add_extra_schema_types(
|
|
220
|
+
schema["properties"]["idle_duration"],
|
|
221
|
+
extra_types=[{"type": "string"}],
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
205
225
|
class InstanceGroupParams(CoreModel):
|
|
206
226
|
env: Annotated[
|
|
207
227
|
Env,
|
|
@@ -297,20 +317,6 @@ class InstanceGroupParams(CoreModel):
|
|
|
297
317
|
termination_policy: Annotated[Optional[TerminationPolicy], Field(exclude=True)] = None
|
|
298
318
|
termination_idle_time: Annotated[Optional[Union[str, int]], Field(exclude=True)] = None
|
|
299
319
|
|
|
300
|
-
class Config(CoreModel.Config):
|
|
301
|
-
@staticmethod
|
|
302
|
-
def schema_extra(schema: Dict[str, Any], model: Type):
|
|
303
|
-
del schema["properties"]["termination_policy"]
|
|
304
|
-
del schema["properties"]["termination_idle_time"]
|
|
305
|
-
add_extra_schema_types(
|
|
306
|
-
schema["properties"]["nodes"],
|
|
307
|
-
extra_types=[{"type": "integer"}, {"type": "string"}],
|
|
308
|
-
)
|
|
309
|
-
add_extra_schema_types(
|
|
310
|
-
schema["properties"]["idle_duration"],
|
|
311
|
-
extra_types=[{"type": "string"}],
|
|
312
|
-
)
|
|
313
|
-
|
|
314
320
|
@validator("nodes", pre=True)
|
|
315
321
|
def parse_nodes(cls, v: Optional[Union[dict, str]]) -> Optional[dict]:
|
|
316
322
|
if isinstance(v, str) and ".." in v:
|
|
@@ -331,7 +337,17 @@ class FleetProps(CoreModel):
|
|
|
331
337
|
name: Annotated[Optional[str], Field(description="The fleet name")] = None
|
|
332
338
|
|
|
333
339
|
|
|
334
|
-
class
|
|
340
|
+
class FleetConfigurationConfig(InstanceGroupParamsConfig):
|
|
341
|
+
@staticmethod
|
|
342
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
343
|
+
InstanceGroupParamsConfig.schema_extra(schema)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class FleetConfiguration(
|
|
347
|
+
InstanceGroupParams,
|
|
348
|
+
FleetProps,
|
|
349
|
+
generate_dual_core_model(FleetConfigurationConfig),
|
|
350
|
+
):
|
|
335
351
|
tags: Annotated[
|
|
336
352
|
Optional[Dict[str, str]],
|
|
337
353
|
Field(
|
|
@@ -346,7 +362,14 @@ class FleetConfiguration(InstanceGroupParams, FleetProps):
|
|
|
346
362
|
_validate_tags = validator("tags", pre=True, allow_reuse=True)(tags_validator)
|
|
347
363
|
|
|
348
364
|
|
|
349
|
-
class
|
|
365
|
+
class FleetSpecConfig(CoreConfig):
|
|
366
|
+
@staticmethod
|
|
367
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
368
|
+
prop = schema.get("properties", {})
|
|
369
|
+
prop.pop("merged_profile", None)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
class FleetSpec(generate_dual_core_model(FleetSpecConfig)):
|
|
350
373
|
configuration: FleetConfiguration
|
|
351
374
|
configuration_path: Optional[str] = None
|
|
352
375
|
profile: Profile
|
|
@@ -356,12 +379,6 @@ class FleetSpec(CoreModel):
|
|
|
356
379
|
# TODO: make merged_profile a computed field after migrating to pydanticV2
|
|
357
380
|
merged_profile: Annotated[Profile, Field(exclude=True)] = None
|
|
358
381
|
|
|
359
|
-
class Config(CoreModel.Config):
|
|
360
|
-
@staticmethod
|
|
361
|
-
def schema_extra(schema: Dict[str, Any], model: Type) -> None:
|
|
362
|
-
prop = schema.get("properties", {})
|
|
363
|
-
prop.pop("merged_profile", None)
|
|
364
|
-
|
|
365
382
|
@root_validator
|
|
366
383
|
def _merged_profile(cls, values) -> Dict:
|
|
367
384
|
try:
|
|
@@ -7,7 +7,10 @@ import gpuhunt
|
|
|
7
7
|
from pydantic import root_validator
|
|
8
8
|
|
|
9
9
|
from dstack._internal.core.models.backends.base import BackendType
|
|
10
|
-
from dstack._internal.core.models.common import
|
|
10
|
+
from dstack._internal.core.models.common import (
|
|
11
|
+
CoreModel,
|
|
12
|
+
FrozenCoreModel,
|
|
13
|
+
)
|
|
11
14
|
from dstack._internal.core.models.envs import Env
|
|
12
15
|
from dstack._internal.core.models.health import HealthStatus
|
|
13
16
|
from dstack._internal.core.models.volumes import Volume
|
|
@@ -117,14 +120,11 @@ class InstanceType(CoreModel):
|
|
|
117
120
|
resources: Resources
|
|
118
121
|
|
|
119
122
|
|
|
120
|
-
class SSHConnectionParams(
|
|
123
|
+
class SSHConnectionParams(FrozenCoreModel):
|
|
121
124
|
hostname: str
|
|
122
125
|
username: str
|
|
123
126
|
port: int
|
|
124
127
|
|
|
125
|
-
class Config(CoreModel.Config):
|
|
126
|
-
frozen = True
|
|
127
|
-
|
|
128
128
|
|
|
129
129
|
class SSHKey(CoreModel):
|
|
130
130
|
public: str
|
|
@@ -6,7 +6,12 @@ from pydantic import Field, root_validator, validator
|
|
|
6
6
|
from typing_extensions import Annotated, Literal
|
|
7
7
|
|
|
8
8
|
from dstack._internal.core.models.backends.base import BackendType
|
|
9
|
-
from dstack._internal.core.models.common import
|
|
9
|
+
from dstack._internal.core.models.common import (
|
|
10
|
+
CoreConfig,
|
|
11
|
+
CoreModel,
|
|
12
|
+
Duration,
|
|
13
|
+
generate_dual_core_model,
|
|
14
|
+
)
|
|
10
15
|
from dstack._internal.utils.common import list_enum_values_for_annotation
|
|
11
16
|
from dstack._internal.utils.cron import validate_cron
|
|
12
17
|
from dstack._internal.utils.json_schema import add_extra_schema_types
|
|
@@ -112,7 +117,16 @@ class RetryEvent(str, Enum):
|
|
|
112
117
|
ERROR = "error"
|
|
113
118
|
|
|
114
119
|
|
|
115
|
-
class
|
|
120
|
+
class ProfileRetryConfig(CoreConfig):
|
|
121
|
+
@staticmethod
|
|
122
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
123
|
+
add_extra_schema_types(
|
|
124
|
+
schema["properties"]["duration"],
|
|
125
|
+
extra_types=[{"type": "string"}],
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ProfileRetry(generate_dual_core_model(ProfileRetryConfig)):
|
|
116
130
|
on_events: Annotated[
|
|
117
131
|
Optional[List[RetryEvent]],
|
|
118
132
|
Field(
|
|
@@ -128,14 +142,6 @@ class ProfileRetry(CoreModel):
|
|
|
128
142
|
Field(description="The maximum period of retrying the run, e.g., `4h` or `1d`"),
|
|
129
143
|
] = None
|
|
130
144
|
|
|
131
|
-
class Config(CoreModel.Config):
|
|
132
|
-
@staticmethod
|
|
133
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
134
|
-
add_extra_schema_types(
|
|
135
|
-
schema["properties"]["duration"],
|
|
136
|
-
extra_types=[{"type": "string"}],
|
|
137
|
-
)
|
|
138
|
-
|
|
139
145
|
_validate_duration = validator("duration", pre=True, allow_reuse=True)(parse_duration)
|
|
140
146
|
|
|
141
147
|
@root_validator
|
|
@@ -146,7 +152,16 @@ class ProfileRetry(CoreModel):
|
|
|
146
152
|
return values
|
|
147
153
|
|
|
148
154
|
|
|
149
|
-
class
|
|
155
|
+
class UtilizationPolicyConfig(CoreConfig):
|
|
156
|
+
@staticmethod
|
|
157
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
158
|
+
add_extra_schema_types(
|
|
159
|
+
schema["properties"]["time_window"],
|
|
160
|
+
extra_types=[{"type": "string"}],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class UtilizationPolicy(generate_dual_core_model(UtilizationPolicyConfig)):
|
|
150
165
|
_min_time_window = "5m"
|
|
151
166
|
|
|
152
167
|
min_gpu_utilization: Annotated[
|
|
@@ -171,14 +186,6 @@ class UtilizationPolicy(CoreModel):
|
|
|
171
186
|
),
|
|
172
187
|
]
|
|
173
188
|
|
|
174
|
-
class Config(CoreModel.Config):
|
|
175
|
-
@staticmethod
|
|
176
|
-
def schema_extra(schema: Dict[str, Any]):
|
|
177
|
-
add_extra_schema_types(
|
|
178
|
-
schema["properties"]["time_window"],
|
|
179
|
-
extra_types=[{"type": "string"}],
|
|
180
|
-
)
|
|
181
|
-
|
|
182
189
|
@validator("time_window", pre=True)
|
|
183
190
|
def validate_time_window(cls, v: Union[int, str]) -> int:
|
|
184
191
|
v = parse_duration(v)
|
|
@@ -219,6 +226,28 @@ class Schedule(CoreModel):
|
|
|
219
226
|
return self.cron
|
|
220
227
|
|
|
221
228
|
|
|
229
|
+
class ProfileParamsConfig(CoreConfig):
|
|
230
|
+
@staticmethod
|
|
231
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
232
|
+
del schema["properties"]["pool_name"]
|
|
233
|
+
del schema["properties"]["instance_name"]
|
|
234
|
+
del schema["properties"]["retry_policy"]
|
|
235
|
+
del schema["properties"]["termination_policy"]
|
|
236
|
+
del schema["properties"]["termination_idle_time"]
|
|
237
|
+
add_extra_schema_types(
|
|
238
|
+
schema["properties"]["max_duration"],
|
|
239
|
+
extra_types=[{"type": "boolean"}, {"type": "string"}],
|
|
240
|
+
)
|
|
241
|
+
add_extra_schema_types(
|
|
242
|
+
schema["properties"]["stop_duration"],
|
|
243
|
+
extra_types=[{"type": "boolean"}, {"type": "string"}],
|
|
244
|
+
)
|
|
245
|
+
add_extra_schema_types(
|
|
246
|
+
schema["properties"]["idle_duration"],
|
|
247
|
+
extra_types=[{"type": "string"}],
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
222
251
|
class ProfileParams(CoreModel):
|
|
223
252
|
backends: Annotated[
|
|
224
253
|
Optional[List[BackendType]],
|
|
@@ -358,27 +387,6 @@ class ProfileParams(CoreModel):
|
|
|
358
387
|
termination_policy: Annotated[Optional[TerminationPolicy], Field(exclude=True)] = None
|
|
359
388
|
termination_idle_time: Annotated[Optional[Union[str, int]], Field(exclude=True)] = None
|
|
360
389
|
|
|
361
|
-
class Config(CoreModel.Config):
|
|
362
|
-
@staticmethod
|
|
363
|
-
def schema_extra(schema: Dict[str, Any]) -> None:
|
|
364
|
-
del schema["properties"]["pool_name"]
|
|
365
|
-
del schema["properties"]["instance_name"]
|
|
366
|
-
del schema["properties"]["retry_policy"]
|
|
367
|
-
del schema["properties"]["termination_policy"]
|
|
368
|
-
del schema["properties"]["termination_idle_time"]
|
|
369
|
-
add_extra_schema_types(
|
|
370
|
-
schema["properties"]["max_duration"],
|
|
371
|
-
extra_types=[{"type": "boolean"}, {"type": "string"}],
|
|
372
|
-
)
|
|
373
|
-
add_extra_schema_types(
|
|
374
|
-
schema["properties"]["stop_duration"],
|
|
375
|
-
extra_types=[{"type": "boolean"}, {"type": "string"}],
|
|
376
|
-
)
|
|
377
|
-
add_extra_schema_types(
|
|
378
|
-
schema["properties"]["idle_duration"],
|
|
379
|
-
extra_types=[{"type": "string"}],
|
|
380
|
-
)
|
|
381
|
-
|
|
382
390
|
_validate_max_duration = validator("max_duration", pre=True, allow_reuse=True)(
|
|
383
391
|
parse_max_duration
|
|
384
392
|
)
|
|
@@ -403,17 +411,28 @@ class ProfileProps(CoreModel):
|
|
|
403
411
|
] = False
|
|
404
412
|
|
|
405
413
|
|
|
406
|
-
class
|
|
414
|
+
class ProfileConfig(ProfileParamsConfig):
|
|
415
|
+
@staticmethod
|
|
416
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
417
|
+
ProfileParamsConfig.schema_extra(schema)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
class Profile(
|
|
421
|
+
ProfileProps,
|
|
422
|
+
ProfileParams,
|
|
423
|
+
generate_dual_core_model(ProfileConfig),
|
|
424
|
+
):
|
|
407
425
|
pass
|
|
408
426
|
|
|
409
427
|
|
|
410
|
-
class
|
|
411
|
-
|
|
428
|
+
class ProfilesConfigConfig(CoreConfig):
|
|
429
|
+
json_loads = orjson.loads
|
|
430
|
+
json_dumps = pydantic_orjson_dumps_with_indent
|
|
431
|
+
schema_extra = {"$schema": "http://json-schema.org/draft-07/schema#"}
|
|
412
432
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
schema_extra = {"$schema": "http://json-schema.org/draft-07/schema#"}
|
|
433
|
+
|
|
434
|
+
class ProfilesConfig(generate_dual_core_model(ProfilesConfigConfig)):
|
|
435
|
+
profiles: List[Profile]
|
|
417
436
|
|
|
418
437
|
def default(self) -> Optional[Profile]:
|
|
419
438
|
for p in self.profiles:
|
|
@@ -11,7 +11,7 @@ from pydantic import Field
|
|
|
11
11
|
from typing_extensions import Literal
|
|
12
12
|
|
|
13
13
|
from dstack._internal.core.errors import DstackError
|
|
14
|
-
from dstack._internal.core.models.common import
|
|
14
|
+
from dstack._internal.core.models.common import CoreConfig, generate_dual_core_model
|
|
15
15
|
from dstack._internal.core.models.repos.base import BaseRepoInfo, Repo
|
|
16
16
|
from dstack._internal.utils.hash import get_sha256, slugify
|
|
17
17
|
from dstack._internal.utils.path import PathLike
|
|
@@ -24,21 +24,33 @@ class RepoError(DstackError):
|
|
|
24
24
|
pass
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class
|
|
27
|
+
class RemoteRepoCredsConfig(CoreConfig):
|
|
28
|
+
@staticmethod
|
|
29
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
30
|
+
del schema["properties"]["protocol"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RemoteRepoCreds(generate_dual_core_model(RemoteRepoCredsConfig)):
|
|
28
34
|
clone_url: str
|
|
29
|
-
private_key: Optional[str]
|
|
30
|
-
oauth_token: Optional[str]
|
|
35
|
+
private_key: Optional[str] = None
|
|
36
|
+
oauth_token: Optional[str] = None
|
|
31
37
|
|
|
32
38
|
# TODO: remove in 0.20. Left for compatibility with CLI <=0.18.44
|
|
33
39
|
protocol: Annotated[Optional[str], Field(exclude=True)] = None
|
|
34
40
|
|
|
35
|
-
class Config(CoreModel.Config):
|
|
36
|
-
@staticmethod
|
|
37
|
-
def schema_extra(schema: Dict[str, Any]) -> None:
|
|
38
|
-
del schema["properties"]["protocol"]
|
|
39
41
|
|
|
42
|
+
class RemoteRepoInfoConfig(CoreConfig):
|
|
43
|
+
@staticmethod
|
|
44
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
45
|
+
del schema["properties"]["repo_host_name"]
|
|
46
|
+
del schema["properties"]["repo_port"]
|
|
47
|
+
del schema["properties"]["repo_user_name"]
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
|
|
50
|
+
class RemoteRepoInfo(
|
|
51
|
+
BaseRepoInfo,
|
|
52
|
+
generate_dual_core_model(RemoteRepoInfoConfig),
|
|
53
|
+
):
|
|
42
54
|
repo_type: Literal["remote"] = "remote"
|
|
43
55
|
repo_name: str
|
|
44
56
|
|
|
@@ -47,13 +59,6 @@ class RemoteRepoInfo(BaseRepoInfo):
|
|
|
47
59
|
repo_port: Annotated[Optional[int], Field(exclude=True)] = None
|
|
48
60
|
repo_user_name: Annotated[Optional[str], Field(exclude=True)] = None
|
|
49
61
|
|
|
50
|
-
class Config(BaseRepoInfo.Config):
|
|
51
|
-
@staticmethod
|
|
52
|
-
def schema_extra(schema: Dict[str, Any]) -> None:
|
|
53
|
-
del schema["properties"]["repo_host_name"]
|
|
54
|
-
del schema["properties"]["repo_port"]
|
|
55
|
-
del schema["properties"]["repo_user_name"]
|
|
56
|
-
|
|
57
62
|
|
|
58
63
|
class RemoteRunRepoData(RemoteRepoInfo):
|
|
59
64
|
repo_branch: Optional[str] = None
|