dstack 0.18.44__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 -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-4a0fe83e84574654e397.js} +18 -14
- dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js.map → main-4a0fe83e84574654e397.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.0.dist-info}/METADATA +1 -1
- {dstack-0.18.44.dist-info → dstack-0.19.0.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.0.dist-info}/LICENSE.md +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/WHEEL +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/entry_points.txt +0 -0
- {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/top_level.txt +0 -0
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Dict, List, Literal, Optional, Union
|
|
1
|
+
from typing import List, Optional
|
|
3
2
|
|
|
4
3
|
import yaml
|
|
5
|
-
from pydantic import
|
|
4
|
+
from pydantic import Field, ValidationError
|
|
6
5
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
7
6
|
from typing_extensions import Annotated
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
import dstack._internal.core.backends.configurators
|
|
9
|
+
from dstack._internal.core.backends.models import (
|
|
10
|
+
AnyBackendConfigWithCreds,
|
|
11
|
+
AnyBackendFileConfigWithCreds,
|
|
12
|
+
BackendInfoYAML,
|
|
13
|
+
)
|
|
10
14
|
from dstack._internal.core.errors import (
|
|
11
15
|
BackendNotAvailable,
|
|
12
16
|
ResourceNotExistsError,
|
|
13
17
|
ServerClientError,
|
|
14
18
|
)
|
|
15
|
-
from dstack._internal.core.models.backends import AnyConfigInfoWithCreds, BackendInfoYAML
|
|
16
|
-
from dstack._internal.core.models.backends.aws import AnyAWSCreds, AWSOSImageConfig
|
|
17
|
-
from dstack._internal.core.models.backends.azure import AnyAzureCreds
|
|
18
19
|
from dstack._internal.core.models.backends.base import BackendType
|
|
19
|
-
from dstack._internal.core.models.backends.cudo import AnyCudoCreds
|
|
20
|
-
from dstack._internal.core.models.backends.datacrunch import AnyDataCrunchCreds
|
|
21
|
-
from dstack._internal.core.models.backends.kubernetes import KubernetesNetworkingConfig
|
|
22
|
-
from dstack._internal.core.models.backends.lambdalabs import AnyLambdaCreds
|
|
23
|
-
from dstack._internal.core.models.backends.oci import AnyOCICreds
|
|
24
|
-
from dstack._internal.core.models.backends.runpod import AnyRunpodCreds
|
|
25
|
-
from dstack._internal.core.models.backends.tensordock import AnyTensorDockCreds
|
|
26
|
-
from dstack._internal.core.models.backends.vastai import AnyVastAICreds
|
|
27
|
-
from dstack._internal.core.models.backends.vultr import AnyVultrCreds
|
|
28
20
|
from dstack._internal.core.models.common import CoreModel
|
|
29
21
|
from dstack._internal.server import settings
|
|
30
22
|
from dstack._internal.server.models import ProjectModel, UserModel
|
|
@@ -37,7 +29,6 @@ from dstack._internal.server.services.permissions import (
|
|
|
37
29
|
DefaultPermissions,
|
|
38
30
|
set_default_permissions,
|
|
39
31
|
)
|
|
40
|
-
from dstack._internal.utils.common import run_async
|
|
41
32
|
from dstack._internal.utils.logging import get_logger
|
|
42
33
|
|
|
43
34
|
logger = get_logger(__name__)
|
|
@@ -58,473 +49,15 @@ def seq_representer(dumper, sequence):
|
|
|
58
49
|
yaml.add_representer(list, seq_representer)
|
|
59
50
|
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# credentials by looking for a file, while YAML-based API doesn't do this.
|
|
64
|
-
# So for some backends there are two sets of config models.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class AWSConfig(CoreModel):
|
|
68
|
-
type: Annotated[Literal["aws"], Field(description="The type of the backend")] = "aws"
|
|
69
|
-
regions: Annotated[
|
|
70
|
-
Optional[List[str]], Field(description="The list of AWS regions. Omit to use all regions")
|
|
71
|
-
] = None
|
|
72
|
-
vpc_name: Annotated[
|
|
73
|
-
Optional[str],
|
|
74
|
-
Field(
|
|
75
|
-
description=(
|
|
76
|
-
"The name of custom VPCs. All configured regions must have a VPC with this name."
|
|
77
|
-
" If your custom VPCs don't have names or have different names in different regions, use `vpc_ids` instead."
|
|
78
|
-
)
|
|
79
|
-
),
|
|
80
|
-
] = None
|
|
81
|
-
vpc_ids: Annotated[
|
|
82
|
-
Optional[Dict[str, str]],
|
|
83
|
-
Field(
|
|
84
|
-
description=(
|
|
85
|
-
"The mapping from AWS regions to VPC IDs."
|
|
86
|
-
" If `default_vpcs: true`, omitted regions will use default VPCs"
|
|
87
|
-
)
|
|
88
|
-
),
|
|
89
|
-
] = None
|
|
90
|
-
default_vpcs: Annotated[
|
|
91
|
-
Optional[bool],
|
|
92
|
-
Field(
|
|
93
|
-
description=(
|
|
94
|
-
"A flag to enable/disable using default VPCs in regions not configured by `vpc_ids`."
|
|
95
|
-
" Set to `false` if default VPCs should never be used."
|
|
96
|
-
" Defaults to `true`"
|
|
97
|
-
)
|
|
98
|
-
),
|
|
99
|
-
] = None
|
|
100
|
-
public_ips: Annotated[
|
|
101
|
-
Optional[bool],
|
|
102
|
-
Field(
|
|
103
|
-
description=(
|
|
104
|
-
"A flag to enable/disable public IP assigning on instances."
|
|
105
|
-
" `public_ips: false` requires at least one private subnet with outbound internet connectivity"
|
|
106
|
-
" provided by a NAT Gateway or a Transit Gateway."
|
|
107
|
-
" Defaults to `true`"
|
|
108
|
-
)
|
|
109
|
-
),
|
|
110
|
-
] = None
|
|
111
|
-
iam_instance_profile: Annotated[
|
|
112
|
-
Optional[str],
|
|
113
|
-
Field(
|
|
114
|
-
description=(
|
|
115
|
-
"The name of the IAM instance profile to associate with EC2 instances."
|
|
116
|
-
" You can also specify the IAM role name for roles created via the AWS console."
|
|
117
|
-
" AWS automatically creates an instance profile and gives it the same name as the role"
|
|
118
|
-
)
|
|
119
|
-
),
|
|
120
|
-
] = None
|
|
121
|
-
tags: Annotated[
|
|
122
|
-
Optional[Dict[str, str]],
|
|
123
|
-
Field(description="The tags that will be assigned to resources created by `dstack`"),
|
|
124
|
-
] = None
|
|
125
|
-
os_images: Annotated[
|
|
126
|
-
Optional[AWSOSImageConfig],
|
|
127
|
-
Field(
|
|
128
|
-
description="The mapping of instance categories (CPU, NVIDIA GPU) to AMI configurations"
|
|
129
|
-
),
|
|
130
|
-
] = None
|
|
131
|
-
creds: AnyAWSCreds = Field(..., description="The credentials", discriminator="type")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class AzureConfig(CoreModel):
|
|
135
|
-
type: Annotated[Literal["azure"], Field(description="The type of the backend")] = "azure"
|
|
136
|
-
tenant_id: Annotated[str, Field(description="The tenant ID")]
|
|
137
|
-
subscription_id: Annotated[str, Field(description="The subscription ID")]
|
|
138
|
-
resource_group: Annotated[
|
|
139
|
-
Optional[str],
|
|
140
|
-
Field(
|
|
141
|
-
description=(
|
|
142
|
-
"The resource group for resources created by `dstack`."
|
|
143
|
-
" If not specified, `dstack` will create a new resource group"
|
|
144
|
-
)
|
|
145
|
-
),
|
|
146
|
-
] = None
|
|
147
|
-
regions: Annotated[
|
|
148
|
-
Optional[List[str]],
|
|
149
|
-
Field(description="The list of Azure regions (locations). Omit to use all regions"),
|
|
150
|
-
] = None
|
|
151
|
-
vpc_ids: Annotated[
|
|
152
|
-
Optional[Dict[str, str]],
|
|
153
|
-
Field(
|
|
154
|
-
description=(
|
|
155
|
-
"The mapping from configured Azure locations to network IDs."
|
|
156
|
-
" A network ID must have a format `networkResourceGroup/networkName`"
|
|
157
|
-
" If not specified, `dstack` will create a new network for every configured region"
|
|
158
|
-
)
|
|
159
|
-
),
|
|
160
|
-
] = None
|
|
161
|
-
public_ips: Annotated[
|
|
162
|
-
Optional[bool],
|
|
163
|
-
Field(
|
|
164
|
-
description=(
|
|
165
|
-
"A flag to enable/disable public IP assigning on instances."
|
|
166
|
-
" `public_ips: false` requires `vpc_ids` that specifies custom networks with outbound internet connectivity"
|
|
167
|
-
" provided by NAT Gateway or other mechanism."
|
|
168
|
-
" Defaults to `true`"
|
|
169
|
-
)
|
|
170
|
-
),
|
|
171
|
-
] = None
|
|
172
|
-
tags: Annotated[
|
|
173
|
-
Optional[Dict[str, str]],
|
|
174
|
-
Field(description="The tags that will be assigned to resources created by `dstack`"),
|
|
175
|
-
] = None
|
|
176
|
-
creds: AnyAzureCreds = Field(..., description="The credentials", discriminator="type")
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
class CudoConfig(CoreModel):
|
|
180
|
-
type: Annotated[Literal["cudo"], Field(description="The type of backend")] = "cudo"
|
|
181
|
-
regions: Annotated[
|
|
182
|
-
Optional[List[str]], Field(description="The list of Cudo regions. Omit to use all regions")
|
|
183
|
-
] = None
|
|
184
|
-
project_id: Annotated[str, Field(description="The project ID")]
|
|
185
|
-
creds: Annotated[AnyCudoCreds, Field(description="The credentials")]
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
class DataCrunchConfig(CoreModel):
|
|
189
|
-
type: Annotated[Literal["datacrunch"], Field(description="The type of backend")] = "datacrunch"
|
|
190
|
-
regions: Annotated[
|
|
191
|
-
Optional[List[str]],
|
|
192
|
-
Field(description="The list of DataCrunch regions. Omit to use all regions"),
|
|
193
|
-
] = None
|
|
194
|
-
creds: Annotated[AnyDataCrunchCreds, Field(description="The credentials")]
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class GCPServiceAccountCreds(CoreModel):
|
|
198
|
-
type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
|
|
199
|
-
"service_account"
|
|
200
|
-
)
|
|
201
|
-
filename: Annotated[str, Field(description="The path to the service account file")]
|
|
202
|
-
data: Annotated[
|
|
203
|
-
Optional[str],
|
|
204
|
-
Field(
|
|
205
|
-
description=(
|
|
206
|
-
"The contents of the service account file."
|
|
207
|
-
" When configuring via `server/config.yml`, it's automatically filled from `filename`."
|
|
208
|
-
" When configuring via UI, it has to be specified explicitly"
|
|
209
|
-
)
|
|
210
|
-
),
|
|
211
|
-
] = None
|
|
212
|
-
|
|
213
|
-
@root_validator
|
|
214
|
-
def fill_data(cls, values):
|
|
215
|
-
return _fill_data(values)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
class GCPServiceAccountAPICreds(CoreModel):
|
|
219
|
-
type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
|
|
220
|
-
"service_account"
|
|
221
|
-
)
|
|
222
|
-
filename: Annotated[
|
|
223
|
-
Optional[str], Field(description="The path to the service account file")
|
|
224
|
-
] = ""
|
|
225
|
-
data: Annotated[str, Field(description="The contents of the service account file")]
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
class GCPDefaultCreds(CoreModel):
|
|
229
|
-
type: Annotated[Literal["default"], Field(description="The type of credentials")] = "default"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
AnyGCPCreds = Union[GCPServiceAccountCreds, GCPDefaultCreds]
|
|
233
|
-
AnyGCPAPICreds = Union[GCPServiceAccountAPICreds, GCPDefaultCreds]
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
class GCPConfig(CoreModel):
|
|
237
|
-
type: Annotated[Literal["gcp"], Field(description="The type of backend")] = "gcp"
|
|
238
|
-
project_id: Annotated[str, Field(description="The project ID")]
|
|
239
|
-
regions: Annotated[
|
|
240
|
-
Optional[List[str]], Field(description="The list of GCP regions. Omit to use all regions")
|
|
241
|
-
] = None
|
|
242
|
-
vpc_name: Annotated[Optional[str], Field(description="The name of a custom VPC")] = None
|
|
243
|
-
vpc_project_id: Annotated[
|
|
244
|
-
Optional[str],
|
|
245
|
-
Field(description="The shared VPC hosted project ID. Required for shared VPC only"),
|
|
246
|
-
] = None
|
|
247
|
-
public_ips: Annotated[
|
|
248
|
-
Optional[bool],
|
|
249
|
-
Field(
|
|
250
|
-
description="A flag to enable/disable public IP assigning on instances. Defaults to `true`"
|
|
251
|
-
),
|
|
252
|
-
] = None
|
|
253
|
-
nat_check: Annotated[
|
|
254
|
-
Optional[bool],
|
|
255
|
-
Field(
|
|
256
|
-
description=(
|
|
257
|
-
"A flag to enable/disable a check that Cloud NAT is configured for the VPC."
|
|
258
|
-
" This should be set to `false` when `public_ips: false` and outbound internet connectivity"
|
|
259
|
-
" is provided by a mechanism other than Cloud NAT such as a third-party NAT appliance."
|
|
260
|
-
" Defaults to `true`"
|
|
261
|
-
)
|
|
262
|
-
),
|
|
263
|
-
] = None
|
|
264
|
-
vm_service_account: Annotated[
|
|
265
|
-
Optional[str], Field(description="The service account to associate with provisioned VMs")
|
|
266
|
-
] = None
|
|
267
|
-
tags: Annotated[
|
|
268
|
-
Optional[Dict[str, str]],
|
|
269
|
-
Field(
|
|
270
|
-
description="The tags (labels) that will be assigned to resources created by `dstack`"
|
|
271
|
-
),
|
|
272
|
-
] = None
|
|
273
|
-
creds: AnyGCPCreds = Field(..., description="The credentials", discriminator="type")
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
class GCPAPIConfig(CoreModel):
|
|
277
|
-
type: Annotated[Literal["gcp"], Field(description="The type of backend")] = "gcp"
|
|
278
|
-
project_id: Annotated[str, Field(description="The project ID")]
|
|
279
|
-
regions: Annotated[
|
|
280
|
-
Optional[List[str]], Field(description="The list of GCP regions. Omit to use all regions")
|
|
281
|
-
] = None
|
|
282
|
-
vpc_name: Annotated[Optional[str], Field(description="The name of a custom VPC")] = None
|
|
283
|
-
vpc_project_id: Annotated[
|
|
284
|
-
Optional[str],
|
|
285
|
-
Field(description="The shared VPC hosted project ID. Required for shared VPC only"),
|
|
286
|
-
] = None
|
|
287
|
-
public_ips: Annotated[
|
|
288
|
-
Optional[bool],
|
|
289
|
-
Field(
|
|
290
|
-
description="A flag to enable/disable public IP assigning on instances. Defaults to `true`"
|
|
291
|
-
),
|
|
292
|
-
] = None
|
|
293
|
-
nat_check: Annotated[
|
|
294
|
-
Optional[bool],
|
|
295
|
-
Field(
|
|
296
|
-
description=(
|
|
297
|
-
"A flag to enable/disable a check that Cloud NAT is configured for the VPC."
|
|
298
|
-
" This should be set to `false` when `public_ips: false` and outbound internet connectivity"
|
|
299
|
-
" is provided by a mechanism other than Cloud NAT such as a third-party NAT appliance."
|
|
300
|
-
" Defaults to `true`"
|
|
301
|
-
)
|
|
302
|
-
),
|
|
303
|
-
] = None
|
|
304
|
-
vm_service_account: Annotated[
|
|
305
|
-
Optional[str], Field(description="The service account associated with provisioned VMs")
|
|
306
|
-
] = None
|
|
307
|
-
tags: Annotated[
|
|
308
|
-
Optional[Dict[str, str]],
|
|
309
|
-
Field(
|
|
310
|
-
description="The tags (labels) that will be assigned to resources created by `dstack`"
|
|
311
|
-
),
|
|
312
|
-
] = None
|
|
313
|
-
creds: AnyGCPAPICreds = Field(..., description="The credentials", discriminator="type")
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
class KubeconfigConfig(CoreModel):
|
|
317
|
-
filename: Annotated[str, Field(description="The path to the kubeconfig file")]
|
|
318
|
-
data: Annotated[
|
|
319
|
-
Optional[str],
|
|
320
|
-
Field(
|
|
321
|
-
description=(
|
|
322
|
-
"The contents of the kubeconfig file."
|
|
323
|
-
" When configuring via `server/config.yml`, it's automatically filled from `filename`."
|
|
324
|
-
" When configuring via UI, it has to be specified explicitly"
|
|
325
|
-
)
|
|
326
|
-
),
|
|
327
|
-
] = None
|
|
328
|
-
|
|
329
|
-
@root_validator
|
|
330
|
-
def fill_data(cls, values):
|
|
331
|
-
return _fill_data(values)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
class KubeconfigAPIConfig(CoreModel):
|
|
335
|
-
filename: Annotated[str, Field(description="The path to the kubeconfig file")] = ""
|
|
336
|
-
data: Annotated[str, Field(description="The contents of the kubeconfig file")]
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
class KubernetesConfig(CoreModel):
|
|
340
|
-
type: Annotated[Literal["kubernetes"], Field(description="The type of backend")] = "kubernetes"
|
|
341
|
-
kubeconfig: Annotated[KubeconfigConfig, Field(description="The kubeconfig configuration")]
|
|
342
|
-
networking: Annotated[
|
|
343
|
-
Optional[KubernetesNetworkingConfig], Field(description="The networking configuration")
|
|
344
|
-
] = None
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
class KubernetesAPIConfig(CoreModel):
|
|
348
|
-
type: Annotated[Literal["kubernetes"], Field(description="The type of backend")] = "kubernetes"
|
|
349
|
-
kubeconfig: Annotated[KubeconfigAPIConfig, Field(description="The kubeconfig configuration")]
|
|
350
|
-
networking: Annotated[
|
|
351
|
-
Optional[KubernetesNetworkingConfig], Field(description="The networking configuration")
|
|
352
|
-
] = None
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
class LambdaConfig(CoreModel):
|
|
356
|
-
type: Annotated[Literal["lambda"], Field(description="The type of backend")] = "lambda"
|
|
357
|
-
regions: Annotated[
|
|
358
|
-
Optional[List[str]],
|
|
359
|
-
Field(description="The list of Lambda regions. Omit to use all regions"),
|
|
360
|
-
] = None
|
|
361
|
-
creds: Annotated[AnyLambdaCreds, Field(description="The credentials")]
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
class NebiusServiceAccountCreds(CoreModel):
|
|
365
|
-
type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
|
|
366
|
-
"service_account"
|
|
367
|
-
)
|
|
368
|
-
filename: Annotated[str, Field(description="The path to the service account file")]
|
|
369
|
-
data: Annotated[
|
|
370
|
-
Optional[str], Field(description="The contents of the service account file")
|
|
371
|
-
] = None
|
|
372
|
-
|
|
373
|
-
@root_validator
|
|
374
|
-
def fill_data(cls, values):
|
|
375
|
-
return _fill_data(values)
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
class NebiusServiceAccountAPICreds(CoreModel):
|
|
379
|
-
type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
|
|
380
|
-
"service_account"
|
|
381
|
-
)
|
|
382
|
-
filename: Annotated[str, Field(description="The path to the service account file")]
|
|
383
|
-
data: Annotated[str, Field(description="The contents of the service account file")]
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
AnyNebiusCreds = NebiusServiceAccountCreds
|
|
387
|
-
AnyNebiusAPICreds = NebiusServiceAccountAPICreds
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
class NebiusConfig(CoreModel):
|
|
391
|
-
type: Literal["nebius"] = "nebius"
|
|
392
|
-
cloud_id: str
|
|
393
|
-
folder_id: str
|
|
394
|
-
network_id: str
|
|
395
|
-
regions: Optional[List[str]] = None
|
|
396
|
-
creds: AnyNebiusCreds
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
class NebiusAPIConfig(CoreModel):
|
|
400
|
-
type: Literal["nebius"] = "nebius"
|
|
401
|
-
cloud_id: str
|
|
402
|
-
folder_id: str
|
|
403
|
-
network_id: str
|
|
404
|
-
regions: Optional[List[str]] = None
|
|
405
|
-
creds: AnyNebiusAPICreds
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
class OCIConfig(CoreModel):
|
|
409
|
-
type: Annotated[Literal["oci"], Field(description="The type of backend")] = "oci"
|
|
410
|
-
creds: Annotated[AnyOCICreds, Field(description="The credentials", discriminator="type")]
|
|
411
|
-
regions: Annotated[
|
|
412
|
-
Optional[List[str]],
|
|
413
|
-
Field(description="The list of OCI regions. Omit to use all regions"),
|
|
414
|
-
] = None
|
|
415
|
-
compartment_id: Annotated[
|
|
416
|
-
Optional[str],
|
|
417
|
-
Field(
|
|
418
|
-
description=(
|
|
419
|
-
"Compartment where `dstack` will create all resources."
|
|
420
|
-
" Omit to instruct `dstack` to create a new compartment"
|
|
421
|
-
)
|
|
422
|
-
),
|
|
423
|
-
] = None
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
class RunpodConfig(CoreModel):
|
|
427
|
-
type: Literal["runpod"] = "runpod"
|
|
428
|
-
regions: Annotated[
|
|
429
|
-
Optional[List[str]],
|
|
430
|
-
Field(description="The list of RunPod regions. Omit to use all regions"),
|
|
431
|
-
] = None
|
|
432
|
-
community_cloud: Annotated[
|
|
433
|
-
Optional[bool],
|
|
434
|
-
Field(
|
|
435
|
-
description=(
|
|
436
|
-
"Whether Community Cloud offers can be suggested in addition to Secure Cloud."
|
|
437
|
-
f" Defaults to `{str(RUNPOD_COMMUNITY_CLOUD_DEFAULT).lower()}`"
|
|
438
|
-
)
|
|
439
|
-
),
|
|
440
|
-
] = None
|
|
441
|
-
creds: Annotated[AnyRunpodCreds, Field(description="The credentials")]
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
class TensorDockConfig(CoreModel):
|
|
445
|
-
type: Annotated[Literal["tensordock"], Field(description="The type of backend")] = "tensordock"
|
|
446
|
-
regions: Annotated[
|
|
447
|
-
Optional[List[str]],
|
|
448
|
-
Field(description="The list of TensorDock regions. Omit to use all regions"),
|
|
449
|
-
] = None
|
|
450
|
-
creds: Annotated[AnyTensorDockCreds, Field(description="The credentials")]
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
class VastAIConfig(CoreModel):
|
|
454
|
-
type: Annotated[Literal["vastai"], Field(description="The type of backend")] = "vastai"
|
|
455
|
-
regions: Annotated[
|
|
456
|
-
Optional[List[str]],
|
|
457
|
-
Field(description="The list of VastAI regions. Omit to use all regions"),
|
|
458
|
-
] = None
|
|
459
|
-
creds: Annotated[AnyVastAICreds, Field(description="The credentials")]
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
class VultrConfig(CoreModel):
|
|
463
|
-
type: Annotated[Literal["vultr"], Field(description="The type of backend")] = "vultr"
|
|
464
|
-
regions: Annotated[
|
|
465
|
-
Optional[List[str]],
|
|
466
|
-
Field(description="The list of Vultr regions. Omit to use all regions"),
|
|
467
|
-
] = None
|
|
468
|
-
creds: Annotated[AnyVultrCreds, Field(description="The credentials")]
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
class DstackConfig(CoreModel):
|
|
472
|
-
type: Annotated[Literal["dstack"], Field(description="The type of backend")] = "dstack"
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
AnyBackendConfig = Union[
|
|
476
|
-
AWSConfig,
|
|
477
|
-
AzureConfig,
|
|
478
|
-
CudoConfig,
|
|
479
|
-
DataCrunchConfig,
|
|
480
|
-
GCPConfig,
|
|
481
|
-
KubernetesConfig,
|
|
482
|
-
LambdaConfig,
|
|
483
|
-
NebiusConfig,
|
|
484
|
-
OCIConfig,
|
|
485
|
-
RunpodConfig,
|
|
486
|
-
TensorDockConfig,
|
|
487
|
-
VastAIConfig,
|
|
488
|
-
VultrConfig,
|
|
489
|
-
DstackConfig,
|
|
52
|
+
BackendFileConfigWithCreds = Annotated[
|
|
53
|
+
AnyBackendFileConfigWithCreds, Field(..., discriminator="type")
|
|
490
54
|
]
|
|
491
55
|
|
|
492
|
-
BackendConfig = Annotated[AnyBackendConfig, Field(..., discriminator="type")]
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
class _BackendConfig(BaseModel):
|
|
496
|
-
__root__: BackendConfig
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
AnyBackendAPIConfig = Union[
|
|
500
|
-
AWSConfig,
|
|
501
|
-
AzureConfig,
|
|
502
|
-
CudoConfig,
|
|
503
|
-
DataCrunchConfig,
|
|
504
|
-
GCPAPIConfig,
|
|
505
|
-
KubernetesAPIConfig,
|
|
506
|
-
LambdaConfig,
|
|
507
|
-
NebiusAPIConfig,
|
|
508
|
-
OCIConfig,
|
|
509
|
-
RunpodConfig,
|
|
510
|
-
TensorDockConfig,
|
|
511
|
-
VastAIConfig,
|
|
512
|
-
VultrConfig,
|
|
513
|
-
DstackConfig,
|
|
514
|
-
]
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
BackendAPIConfig = Annotated[AnyBackendAPIConfig, Field(..., discriminator="type")]
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
class _BackendAPIConfig(CoreModel):
|
|
521
|
-
__root__: BackendAPIConfig
|
|
522
|
-
|
|
523
56
|
|
|
524
57
|
class ProjectConfig(CoreModel):
|
|
525
58
|
name: Annotated[str, Field(description="The name of the project")]
|
|
526
59
|
backends: Annotated[
|
|
527
|
-
Optional[List[
|
|
60
|
+
Optional[List[BackendFileConfigWithCreds]], Field(description="The list of backends")
|
|
528
61
|
] = None
|
|
529
62
|
|
|
530
63
|
|
|
@@ -555,19 +88,13 @@ class ServerConfigManager:
|
|
|
555
88
|
Initializes the default server/config.yml.
|
|
556
89
|
The default config is empty or contains an existing `main` project config.
|
|
557
90
|
"""
|
|
558
|
-
|
|
559
|
-
# so that the backend configuration is always explicit.
|
|
560
|
-
# Details: https://github.com/dstackai/dstack/issues/1384
|
|
561
|
-
self.config = await self._init_config(session=session, init_backends=False)
|
|
91
|
+
self.config = await self._init_config(session)
|
|
562
92
|
if self.config is not None:
|
|
563
93
|
self._save_config(self.config)
|
|
564
94
|
|
|
565
95
|
async def sync_config(self, session: AsyncSession):
|
|
566
96
|
# Disable config.yml sync for https://github.com/dstackai/dstack/issues/815.
|
|
567
97
|
return
|
|
568
|
-
# self.config = await self._init_config(session=session, init_backends=False)
|
|
569
|
-
# if self.config is not None:
|
|
570
|
-
# self._save_config(self.config)
|
|
571
98
|
|
|
572
99
|
async def apply_encryption(self):
|
|
573
100
|
if self.config is None:
|
|
@@ -603,13 +130,15 @@ class ServerConfigManager:
|
|
|
603
130
|
project = await projects_services.get_project_model_by_name_or_error(
|
|
604
131
|
session=session, project_name=project_config.name
|
|
605
132
|
)
|
|
606
|
-
backends_to_delete = set(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
133
|
+
backends_to_delete = set(
|
|
134
|
+
dstack._internal.core.backends.configurators.list_available_backend_types()
|
|
135
|
+
)
|
|
136
|
+
for backend_file_config in project_config.backends or []:
|
|
137
|
+
backend_config = file_config_to_config(backend_file_config)
|
|
138
|
+
backend_type = BackendType(backend_config.type)
|
|
610
139
|
backends_to_delete.difference_update([backend_type])
|
|
611
140
|
try:
|
|
612
|
-
|
|
141
|
+
current_backend_config = await backends_services.get_backend_config(
|
|
613
142
|
project=project,
|
|
614
143
|
backend_type=backend_type,
|
|
615
144
|
)
|
|
@@ -620,23 +149,23 @@ class ServerConfigManager:
|
|
|
620
149
|
backend_type.value,
|
|
621
150
|
)
|
|
622
151
|
continue
|
|
623
|
-
if
|
|
152
|
+
if backend_config == current_backend_config:
|
|
624
153
|
continue
|
|
625
154
|
backend_exists = any(backend_type == b.type for b in project.backends)
|
|
626
155
|
try:
|
|
627
|
-
#
|
|
156
|
+
# current_backend_config may be None if backend exists
|
|
628
157
|
# but it's config is invalid (e.g. cannot be decrypted).
|
|
629
158
|
# Update backend in this case.
|
|
630
|
-
if
|
|
159
|
+
if current_backend_config is None and not backend_exists:
|
|
631
160
|
await backends_services.create_backend(
|
|
632
|
-
session=session, project=project, config=
|
|
161
|
+
session=session, project=project, config=backend_config
|
|
633
162
|
)
|
|
634
163
|
else:
|
|
635
164
|
await backends_services.update_backend(
|
|
636
|
-
session=session, project=project, config=
|
|
165
|
+
session=session, project=project, config=backend_config
|
|
637
166
|
)
|
|
638
167
|
except Exception as e:
|
|
639
|
-
logger.warning("Failed to configure backend %s: %s",
|
|
168
|
+
logger.warning("Failed to configure backend %s: %s", backend_config.type, e)
|
|
640
169
|
await delete_backends_safe(
|
|
641
170
|
session=session,
|
|
642
171
|
project=project,
|
|
@@ -644,9 +173,7 @@ class ServerConfigManager:
|
|
|
644
173
|
error=False,
|
|
645
174
|
)
|
|
646
175
|
|
|
647
|
-
async def _init_config(
|
|
648
|
-
self, session: AsyncSession, init_backends: bool
|
|
649
|
-
) -> Optional[ServerConfig]:
|
|
176
|
+
async def _init_config(self, session: AsyncSession) -> Optional[ServerConfig]:
|
|
650
177
|
project = await projects_services.get_project_model_by_name(
|
|
651
178
|
session=session,
|
|
652
179
|
project_name=settings.DEFAULT_PROJECT_NAME,
|
|
@@ -656,40 +183,20 @@ class ServerConfigManager:
|
|
|
656
183
|
# Force project reload to reflect updates when syncing
|
|
657
184
|
await session.refresh(project)
|
|
658
185
|
backends = []
|
|
659
|
-
for
|
|
660
|
-
|
|
186
|
+
for (
|
|
187
|
+
backend_type
|
|
188
|
+
) in dstack._internal.core.backends.configurators.list_available_backend_types():
|
|
189
|
+
backend_config = await backends_services.get_backend_config(
|
|
661
190
|
project=project, backend_type=backend_type
|
|
662
191
|
)
|
|
663
|
-
if
|
|
664
|
-
backends.append(
|
|
665
|
-
if init_backends and len(backends) == 0:
|
|
666
|
-
backends = await self._init_backends(session=session, project=project)
|
|
192
|
+
if backend_config is not None:
|
|
193
|
+
backends.append(backend_config)
|
|
667
194
|
return ServerConfig(
|
|
668
195
|
projects=[ProjectConfig(name=settings.DEFAULT_PROJECT_NAME, backends=backends)],
|
|
669
196
|
encryption=EncryptionConfig(keys=[]),
|
|
670
197
|
default_permissions=None,
|
|
671
198
|
)
|
|
672
199
|
|
|
673
|
-
async def _init_backends(
|
|
674
|
-
self, session: AsyncSession, project: ProjectModel
|
|
675
|
-
) -> List[BackendConfig]:
|
|
676
|
-
backends = []
|
|
677
|
-
for backend_type in backends_services.list_available_backend_types():
|
|
678
|
-
configurator = backends_services.get_configurator(backend_type)
|
|
679
|
-
if configurator is None:
|
|
680
|
-
continue
|
|
681
|
-
config_infos = await run_async(configurator.get_default_configs)
|
|
682
|
-
for config_info in config_infos:
|
|
683
|
-
try:
|
|
684
|
-
await backends_services.create_backend(
|
|
685
|
-
session=session, project=project, config=config_info
|
|
686
|
-
)
|
|
687
|
-
backends.append(internal_config_to_config(config_info))
|
|
688
|
-
break
|
|
689
|
-
except Exception as e:
|
|
690
|
-
logger.debug("Failed to configure backend %s: %s", config_info.type, e)
|
|
691
|
-
return backends
|
|
692
|
-
|
|
693
200
|
def _load_config(self) -> Optional[ServerConfig]:
|
|
694
201
|
try:
|
|
695
202
|
with open(settings.SERVER_CONFIG_FILE_PATH) as f:
|
|
@@ -707,13 +214,12 @@ class ServerConfigManager:
|
|
|
707
214
|
async def get_backend_config_yaml(
|
|
708
215
|
project: ProjectModel, backend_type: BackendType
|
|
709
216
|
) -> BackendInfoYAML:
|
|
710
|
-
|
|
217
|
+
backend_config = await backends_services.get_backend_config(
|
|
711
218
|
project=project, backend_type=backend_type
|
|
712
219
|
)
|
|
713
|
-
if
|
|
220
|
+
if backend_config is None:
|
|
714
221
|
raise ResourceNotExistsError()
|
|
715
|
-
|
|
716
|
-
config_yaml = config_to_yaml(config)
|
|
222
|
+
config_yaml = config_to_yaml(backend_config)
|
|
717
223
|
return BackendInfoYAML(
|
|
718
224
|
name=backend_type,
|
|
719
225
|
config_yaml=config_yaml,
|
|
@@ -725,9 +231,8 @@ async def create_backend_config_yaml(
|
|
|
725
231
|
project: ProjectModel,
|
|
726
232
|
config_yaml: str,
|
|
727
233
|
):
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
await backends_services.create_backend(session=session, project=project, config=config_info)
|
|
234
|
+
config = config_yaml_to_backend_config(config_yaml)
|
|
235
|
+
await backends_services.create_backend(session=session, project=project, config=config)
|
|
731
236
|
|
|
732
237
|
|
|
733
238
|
async def update_backend_config_yaml(
|
|
@@ -735,64 +240,35 @@ async def update_backend_config_yaml(
|
|
|
735
240
|
project: ProjectModel,
|
|
736
241
|
config_yaml: str,
|
|
737
242
|
):
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
await backends_services.update_backend(session=session, project=project, config=config_info)
|
|
243
|
+
config = config_yaml_to_backend_config(config_yaml)
|
|
244
|
+
await backends_services.update_backend(session=session, project=project, config=config)
|
|
741
245
|
|
|
742
246
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
backend_config = _BackendConfig.parse_obj(config_info.dict(exclude={"locations"}))
|
|
748
|
-
if config_info.type == "azure":
|
|
749
|
-
backend_config.__root__.regions = config_info.locations
|
|
750
|
-
return backend_config.__root__
|
|
751
|
-
|
|
247
|
+
class _BackendConfigWithCreds(CoreModel):
|
|
248
|
+
"""
|
|
249
|
+
Model for parsing API and file YAML configs.
|
|
250
|
+
"""
|
|
752
251
|
|
|
753
|
-
|
|
754
|
-
__root__: Annotated[AnyConfigInfoWithCreds, Field(..., discriminator="type")]
|
|
252
|
+
__root__: Annotated[AnyBackendConfigWithCreds, Field(..., discriminator="type")]
|
|
755
253
|
|
|
756
254
|
|
|
757
|
-
def
|
|
758
|
-
backend_config: Union[BackendConfig, BackendAPIConfig],
|
|
759
|
-
) -> AnyConfigInfoWithCreds:
|
|
760
|
-
backend_config_dict = backend_config.dict()
|
|
761
|
-
# Allow to not specify networking
|
|
762
|
-
if backend_config.type == "kubernetes":
|
|
763
|
-
if backend_config.networking is None:
|
|
764
|
-
backend_config_dict["networking"] = {}
|
|
765
|
-
if backend_config.type == "azure":
|
|
766
|
-
backend_config_dict["locations"] = backend_config_dict["regions"]
|
|
767
|
-
del backend_config_dict["regions"]
|
|
768
|
-
config_info = _ConfigInfoWithCreds.parse_obj(backend_config_dict)
|
|
769
|
-
return config_info.__root__
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
def config_yaml_to_backend_config(config_yaml: str) -> BackendAPIConfig:
|
|
255
|
+
def config_yaml_to_backend_config(config_yaml: str) -> AnyBackendConfigWithCreds:
|
|
773
256
|
try:
|
|
774
257
|
config_dict = yaml.load(config_yaml, yaml.FullLoader)
|
|
775
258
|
except yaml.YAMLError:
|
|
776
259
|
raise ServerClientError("Error parsing YAML")
|
|
777
260
|
try:
|
|
778
|
-
backend_config =
|
|
261
|
+
backend_config = _BackendConfigWithCreds.parse_obj(config_dict).__root__
|
|
779
262
|
except ValidationError as e:
|
|
780
263
|
raise ServerClientError(str(e))
|
|
781
264
|
return backend_config
|
|
782
265
|
|
|
783
266
|
|
|
784
|
-
def
|
|
785
|
-
|
|
267
|
+
def file_config_to_config(file_config: AnyBackendFileConfigWithCreds) -> AnyBackendConfigWithCreds:
|
|
268
|
+
backend_config_dict = file_config.dict()
|
|
269
|
+
backend_config = _BackendConfigWithCreds.parse_obj(backend_config_dict)
|
|
270
|
+
return backend_config.__root__
|
|
786
271
|
|
|
787
272
|
|
|
788
|
-
def
|
|
789
|
-
|
|
790
|
-
return values
|
|
791
|
-
if "filename" not in values:
|
|
792
|
-
raise ValueError()
|
|
793
|
-
try:
|
|
794
|
-
with open(Path(values["filename"]).expanduser()) as f:
|
|
795
|
-
values["data"] = f.read()
|
|
796
|
-
except OSError:
|
|
797
|
-
raise ValueError(f"No such file {values['filename']}")
|
|
798
|
-
return values
|
|
273
|
+
def config_to_yaml(config: CoreModel) -> str:
|
|
274
|
+
return yaml.dump(config.dict(exclude_none=True), sort_keys=False)
|