dstack 0.18.44__py3-none-any.whl → 0.19.0rc1__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.
- 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 -21
- dstack/_internal/cli/services/profile.py +34 -83
- dstack/_internal/cli/utils/gateway.py +1 -1
- 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 +20 -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 +13 -27
- 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 +13 -43
- 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 +7 -3
- 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 +20 -15
- 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 +41 -46
- 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 +17 -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 +0 -3
- 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 +4 -1
- dstack/_internal/server/background/tasks/process_prometheus_metrics.py +1 -1
- dstack/_internal/server/background/tasks/process_running_jobs.py +14 -5
- dstack/_internal/server/background/tasks/process_submitted_jobs.py +16 -37
- dstack/_internal/server/background/tasks/process_volumes.py +5 -2
- dstack/_internal/server/migrations/versions/7bc2586e8b9e_make_instancemodel_pool_id_optional.py +36 -0
- dstack/_internal/server/migrations/versions/bc8ca4a505c6_store_backendtype_as_string.py +171 -0
- dstack/_internal/server/models.py +48 -9
- dstack/_internal/server/routers/backends.py +14 -23
- dstack/_internal/server/routers/instances.py +3 -4
- dstack/_internal/server/routers/metrics.py +10 -8
- dstack/_internal/server/routers/prometheus.py +1 -1
- 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/services/backends/__init__.py +85 -158
- dstack/_internal/server/services/config.py +52 -576
- dstack/_internal/server/services/fleets.py +8 -103
- dstack/_internal/server/services/gateways/__init__.py +12 -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 +16 -0
- 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 +39 -13
- dstack/_internal/server/services/offers.py +1 -1
- dstack/_internal/server/services/projects.py +23 -14
- dstack/_internal/server/services/prometheus.py +176 -18
- dstack/_internal/server/services/runs.py +24 -16
- dstack/_internal/server/services/volumes.py +8 -4
- dstack/_internal/server/statics/index.html +1 -1
- dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js → main-4fd5a4770eff59325ee3.js} +7 -7
- dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js.map → main-4fd5a4770eff59325ee3.js.map} +1 -1
- dstack/_internal/server/testing/common.py +58 -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 +167 -83
- dstack/api/server/__init__.py +11 -13
- dstack/api/server/_backends.py +12 -16
- dstack/api/server/_fleets.py +15 -57
- dstack/api/server/_gateways.py +3 -14
- dstack/api/server/_repos.py +1 -4
- dstack/api/server/_runs.py +21 -100
- dstack/api/server/_volumes.py +10 -5
- dstack/version.py +1 -1
- {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/METADATA +1 -1
- {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/RECORD +218 -204
- 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 +0 -3
- tests/_internal/server/background/tasks/test_process_running_jobs.py +0 -21
- 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 +0 -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 +27 -0
- tests/_internal/server/routers/test_projects.py +56 -0
- tests/_internal/server/routers/test_prometheus.py +116 -27
- tests/_internal/server/routers/test_repos.py +0 -15
- tests/_internal/server/routers/test_runs.py +4 -219
- 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 +9 -5
- 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 -17
- 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 -42
- 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 -67
- 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.44.dist-info → dstack-0.19.0rc1.dist-info}/LICENSE.md +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/WHEEL +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/entry_points.txt +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from dstack._internal.core.backends.base import Backend
|
|
5
|
-
from dstack._internal.core.backends.runpod import RunpodBackend, RunpodConfig, api_client
|
|
6
|
-
from dstack._internal.core.models.backends.base import BackendType, ConfigMultiElement
|
|
7
|
-
from dstack._internal.core.models.backends.runpod import (
|
|
8
|
-
RunpodConfigInfo,
|
|
9
|
-
RunpodConfigInfoWithCreds,
|
|
10
|
-
RunpodConfigInfoWithCredsPartial,
|
|
11
|
-
RunpodConfigValues,
|
|
12
|
-
RunpodCreds,
|
|
13
|
-
RunpodStoredConfig,
|
|
14
|
-
)
|
|
15
|
-
from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
|
|
16
|
-
from dstack._internal.server.services.backends import Configurator
|
|
17
|
-
from dstack._internal.server.services.backends.configurators.base import (
|
|
18
|
-
raise_invalid_credentials_error,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class RunpodConfigurator(Configurator):
|
|
23
|
-
TYPE: BackendType = BackendType.RUNPOD
|
|
24
|
-
|
|
25
|
-
def get_config_values(self, config: RunpodConfigInfoWithCredsPartial) -> RunpodConfigValues:
|
|
26
|
-
config_values = RunpodConfigValues()
|
|
27
|
-
if config.creds is None:
|
|
28
|
-
return config_values
|
|
29
|
-
self._validate_runpod_api_key(config.creds.api_key)
|
|
30
|
-
config_values.regions = self._get_regions_element(selected=config.regions or [])
|
|
31
|
-
return config_values
|
|
32
|
-
|
|
33
|
-
def create_backend(
|
|
34
|
-
self, project: ProjectModel, config: RunpodConfigInfoWithCreds
|
|
35
|
-
) -> BackendModel:
|
|
36
|
-
return BackendModel(
|
|
37
|
-
project_id=project.id,
|
|
38
|
-
type=self.TYPE.value,
|
|
39
|
-
config=RunpodStoredConfig(
|
|
40
|
-
**RunpodConfigInfo.__response__.parse_obj(config).dict()
|
|
41
|
-
).json(),
|
|
42
|
-
auth=DecryptedString(plaintext=RunpodCreds.parse_obj(config.creds).json()),
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
def get_config_info(self, model: BackendModel, include_creds: bool) -> RunpodConfigInfo:
|
|
46
|
-
config = self._get_backend_config(model)
|
|
47
|
-
if include_creds:
|
|
48
|
-
return RunpodConfigInfoWithCreds.__response__.parse_obj(config)
|
|
49
|
-
return RunpodConfigInfo.__response__.parse_obj(config)
|
|
50
|
-
|
|
51
|
-
def get_backend(self, model: BackendModel) -> Backend:
|
|
52
|
-
config = self._get_backend_config(model)
|
|
53
|
-
return RunpodBackend(config=config)
|
|
54
|
-
|
|
55
|
-
def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
|
|
56
|
-
return ConfigMultiElement(selected=selected)
|
|
57
|
-
|
|
58
|
-
def _get_backend_config(self, model: BackendModel) -> RunpodConfig:
|
|
59
|
-
return RunpodConfig(
|
|
60
|
-
**json.loads(model.config),
|
|
61
|
-
creds=RunpodCreds.parse_raw(model.auth.get_plaintext_or_error()),
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
def _validate_runpod_api_key(self, api_key: str):
|
|
65
|
-
client = api_client.RunpodApiClient(api_key=api_key)
|
|
66
|
-
if not client.validate_api_key():
|
|
67
|
-
raise_invalid_credentials_error(fields=[["creds", "api_key"]])
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from dstack._internal.core.backends.tensordock import TensorDockBackend, api_client
|
|
5
|
-
from dstack._internal.core.backends.tensordock.config import TensorDockConfig
|
|
6
|
-
from dstack._internal.core.models.backends.base import (
|
|
7
|
-
BackendType,
|
|
8
|
-
ConfigElementValue,
|
|
9
|
-
ConfigMultiElement,
|
|
10
|
-
)
|
|
11
|
-
from dstack._internal.core.models.backends.tensordock import (
|
|
12
|
-
AnyTensorDockConfigInfo,
|
|
13
|
-
TensorDockConfigInfo,
|
|
14
|
-
TensorDockConfigInfoWithCreds,
|
|
15
|
-
TensorDockConfigInfoWithCredsPartial,
|
|
16
|
-
TensorDockConfigValues,
|
|
17
|
-
TensorDockCreds,
|
|
18
|
-
TensorDockStoredConfig,
|
|
19
|
-
)
|
|
20
|
-
from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
|
|
21
|
-
from dstack._internal.server.services.backends.configurators.base import (
|
|
22
|
-
Configurator,
|
|
23
|
-
raise_invalid_credentials_error,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
# TensorDock regions are dynamic, currently we don't offer any filtering
|
|
27
|
-
REGIONS = []
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class TensorDockConfigurator(Configurator):
|
|
31
|
-
TYPE: BackendType = BackendType.TENSORDOCK
|
|
32
|
-
|
|
33
|
-
def get_config_values(
|
|
34
|
-
self, config: TensorDockConfigInfoWithCredsPartial
|
|
35
|
-
) -> TensorDockConfigValues:
|
|
36
|
-
config_values = TensorDockConfigValues()
|
|
37
|
-
if config.creds is None:
|
|
38
|
-
return config_values
|
|
39
|
-
self._validate_tensordock_creds(config.creds.api_key, config.creds.api_token)
|
|
40
|
-
config_values.regions = self._get_regions_element(selected=config.regions or [])
|
|
41
|
-
return config_values
|
|
42
|
-
|
|
43
|
-
def create_backend(
|
|
44
|
-
self, project: ProjectModel, config: TensorDockConfigInfoWithCreds
|
|
45
|
-
) -> BackendModel:
|
|
46
|
-
if config.regions is None:
|
|
47
|
-
config.regions = REGIONS
|
|
48
|
-
return BackendModel(
|
|
49
|
-
project_id=project.id,
|
|
50
|
-
type=self.TYPE.value,
|
|
51
|
-
config=TensorDockStoredConfig(
|
|
52
|
-
**TensorDockConfigInfo.__response__.parse_obj(config).dict()
|
|
53
|
-
).json(),
|
|
54
|
-
auth=DecryptedString(plaintext=TensorDockCreds.parse_obj(config.creds).json()),
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyTensorDockConfigInfo:
|
|
58
|
-
config = self._get_backend_config(model)
|
|
59
|
-
if include_creds:
|
|
60
|
-
return TensorDockConfigInfoWithCreds.__response__.parse_obj(config)
|
|
61
|
-
return TensorDockConfigInfo.__response__.parse_obj(config)
|
|
62
|
-
|
|
63
|
-
def get_backend(self, model: BackendModel) -> TensorDockBackend:
|
|
64
|
-
config = self._get_backend_config(model)
|
|
65
|
-
return TensorDockBackend(config=config)
|
|
66
|
-
|
|
67
|
-
def _get_backend_config(self, model: BackendModel) -> TensorDockConfig:
|
|
68
|
-
return TensorDockConfig.__response__(
|
|
69
|
-
**json.loads(model.config),
|
|
70
|
-
creds=TensorDockCreds.parse_raw(model.auth.get_plaintext_or_error()),
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
def _validate_tensordock_creds(self, api_key: str, api_token: str):
|
|
74
|
-
client = api_client.TensorDockAPIClient(api_key=api_key, api_token=api_token)
|
|
75
|
-
if not client.auth_test():
|
|
76
|
-
raise_invalid_credentials_error(fields=[["creds", "api_key"], ["creds", "api_token"]])
|
|
77
|
-
|
|
78
|
-
def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
|
|
79
|
-
element = ConfigMultiElement(selected=selected)
|
|
80
|
-
for r in REGIONS:
|
|
81
|
-
element.values.append(ConfigElementValue(value=r, label=r))
|
|
82
|
-
return element
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from dstack._internal.core.backends.vastai import VastAIBackend, api_client
|
|
5
|
-
from dstack._internal.core.backends.vastai.config import VastAIConfig
|
|
6
|
-
from dstack._internal.core.models.backends.base import (
|
|
7
|
-
BackendType,
|
|
8
|
-
ConfigElementValue,
|
|
9
|
-
ConfigMultiElement,
|
|
10
|
-
)
|
|
11
|
-
from dstack._internal.core.models.backends.vastai import (
|
|
12
|
-
AnyVastAIConfigInfo,
|
|
13
|
-
VastAIConfigInfo,
|
|
14
|
-
VastAIConfigInfoWithCreds,
|
|
15
|
-
VastAIConfigInfoWithCredsPartial,
|
|
16
|
-
VastAIConfigValues,
|
|
17
|
-
VastAICreds,
|
|
18
|
-
VastAIStoredConfig,
|
|
19
|
-
)
|
|
20
|
-
from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
|
|
21
|
-
from dstack._internal.server.services.backends.configurators.base import (
|
|
22
|
-
Configurator,
|
|
23
|
-
raise_invalid_credentials_error,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
# VastAI regions are dynamic, currently we don't offer any filtering
|
|
27
|
-
REGIONS = []
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class VastAIConfigurator(Configurator):
|
|
31
|
-
TYPE: BackendType = BackendType.VASTAI
|
|
32
|
-
|
|
33
|
-
def get_config_values(self, config: VastAIConfigInfoWithCredsPartial) -> VastAIConfigValues:
|
|
34
|
-
config_values = VastAIConfigValues()
|
|
35
|
-
if config.creds is None:
|
|
36
|
-
return config_values
|
|
37
|
-
self._validate_vastai_creds(config.creds.api_key)
|
|
38
|
-
config_values.regions = self._get_regions_element(selected=config.regions or [])
|
|
39
|
-
return config_values
|
|
40
|
-
|
|
41
|
-
def create_backend(
|
|
42
|
-
self, project: ProjectModel, config: VastAIConfigInfoWithCreds
|
|
43
|
-
) -> BackendModel:
|
|
44
|
-
if config.regions is None:
|
|
45
|
-
config.regions = REGIONS
|
|
46
|
-
return BackendModel(
|
|
47
|
-
project_id=project.id,
|
|
48
|
-
type=self.TYPE.value,
|
|
49
|
-
config=VastAIStoredConfig(
|
|
50
|
-
**VastAIConfigInfo.__response__.parse_obj(config).dict()
|
|
51
|
-
).json(),
|
|
52
|
-
auth=DecryptedString(plaintext=VastAICreds.parse_obj(config.creds).json()),
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyVastAIConfigInfo:
|
|
56
|
-
config = self._get_backend_config(model)
|
|
57
|
-
if include_creds:
|
|
58
|
-
return VastAIConfigInfoWithCreds.__response__.parse_obj(config)
|
|
59
|
-
return VastAIConfigInfo.__response__.parse_obj(config)
|
|
60
|
-
|
|
61
|
-
def get_backend(self, model: BackendModel) -> VastAIBackend:
|
|
62
|
-
config = self._get_backend_config(model)
|
|
63
|
-
return VastAIBackend(config=config)
|
|
64
|
-
|
|
65
|
-
def _get_backend_config(self, model: BackendModel) -> VastAIConfig:
|
|
66
|
-
return VastAIConfig.__response__(
|
|
67
|
-
**json.loads(model.config),
|
|
68
|
-
creds=VastAICreds.parse_raw(model.auth.get_plaintext_or_error()),
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
def _validate_vastai_creds(self, api_key: str):
|
|
72
|
-
client = api_client.VastAIAPIClient(api_key=api_key)
|
|
73
|
-
if not client.auth_test():
|
|
74
|
-
raise_invalid_credentials_error(fields=[["creds", "api_key"]])
|
|
75
|
-
|
|
76
|
-
def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
|
|
77
|
-
element = ConfigMultiElement(selected=selected)
|
|
78
|
-
for r in REGIONS:
|
|
79
|
-
element.values.append(ConfigElementValue(value=r, label=r))
|
|
80
|
-
return element
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from dstack._internal.core.backends.base import Backend
|
|
5
|
-
from dstack._internal.core.backends.vultr import VultrBackend, VultrConfig, api_client
|
|
6
|
-
from dstack._internal.core.models.backends import (
|
|
7
|
-
VultrConfigInfoWithCreds,
|
|
8
|
-
VultrConfigInfoWithCredsPartial,
|
|
9
|
-
VultrConfigValues,
|
|
10
|
-
)
|
|
11
|
-
from dstack._internal.core.models.backends.base import (
|
|
12
|
-
BackendType,
|
|
13
|
-
ConfigElementValue,
|
|
14
|
-
ConfigMultiElement,
|
|
15
|
-
)
|
|
16
|
-
from dstack._internal.core.models.backends.vultr import (
|
|
17
|
-
VultrConfigInfo,
|
|
18
|
-
VultrCreds,
|
|
19
|
-
VultrStoredConfig,
|
|
20
|
-
)
|
|
21
|
-
from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
|
|
22
|
-
from dstack._internal.server.services.backends import Configurator
|
|
23
|
-
from dstack._internal.server.services.backends.configurators.base import (
|
|
24
|
-
raise_invalid_credentials_error,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
REGIONS = []
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class VultrConfigurator(Configurator):
|
|
31
|
-
TYPE: BackendType = BackendType.VULTR
|
|
32
|
-
|
|
33
|
-
def get_config_values(self, config: VultrConfigInfoWithCredsPartial) -> VultrConfigValues:
|
|
34
|
-
config_values = VultrConfigValues()
|
|
35
|
-
if config.creds is None:
|
|
36
|
-
return config_values
|
|
37
|
-
self._validate_vultr_api_key(config.creds.api_key)
|
|
38
|
-
config_values.regions = self._get_regions_element(selected=config.regions or [])
|
|
39
|
-
return config_values
|
|
40
|
-
|
|
41
|
-
def create_backend(
|
|
42
|
-
self, project: ProjectModel, config: VultrConfigInfoWithCreds
|
|
43
|
-
) -> BackendModel:
|
|
44
|
-
if config.regions is None:
|
|
45
|
-
config.regions = REGIONS
|
|
46
|
-
return BackendModel(
|
|
47
|
-
project_id=project.id,
|
|
48
|
-
type=self.TYPE.value,
|
|
49
|
-
config=VultrStoredConfig(
|
|
50
|
-
**VultrConfigInfo.__response__.parse_obj(config).dict()
|
|
51
|
-
).json(),
|
|
52
|
-
auth=DecryptedString(plaintext=VultrCreds.parse_obj(config.creds).json()),
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
def get_config_info(self, model: BackendModel, include_creds: bool) -> VultrConfigInfo:
|
|
56
|
-
config = self._get_backend_config(model)
|
|
57
|
-
if include_creds:
|
|
58
|
-
return VultrConfigInfoWithCreds.__response__.parse_obj(config)
|
|
59
|
-
return VultrConfigInfo.__response__.parse_obj(config)
|
|
60
|
-
|
|
61
|
-
def get_backend(self, model: BackendModel) -> Backend:
|
|
62
|
-
config = self._get_backend_config(model)
|
|
63
|
-
return VultrBackend(config=config)
|
|
64
|
-
|
|
65
|
-
def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
|
|
66
|
-
element = ConfigMultiElement(selected=selected)
|
|
67
|
-
for r in REGIONS:
|
|
68
|
-
element.values.append(ConfigElementValue(value=r, label=r))
|
|
69
|
-
return element
|
|
70
|
-
|
|
71
|
-
def _get_backend_config(self, model: BackendModel) -> VultrConfig:
|
|
72
|
-
return VultrConfig.__response__(
|
|
73
|
-
**json.loads(model.config),
|
|
74
|
-
creds=VultrCreds.parse_raw(model.auth.get_plaintext_or_error()),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
def _validate_vultr_api_key(self, api_key: str):
|
|
78
|
-
client = api_client.VultrApiClient(api_key=api_key)
|
|
79
|
-
if not client.validate_api_key():
|
|
80
|
-
raise_invalid_credentials_error(fields=[["creds", "api_key"]])
|
dstack/api/_public/pools.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
from dstack._internal.core.models.pools import Pool
|
|
4
|
-
from dstack.api.server import APIClient
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class PoolInstance:
|
|
8
|
-
def __init__(self, api_client: APIClient, pool: Pool):
|
|
9
|
-
self._api_client = api_client
|
|
10
|
-
self._pool = pool
|
|
11
|
-
|
|
12
|
-
@property
|
|
13
|
-
def name(self) -> str:
|
|
14
|
-
return self._pool.name
|
|
15
|
-
|
|
16
|
-
def __str__(self) -> str:
|
|
17
|
-
return f"<PoolInstance '{self.name}'>"
|
|
18
|
-
|
|
19
|
-
def __repr__(self) -> str:
|
|
20
|
-
return f"<PoolInstance '{self.name}'>"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class PoolCollection:
|
|
24
|
-
"""
|
|
25
|
-
Operations with pools
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
def __init__(self, api_client: APIClient, project: str):
|
|
29
|
-
self._api_client = api_client
|
|
30
|
-
self._project = project
|
|
31
|
-
|
|
32
|
-
def list(self) -> List[PoolInstance]:
|
|
33
|
-
"""
|
|
34
|
-
List available pool in the project
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
pools
|
|
38
|
-
"""
|
|
39
|
-
list_raw_pool = self._api_client.pool.list(project_name=self._project)
|
|
40
|
-
list_pool = [PoolInstance(self._api_client, instance) for instance in list_raw_pool]
|
|
41
|
-
return list_pool
|
dstack/api/_public/resources.py
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
from typing import List, Optional, Union
|
|
2
|
-
|
|
3
|
-
from dstack._internal.core.models.resources import (
|
|
4
|
-
DEFAULT_CPU_COUNT,
|
|
5
|
-
DEFAULT_GPU_COUNT,
|
|
6
|
-
DEFAULT_MEMORY_SIZE,
|
|
7
|
-
ComputeCapabilityLike,
|
|
8
|
-
DiskLike,
|
|
9
|
-
DiskSpec,
|
|
10
|
-
DiskSpecSchema,
|
|
11
|
-
GPULike,
|
|
12
|
-
GPUSpec,
|
|
13
|
-
GPUSpecSchema,
|
|
14
|
-
IntRangeLike,
|
|
15
|
-
MemoryLike,
|
|
16
|
-
MemoryRangeLike,
|
|
17
|
-
ResourcesSpec,
|
|
18
|
-
ResourcesSpecSchema,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# TODO(andrey): This method looks like a workaround and possibly must be reworked (replaced with something else).
|
|
23
|
-
# Currently it's only used by the `dstack pool add` command.
|
|
24
|
-
def Resources(
|
|
25
|
-
*,
|
|
26
|
-
cpu: IntRangeLike = DEFAULT_CPU_COUNT,
|
|
27
|
-
memory: MemoryRangeLike = DEFAULT_MEMORY_SIZE,
|
|
28
|
-
gpu: Optional[GPULike] = None,
|
|
29
|
-
shm_size: Optional[MemoryLike] = None,
|
|
30
|
-
disk: Optional[DiskLike] = None,
|
|
31
|
-
) -> ResourcesSpec:
|
|
32
|
-
"""
|
|
33
|
-
Creates required resources specification.
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
cpu (Optional[Range[int]]): The number of CPUs
|
|
37
|
-
memory (Optional[Range[Memory]]): The size of RAM memory (e.g., `"16GB"`)
|
|
38
|
-
gpu (Optional[GPUSpec]): The GPU spec
|
|
39
|
-
shm_size (Optional[Range[Memory]]): The of shared memory (e.g., `"8GB"`). If you are using parallel communicating processes (e.g., dataloaders in PyTorch), you may need to configure this.
|
|
40
|
-
disk (Optional[DiskSpec]): The disk spec
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
resources specification
|
|
44
|
-
"""
|
|
45
|
-
return ResourcesSpec.parse_obj(
|
|
46
|
-
ResourcesSpecSchema(
|
|
47
|
-
cpu=cpu,
|
|
48
|
-
memory=memory,
|
|
49
|
-
gpu=gpu,
|
|
50
|
-
shm_size=shm_size,
|
|
51
|
-
disk=disk,
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def GPU(
|
|
57
|
-
*,
|
|
58
|
-
name: Optional[Union[List[str], str]] = None,
|
|
59
|
-
count: IntRangeLike = DEFAULT_GPU_COUNT,
|
|
60
|
-
memory: Optional[MemoryRangeLike] = None,
|
|
61
|
-
total_memory: Optional[MemoryRangeLike] = None,
|
|
62
|
-
compute_capability: Optional[ComputeCapabilityLike] = None,
|
|
63
|
-
) -> GPUSpec:
|
|
64
|
-
"""
|
|
65
|
-
Creates GPU specification.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
name (Optional[List[str]]): The name of the GPU (e.g., `"A100"` or `"H100"`)
|
|
69
|
-
count (Optional[Range[int]]): The number of GPUs
|
|
70
|
-
memory (Optional[Range[Memory]]): The size of a single GPU memory (e.g., `"16GB"`)
|
|
71
|
-
total_memory (Optional[Range[Memory]]): The total size of all GPUs memory (e.g., `"32GB"`)
|
|
72
|
-
compute_capability (Optional[float]): The minimum compute capability of the GPU (e.g., `7.5`)
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
GPU specification
|
|
76
|
-
"""
|
|
77
|
-
return GPUSpec.parse_obj(
|
|
78
|
-
GPUSpecSchema(
|
|
79
|
-
name=name,
|
|
80
|
-
count=count,
|
|
81
|
-
memory=memory,
|
|
82
|
-
total_memory=total_memory,
|
|
83
|
-
compute_capability=compute_capability,
|
|
84
|
-
)
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def Disk(
|
|
89
|
-
*,
|
|
90
|
-
size: MemoryRangeLike,
|
|
91
|
-
) -> DiskSpec:
|
|
92
|
-
"""
|
|
93
|
-
Creates disk specification.
|
|
94
|
-
|
|
95
|
-
Args:
|
|
96
|
-
size (Range[Memory]): The size of the disk (e.g., `"100GB"`)
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
disk specification
|
|
100
|
-
"""
|
|
101
|
-
return DiskSpec.parse_obj(
|
|
102
|
-
DiskSpecSchema(
|
|
103
|
-
size=size,
|
|
104
|
-
)
|
|
105
|
-
)
|
dstack/api/server/_pools.py
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
2
|
-
|
|
3
|
-
from pydantic import parse_obj_as
|
|
4
|
-
|
|
5
|
-
import dstack._internal.server.schemas.pools as schemas_pools
|
|
6
|
-
from dstack._internal.core.models.instances import SSHKey
|
|
7
|
-
from dstack._internal.core.models.pools import Instance, Pool, PoolInstances
|
|
8
|
-
from dstack._internal.server.schemas.runs import AddRemoteInstanceRequest
|
|
9
|
-
from dstack.api.server._group import APIClientGroup
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class PoolAPIClient(APIClientGroup):
|
|
13
|
-
def list(self, project_name: str) -> List[Pool]:
|
|
14
|
-
resp = self._request(f"/api/project/{project_name}/pool/list")
|
|
15
|
-
return parse_obj_as(List[Pool.__response__], resp.json())
|
|
16
|
-
|
|
17
|
-
def delete(self, project_name: str, pool_name: str, force: bool) -> None:
|
|
18
|
-
body = schemas_pools.DeletePoolRequest(name=pool_name, force=force)
|
|
19
|
-
self._request(f"/api/project/{project_name}/pool/delete", body=body.json())
|
|
20
|
-
|
|
21
|
-
def create(self, project_name: str, pool_name: str) -> None:
|
|
22
|
-
body = schemas_pools.CreatePoolRequest(name=pool_name)
|
|
23
|
-
self._request(f"/api/project/{project_name}/pool/create", body=body.json())
|
|
24
|
-
|
|
25
|
-
def show(self, project_name: str, pool_name: Optional[str]) -> PoolInstances:
|
|
26
|
-
body = schemas_pools.ShowPoolRequest(name=pool_name)
|
|
27
|
-
resp = self._request(f"/api/project/{project_name}/pool/show", body=body.json())
|
|
28
|
-
return parse_obj_as(PoolInstances.__response__, resp.json())
|
|
29
|
-
|
|
30
|
-
def remove(self, project_name: str, pool_name: str, instance_name: str, force: bool) -> None:
|
|
31
|
-
body = schemas_pools.RemoveInstanceRequest(
|
|
32
|
-
pool_name=pool_name, instance_name=instance_name, force=force
|
|
33
|
-
)
|
|
34
|
-
self._request(f"/api/project/{project_name}/pool/remove", body=body.json())
|
|
35
|
-
|
|
36
|
-
def set_default(self, project_name: str, pool_name: str) -> None:
|
|
37
|
-
body = schemas_pools.SetDefaultPoolRequest(pool_name=pool_name)
|
|
38
|
-
self._request(f"/api/project/{project_name}/pool/set_default", body=body.json())
|
|
39
|
-
|
|
40
|
-
def add_remote(
|
|
41
|
-
self,
|
|
42
|
-
project_name: str,
|
|
43
|
-
pool_name: Optional[str],
|
|
44
|
-
instance_name: Optional[str],
|
|
45
|
-
instance_network: Optional[str],
|
|
46
|
-
region: Optional[str],
|
|
47
|
-
host: str,
|
|
48
|
-
port: int,
|
|
49
|
-
ssh_user: str,
|
|
50
|
-
ssh_keys: List[SSHKey],
|
|
51
|
-
) -> Instance:
|
|
52
|
-
body = AddRemoteInstanceRequest(
|
|
53
|
-
pool_name=pool_name,
|
|
54
|
-
instance_name=instance_name,
|
|
55
|
-
instance_network=instance_network,
|
|
56
|
-
region=region,
|
|
57
|
-
host=host,
|
|
58
|
-
port=port,
|
|
59
|
-
ssh_user=ssh_user,
|
|
60
|
-
ssh_keys=ssh_keys,
|
|
61
|
-
)
|
|
62
|
-
result = self._request(f"/api/project/{project_name}/pool/add_remote", body=body.json())
|
|
63
|
-
return parse_obj_as(Instance.__response__, result.json())
|