dstack 0.18.43__py3-none-any.whl → 0.19.0__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/gateway.py +15 -3
- dstack/_internal/cli/commands/logs.py +0 -22
- dstack/_internal/cli/commands/stats.py +8 -17
- dstack/_internal/cli/main.py +1 -5
- dstack/_internal/cli/services/configurators/fleet.py +4 -39
- dstack/_internal/cli/services/configurators/run.py +22 -20
- dstack/_internal/cli/services/profile.py +34 -83
- dstack/_internal/cli/utils/gateway.py +1 -1
- dstack/_internal/cli/utils/run.py +11 -0
- dstack/_internal/core/backends/__init__.py +56 -39
- dstack/_internal/core/backends/aws/__init__.py +0 -25
- dstack/_internal/core/backends/aws/auth.py +1 -10
- dstack/_internal/core/backends/aws/backend.py +26 -0
- dstack/_internal/core/backends/aws/compute.py +21 -45
- dstack/_internal/{server/services/backends/configurators/aws.py → core/backends/aws/configurator.py} +46 -85
- dstack/_internal/core/backends/aws/models.py +135 -0
- dstack/_internal/core/backends/aws/resources.py +1 -1
- dstack/_internal/core/backends/azure/__init__.py +0 -20
- dstack/_internal/core/backends/azure/auth.py +2 -11
- dstack/_internal/core/backends/azure/backend.py +21 -0
- dstack/_internal/core/backends/azure/compute.py +14 -28
- dstack/_internal/{server/services/backends/configurators/azure.py → core/backends/azure/configurator.py} +141 -210
- dstack/_internal/core/backends/azure/models.py +89 -0
- dstack/_internal/core/backends/base/__init__.py +0 -12
- dstack/_internal/core/backends/base/backend.py +18 -0
- dstack/_internal/core/backends/base/compute.py +153 -33
- dstack/_internal/core/backends/base/configurator.py +105 -0
- dstack/_internal/core/backends/base/models.py +14 -0
- dstack/_internal/core/backends/configurators.py +138 -0
- dstack/_internal/core/backends/cudo/__init__.py +0 -15
- dstack/_internal/core/backends/cudo/backend.py +16 -0
- dstack/_internal/core/backends/cudo/compute.py +8 -26
- dstack/_internal/core/backends/cudo/configurator.py +72 -0
- dstack/_internal/core/backends/cudo/models.py +37 -0
- dstack/_internal/core/backends/datacrunch/__init__.py +0 -15
- dstack/_internal/core/backends/datacrunch/backend.py +16 -0
- dstack/_internal/core/backends/datacrunch/compute.py +8 -25
- dstack/_internal/core/backends/datacrunch/configurator.py +66 -0
- dstack/_internal/core/backends/datacrunch/models.py +38 -0
- dstack/_internal/core/{models/backends/dstack.py → backends/dstack/models.py} +7 -7
- dstack/_internal/core/backends/gcp/__init__.py +0 -16
- dstack/_internal/core/backends/gcp/auth.py +2 -11
- dstack/_internal/core/backends/gcp/backend.py +17 -0
- dstack/_internal/core/backends/gcp/compute.py +14 -44
- dstack/_internal/{server/services/backends/configurators/gcp.py → core/backends/gcp/configurator.py} +46 -103
- dstack/_internal/core/backends/gcp/models.py +125 -0
- dstack/_internal/core/backends/kubernetes/__init__.py +0 -15
- dstack/_internal/core/backends/kubernetes/backend.py +16 -0
- dstack/_internal/core/backends/kubernetes/compute.py +16 -5
- dstack/_internal/core/backends/kubernetes/configurator.py +55 -0
- dstack/_internal/core/backends/kubernetes/models.py +72 -0
- dstack/_internal/core/backends/lambdalabs/__init__.py +0 -16
- dstack/_internal/core/backends/lambdalabs/backend.py +17 -0
- dstack/_internal/core/backends/lambdalabs/compute.py +7 -28
- dstack/_internal/core/backends/lambdalabs/configurator.py +82 -0
- dstack/_internal/core/backends/lambdalabs/models.py +37 -0
- dstack/_internal/core/backends/local/__init__.py +0 -13
- dstack/_internal/core/backends/local/backend.py +14 -0
- dstack/_internal/core/backends/local/compute.py +16 -2
- dstack/_internal/core/backends/models.py +128 -0
- dstack/_internal/core/backends/oci/__init__.py +0 -15
- dstack/_internal/core/backends/oci/auth.py +1 -5
- dstack/_internal/core/backends/oci/backend.py +16 -0
- dstack/_internal/core/backends/oci/compute.py +9 -23
- dstack/_internal/{server/services/backends/configurators/oci.py → core/backends/oci/configurator.py} +40 -85
- dstack/_internal/core/{models/backends/oci.py → backends/oci/models.py} +24 -25
- dstack/_internal/core/backends/oci/region.py +1 -1
- dstack/_internal/core/backends/runpod/__init__.py +0 -15
- dstack/_internal/core/backends/runpod/backend.py +16 -0
- dstack/_internal/core/backends/runpod/compute.py +28 -6
- dstack/_internal/core/backends/runpod/configurator.py +59 -0
- dstack/_internal/core/backends/runpod/models.py +54 -0
- dstack/_internal/core/backends/template/__init__.py +0 -0
- dstack/_internal/core/backends/tensordock/__init__.py +0 -15
- dstack/_internal/core/backends/tensordock/backend.py +16 -0
- dstack/_internal/core/backends/tensordock/compute.py +8 -27
- dstack/_internal/core/backends/tensordock/configurator.py +68 -0
- dstack/_internal/core/backends/tensordock/models.py +38 -0
- dstack/_internal/core/backends/vastai/__init__.py +0 -15
- dstack/_internal/core/backends/vastai/backend.py +16 -0
- dstack/_internal/core/backends/vastai/compute.py +2 -2
- dstack/_internal/core/backends/vastai/configurator.py +66 -0
- dstack/_internal/core/backends/vastai/models.py +37 -0
- dstack/_internal/core/backends/vultr/__init__.py +0 -15
- dstack/_internal/core/backends/vultr/backend.py +16 -0
- dstack/_internal/core/backends/vultr/compute.py +10 -24
- dstack/_internal/core/backends/vultr/configurator.py +64 -0
- dstack/_internal/core/backends/vultr/models.py +34 -0
- dstack/_internal/core/models/backends/__init__.py +0 -184
- dstack/_internal/core/models/backends/base.py +0 -19
- dstack/_internal/core/models/configurations.py +22 -16
- dstack/_internal/core/models/envs.py +4 -3
- dstack/_internal/core/models/fleets.py +17 -22
- dstack/_internal/core/models/gateways.py +3 -3
- dstack/_internal/core/models/instances.py +24 -0
- dstack/_internal/core/models/profiles.py +85 -45
- dstack/_internal/core/models/projects.py +1 -1
- dstack/_internal/core/models/repos/base.py +0 -5
- dstack/_internal/core/models/repos/local.py +3 -3
- dstack/_internal/core/models/repos/remote.py +26 -12
- dstack/_internal/core/models/repos/virtual.py +1 -1
- dstack/_internal/core/models/resources.py +45 -76
- dstack/_internal/core/models/runs.py +21 -19
- dstack/_internal/core/models/volumes.py +1 -3
- dstack/_internal/core/services/profiles.py +7 -16
- dstack/_internal/core/services/repos.py +0 -4
- dstack/_internal/server/app.py +11 -4
- dstack/_internal/server/background/__init__.py +10 -0
- dstack/_internal/server/background/tasks/process_gateways.py +4 -8
- dstack/_internal/server/background/tasks/process_instances.py +14 -9
- dstack/_internal/server/background/tasks/process_metrics.py +1 -1
- dstack/_internal/server/background/tasks/process_placement_groups.py +5 -1
- dstack/_internal/server/background/tasks/process_prometheus_metrics.py +135 -0
- dstack/_internal/server/background/tasks/process_running_jobs.py +80 -24
- dstack/_internal/server/background/tasks/process_runs.py +1 -0
- dstack/_internal/server/background/tasks/process_submitted_jobs.py +20 -38
- dstack/_internal/server/background/tasks/process_volumes.py +5 -2
- dstack/_internal/server/migrations/versions/60e444118b6d_add_jobprometheusmetrics.py +40 -0
- dstack/_internal/server/migrations/versions/7bc2586e8b9e_make_instancemodel_pool_id_optional.py +36 -0
- dstack/_internal/server/migrations/versions/98d1b92988bc_add_jobterminationreason_terminated_due_.py +140 -0
- dstack/_internal/server/migrations/versions/bc8ca4a505c6_store_backendtype_as_string.py +171 -0
- dstack/_internal/server/models.py +59 -9
- dstack/_internal/server/routers/backends.py +14 -23
- dstack/_internal/server/routers/instances.py +3 -4
- dstack/_internal/server/routers/metrics.py +31 -10
- dstack/_internal/server/routers/prometheus.py +36 -0
- dstack/_internal/server/routers/repos.py +1 -2
- dstack/_internal/server/routers/runs.py +13 -59
- dstack/_internal/server/schemas/gateways.py +14 -23
- dstack/_internal/server/schemas/projects.py +7 -2
- dstack/_internal/server/schemas/repos.py +2 -38
- dstack/_internal/server/schemas/runner.py +1 -0
- dstack/_internal/server/schemas/runs.py +1 -24
- dstack/_internal/server/security/permissions.py +1 -1
- dstack/_internal/server/services/backends/__init__.py +85 -158
- dstack/_internal/server/services/config.py +53 -567
- dstack/_internal/server/services/fleets.py +9 -103
- dstack/_internal/server/services/gateways/__init__.py +13 -4
- dstack/_internal/server/services/{pools.py → instances.py} +22 -329
- dstack/_internal/server/services/jobs/__init__.py +9 -6
- dstack/_internal/server/services/jobs/configurators/base.py +25 -1
- dstack/_internal/server/services/jobs/configurators/dev.py +9 -1
- dstack/_internal/server/services/jobs/configurators/extensions/cursor.py +42 -0
- dstack/_internal/server/services/metrics.py +131 -72
- dstack/_internal/server/services/offers.py +1 -1
- dstack/_internal/server/services/projects.py +23 -14
- dstack/_internal/server/services/prometheus.py +245 -0
- dstack/_internal/server/services/runner/client.py +14 -3
- dstack/_internal/server/services/runs.py +67 -31
- dstack/_internal/server/services/volumes.py +9 -4
- dstack/_internal/server/settings.py +3 -0
- dstack/_internal/server/statics/index.html +1 -1
- dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js → main-4a0fe83e84574654e397.js} +76 -19
- dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js.map → main-4a0fe83e84574654e397.js.map} +1 -1
- dstack/_internal/server/statics/{main-7510e71dfa9749a4e70e.css → main-da9f8c06a69c20dac23e.css} +1 -1
- dstack/_internal/server/statics/static/media/entraID.d65d1f3e9486a8e56d24fc07b3230885.svg +9 -0
- dstack/_internal/server/testing/common.py +75 -32
- dstack/_internal/utils/json_schema.py +6 -0
- dstack/_internal/utils/ssh.py +2 -1
- dstack/api/__init__.py +4 -0
- dstack/api/_public/__init__.py +16 -20
- dstack/api/_public/backends.py +1 -1
- dstack/api/_public/repos.py +36 -36
- dstack/api/_public/runs.py +170 -83
- dstack/api/server/__init__.py +11 -13
- dstack/api/server/_backends.py +12 -16
- dstack/api/server/_fleets.py +15 -55
- dstack/api/server/_gateways.py +3 -14
- dstack/api/server/_repos.py +1 -4
- dstack/api/server/_runs.py +21 -96
- dstack/api/server/_volumes.py +10 -5
- dstack/api/utils.py +3 -0
- dstack/version.py +1 -1
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/METADATA +10 -1
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/RECORD +229 -206
- tests/_internal/cli/services/configurators/test_profile.py +6 -6
- tests/_internal/core/backends/aws/test_configurator.py +35 -0
- tests/_internal/core/backends/aws/test_resources.py +1 -1
- tests/_internal/core/backends/azure/test_configurator.py +61 -0
- tests/_internal/core/backends/cudo/__init__.py +0 -0
- tests/_internal/core/backends/cudo/test_configurator.py +37 -0
- tests/_internal/core/backends/datacrunch/__init__.py +0 -0
- tests/_internal/core/backends/datacrunch/test_configurator.py +17 -0
- tests/_internal/core/backends/gcp/test_configurator.py +42 -0
- tests/_internal/core/backends/kubernetes/test_configurator.py +43 -0
- tests/_internal/core/backends/lambdalabs/__init__.py +0 -0
- tests/_internal/core/backends/lambdalabs/test_configurator.py +38 -0
- tests/_internal/core/backends/oci/test_configurator.py +55 -0
- tests/_internal/core/backends/runpod/__init__.py +0 -0
- tests/_internal/core/backends/runpod/test_configurator.py +33 -0
- tests/_internal/core/backends/tensordock/__init__.py +0 -0
- tests/_internal/core/backends/tensordock/test_configurator.py +38 -0
- tests/_internal/core/backends/vastai/__init__.py +0 -0
- tests/_internal/core/backends/vastai/test_configurator.py +33 -0
- tests/_internal/core/backends/vultr/__init__.py +0 -0
- tests/_internal/core/backends/vultr/test_configurator.py +33 -0
- tests/_internal/server/background/tasks/test_process_gateways.py +4 -0
- tests/_internal/server/background/tasks/test_process_instances.py +49 -48
- tests/_internal/server/background/tasks/test_process_metrics.py +0 -3
- tests/_internal/server/background/tasks/test_process_placement_groups.py +2 -0
- tests/_internal/server/background/tasks/test_process_prometheus_metrics.py +186 -0
- tests/_internal/server/background/tasks/test_process_running_jobs.py +123 -19
- tests/_internal/server/background/tasks/test_process_runs.py +8 -22
- tests/_internal/server/background/tasks/test_process_submitted_jobs.py +3 -40
- tests/_internal/server/background/tasks/test_process_submitted_volumes.py +2 -0
- tests/_internal/server/background/tasks/test_process_terminating_jobs.py +10 -15
- tests/_internal/server/routers/test_backends.py +6 -764
- tests/_internal/server/routers/test_fleets.py +2 -26
- tests/_internal/server/routers/test_gateways.py +27 -3
- tests/_internal/server/routers/test_instances.py +0 -10
- tests/_internal/server/routers/test_metrics.py +42 -0
- tests/_internal/server/routers/test_projects.py +56 -0
- tests/_internal/server/routers/test_prometheus.py +333 -0
- tests/_internal/server/routers/test_repos.py +0 -15
- tests/_internal/server/routers/test_runs.py +83 -275
- tests/_internal/server/routers/test_volumes.py +2 -3
- tests/_internal/server/services/backends/__init__.py +0 -0
- tests/_internal/server/services/jobs/configurators/test_task.py +35 -0
- tests/_internal/server/services/test_config.py +7 -4
- tests/_internal/server/services/test_fleets.py +1 -4
- tests/_internal/server/services/{test_pools.py → test_instances.py} +11 -49
- tests/_internal/server/services/test_metrics.py +167 -0
- tests/_internal/server/services/test_repos.py +1 -14
- tests/_internal/server/services/test_runs.py +0 -4
- dstack/_internal/cli/commands/pool.py +0 -581
- dstack/_internal/cli/commands/run.py +0 -75
- dstack/_internal/core/backends/aws/config.py +0 -18
- dstack/_internal/core/backends/azure/config.py +0 -12
- dstack/_internal/core/backends/base/config.py +0 -5
- dstack/_internal/core/backends/cudo/config.py +0 -9
- dstack/_internal/core/backends/datacrunch/config.py +0 -9
- dstack/_internal/core/backends/gcp/config.py +0 -22
- dstack/_internal/core/backends/kubernetes/config.py +0 -6
- dstack/_internal/core/backends/lambdalabs/config.py +0 -9
- dstack/_internal/core/backends/nebius/__init__.py +0 -15
- dstack/_internal/core/backends/nebius/api_client.py +0 -319
- dstack/_internal/core/backends/nebius/compute.py +0 -220
- dstack/_internal/core/backends/nebius/config.py +0 -6
- dstack/_internal/core/backends/nebius/types.py +0 -37
- dstack/_internal/core/backends/oci/config.py +0 -6
- dstack/_internal/core/backends/runpod/config.py +0 -9
- dstack/_internal/core/backends/tensordock/config.py +0 -9
- dstack/_internal/core/backends/vastai/config.py +0 -6
- dstack/_internal/core/backends/vultr/config.py +0 -9
- dstack/_internal/core/models/backends/aws.py +0 -86
- dstack/_internal/core/models/backends/azure.py +0 -68
- dstack/_internal/core/models/backends/cudo.py +0 -43
- dstack/_internal/core/models/backends/datacrunch.py +0 -44
- dstack/_internal/core/models/backends/gcp.py +0 -67
- dstack/_internal/core/models/backends/kubernetes.py +0 -40
- dstack/_internal/core/models/backends/lambdalabs.py +0 -43
- dstack/_internal/core/models/backends/nebius.py +0 -54
- dstack/_internal/core/models/backends/runpod.py +0 -40
- dstack/_internal/core/models/backends/tensordock.py +0 -44
- dstack/_internal/core/models/backends/vastai.py +0 -43
- dstack/_internal/core/models/backends/vultr.py +0 -40
- dstack/_internal/core/models/pools.py +0 -43
- dstack/_internal/server/routers/pools.py +0 -142
- dstack/_internal/server/schemas/pools.py +0 -38
- dstack/_internal/server/services/backends/configurators/base.py +0 -72
- dstack/_internal/server/services/backends/configurators/cudo.py +0 -87
- dstack/_internal/server/services/backends/configurators/datacrunch.py +0 -79
- dstack/_internal/server/services/backends/configurators/kubernetes.py +0 -63
- dstack/_internal/server/services/backends/configurators/lambdalabs.py +0 -98
- dstack/_internal/server/services/backends/configurators/nebius.py +0 -85
- dstack/_internal/server/services/backends/configurators/runpod.py +0 -97
- dstack/_internal/server/services/backends/configurators/tensordock.py +0 -82
- dstack/_internal/server/services/backends/configurators/vastai.py +0 -80
- dstack/_internal/server/services/backends/configurators/vultr.py +0 -80
- dstack/api/_public/pools.py +0 -41
- dstack/api/_public/resources.py +0 -105
- dstack/api/server/_pools.py +0 -63
- tests/_internal/server/routers/test_pools.py +0 -612
- /dstack/_internal/{server/services/backends/configurators → core/backends/dstack}/__init__.py +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/LICENSE.md +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/WHEEL +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/entry_points.txt +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from dstack._internal.core.backends.base import Backend
|
|
2
|
-
from dstack._internal.core.backends.vultr.compute import VultrCompute
|
|
3
|
-
from dstack._internal.core.backends.vultr.config import VultrConfig
|
|
4
|
-
from dstack._internal.core.models.backends.base import BackendType
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class VultrBackend(Backend):
|
|
8
|
-
TYPE: BackendType = BackendType.VULTR
|
|
9
|
-
|
|
10
|
-
def __init__(self, config: VultrConfig):
|
|
11
|
-
self.config = config
|
|
12
|
-
self._compute = VultrCompute(self.config)
|
|
13
|
-
|
|
14
|
-
def compute(self) -> VultrCompute:
|
|
15
|
-
return self._compute
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dstack._internal.core.backends.base.backend import Backend
|
|
2
|
+
from dstack._internal.core.backends.vultr.compute import VultrCompute
|
|
3
|
+
from dstack._internal.core.backends.vultr.models import VultrConfig
|
|
4
|
+
from dstack._internal.core.models.backends.base import BackendType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class VultrBackend(Backend):
|
|
8
|
+
TYPE = BackendType.VULTR
|
|
9
|
+
COMPUTE_CLASS = VultrCompute
|
|
10
|
+
|
|
11
|
+
def __init__(self, config: VultrConfig):
|
|
12
|
+
self.config = config
|
|
13
|
+
self._compute = VultrCompute(self.config)
|
|
14
|
+
|
|
15
|
+
def compute(self) -> VultrCompute:
|
|
16
|
+
return self._compute
|
|
@@ -4,15 +4,16 @@ from typing import List, Optional
|
|
|
4
4
|
|
|
5
5
|
import requests
|
|
6
6
|
|
|
7
|
-
from dstack._internal.core.backends.base import Compute
|
|
7
|
+
from dstack._internal.core.backends.base.backend import Compute
|
|
8
8
|
from dstack._internal.core.backends.base.compute import (
|
|
9
|
+
ComputeWithCreateInstanceSupport,
|
|
10
|
+
ComputeWithMultinodeSupport,
|
|
9
11
|
generate_unique_instance_name,
|
|
10
|
-
get_job_instance_name,
|
|
11
12
|
get_user_data,
|
|
12
13
|
)
|
|
13
14
|
from dstack._internal.core.backends.base.offers import get_catalog_offers
|
|
14
15
|
from dstack._internal.core.backends.vultr.api_client import VultrApiClient
|
|
15
|
-
from dstack._internal.core.backends.vultr.
|
|
16
|
+
from dstack._internal.core.backends.vultr.models import VultrConfig
|
|
16
17
|
from dstack._internal.core.errors import BackendError, ProvisioningError
|
|
17
18
|
from dstack._internal.core.models.backends.base import BackendType
|
|
18
19
|
from dstack._internal.core.models.instances import (
|
|
@@ -20,10 +21,8 @@ from dstack._internal.core.models.instances import (
|
|
|
20
21
|
InstanceConfiguration,
|
|
21
22
|
InstanceOffer,
|
|
22
23
|
InstanceOfferWithAvailability,
|
|
23
|
-
SSHKey,
|
|
24
24
|
)
|
|
25
|
-
from dstack._internal.core.models.runs import
|
|
26
|
-
from dstack._internal.core.models.volumes import Volume
|
|
25
|
+
from dstack._internal.core.models.runs import JobProvisioningData, Requirements
|
|
27
26
|
from dstack._internal.utils.logging import get_logger
|
|
28
27
|
|
|
29
28
|
logger = get_logger(__name__)
|
|
@@ -31,7 +30,11 @@ logger = get_logger(__name__)
|
|
|
31
30
|
MAX_INSTANCE_NAME_LEN = 64
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
class VultrCompute(
|
|
33
|
+
class VultrCompute(
|
|
34
|
+
ComputeWithCreateInstanceSupport,
|
|
35
|
+
ComputeWithMultinodeSupport,
|
|
36
|
+
Compute,
|
|
37
|
+
):
|
|
35
38
|
def __init__(self, config: VultrConfig):
|
|
36
39
|
super().__init__()
|
|
37
40
|
self.config = config
|
|
@@ -54,23 +57,6 @@ class VultrCompute(Compute):
|
|
|
54
57
|
]
|
|
55
58
|
return offers
|
|
56
59
|
|
|
57
|
-
def run_job(
|
|
58
|
-
self,
|
|
59
|
-
run: Run,
|
|
60
|
-
job: Job,
|
|
61
|
-
instance_offer: InstanceOfferWithAvailability,
|
|
62
|
-
project_ssh_public_key: str,
|
|
63
|
-
project_ssh_private_key: str,
|
|
64
|
-
volumes: List[Volume],
|
|
65
|
-
) -> JobProvisioningData:
|
|
66
|
-
instance_config = InstanceConfiguration(
|
|
67
|
-
project_name=run.project_name,
|
|
68
|
-
instance_name=get_job_instance_name(run, job),
|
|
69
|
-
ssh_keys=[SSHKey(public=project_ssh_public_key.strip())],
|
|
70
|
-
user=run.user,
|
|
71
|
-
)
|
|
72
|
-
return self.create_instance(instance_offer, instance_config)
|
|
73
|
-
|
|
74
60
|
def create_instance(
|
|
75
61
|
self, instance_offer: InstanceOfferWithAvailability, instance_config: InstanceConfiguration
|
|
76
62
|
) -> JobProvisioningData:
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from dstack._internal.core.backends.base.configurator import (
|
|
4
|
+
BackendRecord,
|
|
5
|
+
Configurator,
|
|
6
|
+
raise_invalid_credentials_error,
|
|
7
|
+
)
|
|
8
|
+
from dstack._internal.core.backends.models import (
|
|
9
|
+
VultrBackendConfigWithCreds,
|
|
10
|
+
)
|
|
11
|
+
from dstack._internal.core.backends.vultr import api_client
|
|
12
|
+
from dstack._internal.core.backends.vultr.backend import VultrBackend
|
|
13
|
+
from dstack._internal.core.backends.vultr.models import (
|
|
14
|
+
VultrBackendConfig,
|
|
15
|
+
VultrConfig,
|
|
16
|
+
VultrCreds,
|
|
17
|
+
VultrStoredConfig,
|
|
18
|
+
)
|
|
19
|
+
from dstack._internal.core.models.backends.base import (
|
|
20
|
+
BackendType,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
REGIONS = []
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class VultrConfigurator(Configurator):
|
|
27
|
+
TYPE = BackendType.VULTR
|
|
28
|
+
BACKEND_CLASS = VultrBackend
|
|
29
|
+
|
|
30
|
+
def validate_config(self, config: VultrBackendConfigWithCreds, default_creds_enabled: bool):
|
|
31
|
+
self._validate_vultr_api_key(config.creds.api_key)
|
|
32
|
+
|
|
33
|
+
def create_backend(
|
|
34
|
+
self, project_name: str, config: VultrBackendConfigWithCreds
|
|
35
|
+
) -> BackendRecord:
|
|
36
|
+
if config.regions is None:
|
|
37
|
+
config.regions = REGIONS
|
|
38
|
+
return BackendRecord(
|
|
39
|
+
config=VultrStoredConfig(
|
|
40
|
+
**VultrBackendConfig.__response__.parse_obj(config).dict()
|
|
41
|
+
).json(),
|
|
42
|
+
auth=VultrCreds.parse_obj(config.creds).json(),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def get_backend_config(self, record: BackendRecord, include_creds: bool) -> VultrBackendConfig:
|
|
46
|
+
config = self._get_config(record)
|
|
47
|
+
if include_creds:
|
|
48
|
+
return VultrBackendConfigWithCreds.__response__.parse_obj(config)
|
|
49
|
+
return VultrBackendConfig.__response__.parse_obj(config)
|
|
50
|
+
|
|
51
|
+
def get_backend(self, record: BackendRecord) -> VultrBackend:
|
|
52
|
+
config = self._get_config(record)
|
|
53
|
+
return VultrBackend(config=config)
|
|
54
|
+
|
|
55
|
+
def _get_config(self, record: BackendRecord) -> VultrConfig:
|
|
56
|
+
return VultrConfig.__response__(
|
|
57
|
+
**json.loads(record.config),
|
|
58
|
+
creds=VultrCreds.parse_raw(record.auth),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def _validate_vultr_api_key(self, api_key: str):
|
|
62
|
+
client = api_client.VultrApiClient(api_key=api_key)
|
|
63
|
+
if not client.validate_api_key():
|
|
64
|
+
raise_invalid_credentials_error(fields=[["creds", "api_key"]])
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import Annotated, List, Literal, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.models.common import CoreModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class VultrAPIKeyCreds(CoreModel):
|
|
9
|
+
type: Annotated[Literal["api_key"], Field(description="The type of credentials")] = "api_key"
|
|
10
|
+
api_key: Annotated[str, Field(description="The API key")]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
AnyVultrCreds = VultrAPIKeyCreds
|
|
14
|
+
VultrCreds = AnyVultrCreds
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class VultrBackendConfig(CoreModel):
|
|
18
|
+
type: Annotated[Literal["vultr"], Field(description="The type of backend")] = "vultr"
|
|
19
|
+
regions: Annotated[
|
|
20
|
+
Optional[List[str]],
|
|
21
|
+
Field(description="The list of Vultr regions. Omit to use all regions"),
|
|
22
|
+
] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class VultrBackendConfigWithCreds(VultrBackendConfig):
|
|
26
|
+
creds: Annotated[AnyVultrCreds, Field(description="The credentials")]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class VultrStoredConfig(VultrBackendConfig):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class VultrConfig(VultrStoredConfig):
|
|
34
|
+
creds: AnyVultrCreds
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
|
|
3
|
-
from dstack._internal.core.models.backends.aws import (
|
|
4
|
-
AWSConfigInfo,
|
|
5
|
-
AWSConfigInfoWithCreds,
|
|
6
|
-
AWSConfigInfoWithCredsPartial,
|
|
7
|
-
AWSConfigValues,
|
|
8
|
-
)
|
|
9
|
-
from dstack._internal.core.models.backends.azure import (
|
|
10
|
-
AzureConfigInfo,
|
|
11
|
-
AzureConfigInfoWithCreds,
|
|
12
|
-
AzureConfigInfoWithCredsPartial,
|
|
13
|
-
AzureConfigValues,
|
|
14
|
-
)
|
|
15
|
-
from dstack._internal.core.models.backends.cudo import (
|
|
16
|
-
CudoConfigInfo,
|
|
17
|
-
CudoConfigInfoWithCreds,
|
|
18
|
-
CudoConfigInfoWithCredsPartial,
|
|
19
|
-
CudoConfigValues,
|
|
20
|
-
)
|
|
21
|
-
from dstack._internal.core.models.backends.datacrunch import (
|
|
22
|
-
DataCrunchConfigInfo,
|
|
23
|
-
DataCrunchConfigInfoWithCreds,
|
|
24
|
-
DataCrunchConfigInfoWithCredsPartial,
|
|
25
|
-
DataCrunchConfigValues,
|
|
26
|
-
)
|
|
27
|
-
from dstack._internal.core.models.backends.dstack import (
|
|
28
|
-
DstackBaseBackendConfigInfo,
|
|
29
|
-
DstackConfigInfo,
|
|
30
|
-
DstackConfigValues,
|
|
31
|
-
)
|
|
32
|
-
from dstack._internal.core.models.backends.gcp import (
|
|
33
|
-
GCPConfigInfo,
|
|
34
|
-
GCPConfigInfoWithCreds,
|
|
35
|
-
GCPConfigInfoWithCredsPartial,
|
|
36
|
-
GCPConfigValues,
|
|
37
|
-
)
|
|
38
|
-
from dstack._internal.core.models.backends.kubernetes import (
|
|
39
|
-
KubernetesConfigInfo,
|
|
40
|
-
KubernetesConfigInfoWithCreds,
|
|
41
|
-
KubernetesConfigInfoWithCredsPartial,
|
|
42
|
-
KubernetesConfigValues,
|
|
43
|
-
)
|
|
44
|
-
from dstack._internal.core.models.backends.lambdalabs import (
|
|
45
|
-
LambdaConfigInfo,
|
|
46
|
-
LambdaConfigInfoWithCreds,
|
|
47
|
-
LambdaConfigInfoWithCredsPartial,
|
|
48
|
-
LambdaConfigValues,
|
|
49
|
-
)
|
|
50
|
-
from dstack._internal.core.models.backends.nebius import (
|
|
51
|
-
NebiusConfigInfo,
|
|
52
|
-
NebiusConfigInfoWithCreds,
|
|
53
|
-
NebiusConfigInfoWithCredsPartial,
|
|
54
|
-
NebiusConfigValues,
|
|
55
|
-
)
|
|
56
|
-
from dstack._internal.core.models.backends.oci import (
|
|
57
|
-
OCIConfigInfo,
|
|
58
|
-
OCIConfigInfoWithCreds,
|
|
59
|
-
OCIConfigInfoWithCredsPartial,
|
|
60
|
-
OCIConfigValues,
|
|
61
|
-
)
|
|
62
|
-
from dstack._internal.core.models.backends.runpod import (
|
|
63
|
-
RunpodConfigInfo,
|
|
64
|
-
RunpodConfigInfoWithCreds,
|
|
65
|
-
RunpodConfigInfoWithCredsPartial,
|
|
66
|
-
RunpodConfigValues,
|
|
67
|
-
)
|
|
68
|
-
from dstack._internal.core.models.backends.tensordock import (
|
|
69
|
-
TensorDockConfigInfo,
|
|
70
|
-
TensorDockConfigInfoWithCreds,
|
|
71
|
-
TensorDockConfigInfoWithCredsPartial,
|
|
72
|
-
TensorDockConfigValues,
|
|
73
|
-
)
|
|
74
|
-
from dstack._internal.core.models.backends.vastai import (
|
|
75
|
-
VastAIConfigInfo,
|
|
76
|
-
VastAIConfigInfoWithCreds,
|
|
77
|
-
VastAIConfigInfoWithCredsPartial,
|
|
78
|
-
VastAIConfigValues,
|
|
79
|
-
)
|
|
80
|
-
from dstack._internal.core.models.backends.vultr import (
|
|
81
|
-
VultrConfigInfo,
|
|
82
|
-
VultrConfigInfoWithCreds,
|
|
83
|
-
VultrConfigInfoWithCredsPartial,
|
|
84
|
-
VultrConfigValues,
|
|
85
|
-
)
|
|
86
|
-
from dstack._internal.core.models.common import CoreModel
|
|
87
|
-
|
|
88
|
-
# The following models are the basis of the JSON-based backend API.
|
|
89
|
-
# They are also the models used by the Configurator interface.
|
|
90
|
-
# The JSON-based backend API is replaced by the YAML-based backend API and not used.
|
|
91
|
-
# It's likely to be deprecated and removed.
|
|
92
|
-
# Some of the models below like those needed for interactive backend setup could be removed then.
|
|
93
|
-
# Still, others are going to stay as Configurator models to keep YAML-based configs and internal configs separated.
|
|
94
|
-
|
|
95
|
-
# Backend config returned by the API
|
|
96
|
-
AnyConfigInfoWithoutCreds = Union[
|
|
97
|
-
AWSConfigInfo,
|
|
98
|
-
AzureConfigInfo,
|
|
99
|
-
CudoConfigInfo,
|
|
100
|
-
DataCrunchConfigInfo,
|
|
101
|
-
GCPConfigInfo,
|
|
102
|
-
KubernetesConfigInfo,
|
|
103
|
-
LambdaConfigInfo,
|
|
104
|
-
NebiusConfigInfo,
|
|
105
|
-
OCIConfigInfo,
|
|
106
|
-
RunpodConfigInfo,
|
|
107
|
-
TensorDockConfigInfo,
|
|
108
|
-
VastAIConfigInfo,
|
|
109
|
-
VultrConfigInfo,
|
|
110
|
-
DstackConfigInfo,
|
|
111
|
-
DstackBaseBackendConfigInfo,
|
|
112
|
-
]
|
|
113
|
-
|
|
114
|
-
# Same as AnyConfigInfoWithoutCreds but also includes creds.
|
|
115
|
-
# Used to create/update backend.
|
|
116
|
-
# Also returned by the API to project admins so that they can see/update backend creds.
|
|
117
|
-
AnyConfigInfoWithCreds = Union[
|
|
118
|
-
AWSConfigInfoWithCreds,
|
|
119
|
-
AzureConfigInfoWithCreds,
|
|
120
|
-
CudoConfigInfoWithCreds,
|
|
121
|
-
DataCrunchConfigInfoWithCreds,
|
|
122
|
-
GCPConfigInfoWithCreds,
|
|
123
|
-
KubernetesConfigInfoWithCreds,
|
|
124
|
-
LambdaConfigInfoWithCreds,
|
|
125
|
-
NebiusConfigInfoWithCreds,
|
|
126
|
-
OCIConfigInfoWithCreds,
|
|
127
|
-
RunpodConfigInfoWithCreds,
|
|
128
|
-
TensorDockConfigInfoWithCreds,
|
|
129
|
-
VastAIConfigInfoWithCreds,
|
|
130
|
-
VultrConfigInfoWithCreds,
|
|
131
|
-
DstackConfigInfo,
|
|
132
|
-
]
|
|
133
|
-
|
|
134
|
-
AnyConfigInfo = Union[AnyConfigInfoWithoutCreds, AnyConfigInfoWithCreds]
|
|
135
|
-
|
|
136
|
-
# Same as AnyConfigInfoWithCreds but some fields may be optional.
|
|
137
|
-
# Used for interactive setup with validation and suggestions (e.g. via UI).
|
|
138
|
-
# If the backend does not need interactive setup, it's the same as AnyConfigInfoWithCreds.
|
|
139
|
-
AnyConfigInfoWithCredsPartial = Union[
|
|
140
|
-
AWSConfigInfoWithCredsPartial,
|
|
141
|
-
AzureConfigInfoWithCredsPartial,
|
|
142
|
-
CudoConfigInfoWithCredsPartial,
|
|
143
|
-
DataCrunchConfigInfoWithCredsPartial,
|
|
144
|
-
GCPConfigInfoWithCredsPartial,
|
|
145
|
-
KubernetesConfigInfoWithCredsPartial,
|
|
146
|
-
LambdaConfigInfoWithCredsPartial,
|
|
147
|
-
NebiusConfigInfoWithCredsPartial,
|
|
148
|
-
OCIConfigInfoWithCredsPartial,
|
|
149
|
-
RunpodConfigInfoWithCredsPartial,
|
|
150
|
-
TensorDockConfigInfoWithCredsPartial,
|
|
151
|
-
VastAIConfigInfoWithCredsPartial,
|
|
152
|
-
VultrConfigInfoWithCredsPartial,
|
|
153
|
-
DstackConfigInfo,
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
# Suggestions for unfilled fields used in interactive setup.
|
|
157
|
-
AnyConfigValues = Union[
|
|
158
|
-
AWSConfigValues,
|
|
159
|
-
AzureConfigValues,
|
|
160
|
-
CudoConfigValues,
|
|
161
|
-
DataCrunchConfigValues,
|
|
162
|
-
GCPConfigValues,
|
|
163
|
-
KubernetesConfigValues,
|
|
164
|
-
LambdaConfigValues,
|
|
165
|
-
NebiusConfigValues,
|
|
166
|
-
OCIConfigValues,
|
|
167
|
-
RunpodConfigValues,
|
|
168
|
-
TensorDockConfigValues,
|
|
169
|
-
VastAIConfigValues,
|
|
170
|
-
VultrConfigValues,
|
|
171
|
-
DstackConfigValues,
|
|
172
|
-
]
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# In case we'll support multiple backends of the same type,
|
|
176
|
-
# this adds backend name to backend config.
|
|
177
|
-
class BackendInfo(CoreModel):
|
|
178
|
-
name: str
|
|
179
|
-
config: AnyConfigInfoWithoutCreds
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
class BackendInfoYAML(CoreModel):
|
|
183
|
-
name: str
|
|
184
|
-
config_yaml: str
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import enum
|
|
2
|
-
from typing import List, Optional
|
|
3
|
-
|
|
4
|
-
from dstack._internal.core.models.common import CoreModel
|
|
5
2
|
|
|
6
3
|
|
|
7
4
|
class BackendType(str, enum.Enum):
|
|
@@ -32,24 +29,8 @@ class BackendType(str, enum.Enum):
|
|
|
32
29
|
LAMBDA = "lambda"
|
|
33
30
|
LOCAL = "local"
|
|
34
31
|
REMOTE = "remote" # TODO: replace for LOCAL
|
|
35
|
-
NEBIUS = "nebius"
|
|
36
32
|
OCI = "oci"
|
|
37
33
|
RUNPOD = "runpod"
|
|
38
34
|
TENSORDOCK = "tensordock"
|
|
39
35
|
VASTAI = "vastai"
|
|
40
36
|
VULTR = "vultr"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class ConfigElementValue(CoreModel):
|
|
44
|
-
value: str
|
|
45
|
-
label: str
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class ConfigElement(CoreModel):
|
|
49
|
-
selected: Optional[str] = None
|
|
50
|
-
values: List[ConfigElementValue] = []
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class ConfigMultiElement(CoreModel):
|
|
54
|
-
selected: List[str] = []
|
|
55
|
-
values: List[ConfigElementValue] = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import Any, List, Optional, Union
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import Field, ValidationError, conint, constr, root_validator, validator
|
|
6
6
|
from typing_extensions import Annotated, Literal
|
|
@@ -11,8 +11,6 @@ from dstack._internal.core.models.envs import Env
|
|
|
11
11
|
from dstack._internal.core.models.fleets import FleetConfiguration
|
|
12
12
|
from dstack._internal.core.models.gateways import GatewayConfiguration
|
|
13
13
|
from dstack._internal.core.models.profiles import ProfileParams, parse_off_duration
|
|
14
|
-
from dstack._internal.core.models.repos.base import Repo
|
|
15
|
-
from dstack._internal.core.models.repos.virtual import VirtualRepo
|
|
16
14
|
from dstack._internal.core.models.resources import Range, ResourcesSpec
|
|
17
15
|
from dstack._internal.core.models.services import AnyModel, OpenAIChatModel
|
|
18
16
|
from dstack._internal.core.models.unix import UnixUser
|
|
@@ -93,7 +91,9 @@ class BaseRunConfiguration(CoreModel):
|
|
|
93
91
|
Optional[str],
|
|
94
92
|
Field(description="The run name. If not specified, a random name is generated"),
|
|
95
93
|
] = None
|
|
96
|
-
image: Annotated[Optional[str], Field(description="The name of the Docker image to run")]
|
|
94
|
+
image: Annotated[Optional[str], Field(description="The name of the Docker image to run")] = (
|
|
95
|
+
None
|
|
96
|
+
)
|
|
97
97
|
user: Annotated[
|
|
98
98
|
Optional[str],
|
|
99
99
|
Field(
|
|
@@ -104,7 +104,7 @@ class BaseRunConfiguration(CoreModel):
|
|
|
104
104
|
),
|
|
105
105
|
] = None
|
|
106
106
|
privileged: Annotated[bool, Field(description="Run the container in privileged mode")] = False
|
|
107
|
-
entrypoint: Annotated[Optional[str], Field(description="The Docker entrypoint")]
|
|
107
|
+
entrypoint: Annotated[Optional[str], Field(description="The Docker entrypoint")] = None
|
|
108
108
|
working_dir: Annotated[
|
|
109
109
|
Optional[str],
|
|
110
110
|
Field(
|
|
@@ -119,17 +119,17 @@ class BaseRunConfiguration(CoreModel):
|
|
|
119
119
|
home_dir: str = "/root"
|
|
120
120
|
registry_auth: Annotated[
|
|
121
121
|
Optional[RegistryAuth], Field(description="Credentials for pulling a private Docker image")
|
|
122
|
-
]
|
|
122
|
+
] = None
|
|
123
123
|
python: Annotated[
|
|
124
124
|
Optional[PythonVersion],
|
|
125
125
|
Field(description="The major version of Python. Mutually exclusive with `image`"),
|
|
126
|
-
]
|
|
126
|
+
] = None
|
|
127
127
|
nvcc: Annotated[
|
|
128
128
|
Optional[bool],
|
|
129
129
|
Field(
|
|
130
130
|
description="Use image with NVIDIA CUDA Compiler (NVCC) included. Mutually exclusive with `image`"
|
|
131
131
|
),
|
|
132
|
-
]
|
|
132
|
+
] = None
|
|
133
133
|
single_branch: Annotated[
|
|
134
134
|
Optional[bool],
|
|
135
135
|
Field(
|
|
@@ -178,9 +178,6 @@ class BaseRunConfiguration(CoreModel):
|
|
|
178
178
|
UnixUser.parse(v)
|
|
179
179
|
return v
|
|
180
180
|
|
|
181
|
-
def get_repo(self) -> Repo:
|
|
182
|
-
return VirtualRepo()
|
|
183
|
-
|
|
184
181
|
|
|
185
182
|
class BaseRunConfigurationWithPorts(BaseRunConfiguration):
|
|
186
183
|
ports: Annotated[
|
|
@@ -208,8 +205,11 @@ class BaseRunConfigurationWithCommands(BaseRunConfiguration):
|
|
|
208
205
|
|
|
209
206
|
|
|
210
207
|
class DevEnvironmentConfigurationParams(CoreModel):
|
|
211
|
-
ide: Annotated[
|
|
212
|
-
|
|
208
|
+
ide: Annotated[
|
|
209
|
+
Union[Literal["vscode"], Literal["cursor"]],
|
|
210
|
+
Field(description="The IDE to run. Supported values include `vscode` and `cursor`"),
|
|
211
|
+
]
|
|
212
|
+
version: Annotated[Optional[str], Field(description="The version of the IDE")] = None
|
|
213
213
|
init: Annotated[CommandsList, Field(description="The bash commands to run on startup")] = []
|
|
214
214
|
inactivity_duration: Annotated[
|
|
215
215
|
Optional[Union[Literal["off"], int, bool, str]],
|
|
@@ -221,10 +221,11 @@ class DevEnvironmentConfigurationParams(CoreModel):
|
|
|
221
221
|
" Inactivity is defined as the absence of SSH connections to the"
|
|
222
222
|
" dev environment, including VS Code connections, `ssh <run name>`"
|
|
223
223
|
" shells, and attached `dstack apply` or `dstack attach` commands."
|
|
224
|
-
" Use `off` for unlimited duration.
|
|
224
|
+
" Use `off` for unlimited duration. Can be updated in-place."
|
|
225
|
+
" Defaults to `off`"
|
|
225
226
|
)
|
|
226
227
|
),
|
|
227
|
-
]
|
|
228
|
+
] = None
|
|
228
229
|
|
|
229
230
|
@validator("inactivity_duration", pre=True, allow_reuse=True)
|
|
230
231
|
def parse_inactivity_duration(
|
|
@@ -424,4 +425,9 @@ class DstackConfiguration(CoreModel):
|
|
|
424
425
|
]
|
|
425
426
|
|
|
426
427
|
class Config:
|
|
427
|
-
|
|
428
|
+
@staticmethod
|
|
429
|
+
def schema_extra(schema: Dict[str, Any]):
|
|
430
|
+
schema["$schema"] = "http://json-schema.org/draft-07/schema#"
|
|
431
|
+
# Allow additionalProperties so that vscode and others not supporting
|
|
432
|
+
# top-level oneOf do not warn about properties being invalid.
|
|
433
|
+
schema["additionalProperties"] = True
|
|
@@ -102,10 +102,11 @@ class Env(BaseModel):
|
|
|
102
102
|
def copy(self, **kwargs) -> Self:
|
|
103
103
|
# Env.copy() is tricky because it copies only the hidden top-level {"__root__": {...}}
|
|
104
104
|
# structure, not the actual nested dict representing the env itself.
|
|
105
|
-
#
|
|
105
|
+
# So we copy __root__ explicitly in case of a shallow copy.
|
|
106
|
+
new_copy = super().copy(**kwargs)
|
|
106
107
|
if not kwargs.get("deep", False):
|
|
107
|
-
|
|
108
|
-
return
|
|
108
|
+
new_copy.__root__ = new_copy.__root__.copy()
|
|
109
|
+
return new_copy
|
|
109
110
|
|
|
110
111
|
def as_dict(self) -> Dict[str, str]:
|
|
111
112
|
"""
|
|
@@ -10,18 +10,17 @@ from typing_extensions import Annotated, Literal
|
|
|
10
10
|
from dstack._internal.core.models.backends.base import BackendType
|
|
11
11
|
from dstack._internal.core.models.common import CoreModel
|
|
12
12
|
from dstack._internal.core.models.envs import Env
|
|
13
|
-
from dstack._internal.core.models.instances import InstanceOfferWithAvailability, SSHKey
|
|
14
|
-
from dstack._internal.core.models.pools import Instance
|
|
13
|
+
from dstack._internal.core.models.instances import Instance, InstanceOfferWithAvailability, SSHKey
|
|
15
14
|
from dstack._internal.core.models.profiles import (
|
|
16
15
|
Profile,
|
|
17
16
|
ProfileParams,
|
|
18
17
|
ProfileRetry,
|
|
19
18
|
SpotPolicy,
|
|
20
19
|
TerminationPolicy,
|
|
21
|
-
parse_duration,
|
|
22
20
|
parse_idle_duration,
|
|
23
21
|
)
|
|
24
22
|
from dstack._internal.core.models.resources import Range, ResourcesSpec
|
|
23
|
+
from dstack._internal.utils.json_schema import add_extra_schema_types
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
class FleetStatus(str, Enum):
|
|
@@ -218,30 +217,27 @@ class InstanceGroupParams(CoreModel):
|
|
|
218
217
|
Optional[float],
|
|
219
218
|
Field(description="The maximum instance price per hour, in dollars", gt=0.0),
|
|
220
219
|
] = None
|
|
221
|
-
|
|
222
220
|
idle_duration: Annotated[
|
|
223
221
|
Optional[Union[Literal["off"], str, int]],
|
|
224
222
|
Field(
|
|
225
223
|
description="Time to wait before terminating idle instances. Defaults to `5m` for runs and `3d` for fleets. Use `off` for unlimited duration"
|
|
226
224
|
),
|
|
227
225
|
] = None
|
|
228
|
-
# Deprecated:
|
|
229
|
-
termination_policy: Annotated[
|
|
230
|
-
Optional[TerminationPolicy],
|
|
231
|
-
Field(
|
|
232
|
-
description="Deprecated in favor of `idle_duration`",
|
|
233
|
-
),
|
|
234
|
-
] = None
|
|
235
|
-
termination_idle_time: Annotated[
|
|
236
|
-
Optional[Union[str, int]],
|
|
237
|
-
Field(
|
|
238
|
-
description="Deprecated in favor of `idle_duration`",
|
|
239
|
-
),
|
|
240
|
-
] = None
|
|
241
226
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
227
|
+
# Deprecated and unused. Left for compatibility with 0.18 clients.
|
|
228
|
+
termination_policy: Annotated[Optional[TerminationPolicy], Field(exclude=True)] = None
|
|
229
|
+
termination_idle_time: Annotated[Optional[Union[str, int]], Field(exclude=True)] = None
|
|
230
|
+
|
|
231
|
+
class Config:
|
|
232
|
+
@staticmethod
|
|
233
|
+
def schema_extra(schema: Dict[str, Any], model: Type):
|
|
234
|
+
del schema["properties"]["termination_policy"]
|
|
235
|
+
del schema["properties"]["termination_idle_time"]
|
|
236
|
+
add_extra_schema_types(
|
|
237
|
+
schema["properties"]["nodes"],
|
|
238
|
+
extra_types=[{"type": "integer"}, {"type": "string"}],
|
|
239
|
+
)
|
|
240
|
+
|
|
245
241
|
_validate_idle_duration = validator("idle_duration", pre=True, allow_reuse=True)(
|
|
246
242
|
parse_idle_duration
|
|
247
243
|
)
|
|
@@ -290,8 +286,7 @@ class FleetSpec(CoreModel):
|
|
|
290
286
|
|
|
291
287
|
|
|
292
288
|
class Fleet(CoreModel):
|
|
293
|
-
|
|
294
|
-
id: Optional[uuid.UUID] = None
|
|
289
|
+
id: uuid.UUID
|
|
295
290
|
name: str
|
|
296
291
|
project_name: str
|
|
297
292
|
spec: FleetSpec
|
|
@@ -76,12 +76,12 @@ class Gateway(CoreModel):
|
|
|
76
76
|
# The ip address of the gateway instance
|
|
77
77
|
ip_address: Optional[str]
|
|
78
78
|
instance_id: Optional[str]
|
|
79
|
+
wildcard_domain: Optional[str]
|
|
80
|
+
default: bool
|
|
79
81
|
# TODO: configuration fields are duplicated on top-level for backward compatibility with 0.18.x
|
|
80
|
-
# Remove
|
|
82
|
+
# Remove after 0.19
|
|
81
83
|
backend: BackendType
|
|
82
84
|
region: str
|
|
83
|
-
default: bool
|
|
84
|
-
wildcard_domain: Optional[str]
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
class GatewayPlan(CoreModel):
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
from enum import Enum
|
|
2
3
|
from typing import List, Optional
|
|
4
|
+
from uuid import UUID
|
|
3
5
|
|
|
4
6
|
import gpuhunt
|
|
5
7
|
from pydantic import root_validator
|
|
@@ -167,3 +169,25 @@ class InstanceStatus(str, Enum):
|
|
|
167
169
|
@classmethod
|
|
168
170
|
def finished_statuses(cls) -> List["InstanceStatus"]:
|
|
169
171
|
return [cls.TERMINATING, cls.TERMINATED]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class Instance(CoreModel):
|
|
175
|
+
id: UUID
|
|
176
|
+
project_name: str
|
|
177
|
+
backend: Optional[BackendType] = None
|
|
178
|
+
instance_type: Optional[InstanceType] = None
|
|
179
|
+
name: str
|
|
180
|
+
fleet_id: Optional[UUID] = None
|
|
181
|
+
fleet_name: Optional[str] = None
|
|
182
|
+
instance_num: int
|
|
183
|
+
job_name: Optional[str] = None # deprecated, always None (instance can have more than one job)
|
|
184
|
+
hostname: Optional[str] = None
|
|
185
|
+
status: InstanceStatus
|
|
186
|
+
unreachable: bool = False
|
|
187
|
+
termination_reason: Optional[str] = None
|
|
188
|
+
created: datetime.datetime
|
|
189
|
+
region: Optional[str] = None
|
|
190
|
+
availability_zone: Optional[str] = None
|
|
191
|
+
price: Optional[float] = None
|
|
192
|
+
total_blocks: Optional[int] = None
|
|
193
|
+
busy_blocks: int = 0
|