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
|
@@ -128,7 +128,6 @@ class TestGetRepo:
|
|
|
128
128
|
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
129
129
|
project = await create_project(session=session, owner=user)
|
|
130
130
|
legacy_creds = {
|
|
131
|
-
"protocol": "https",
|
|
132
131
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
133
132
|
"private_key": None,
|
|
134
133
|
"oauth_token": "test_token",
|
|
@@ -157,14 +156,12 @@ class TestGetRepo:
|
|
|
157
156
|
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
158
157
|
project = await create_project(session=session, owner=user)
|
|
159
158
|
legacy_creds = {
|
|
160
|
-
"protocol": "https",
|
|
161
159
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
162
160
|
"private_key": None,
|
|
163
161
|
"oauth_token": "legacy_creds",
|
|
164
162
|
}
|
|
165
163
|
repo = await create_repo(session=session, project_id=project.id, creds=legacy_creds)
|
|
166
164
|
user_creds = {
|
|
167
|
-
"protocol": "https",
|
|
168
165
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
169
166
|
"private_key": None,
|
|
170
167
|
"oauth_token": "user_creds",
|
|
@@ -214,13 +211,9 @@ class TestInitRepo:
|
|
|
214
211
|
"repo_id": "test_repo",
|
|
215
212
|
"repo_info": {
|
|
216
213
|
"repo_type": "remote",
|
|
217
|
-
"repo_host_name": "",
|
|
218
|
-
"repo_port": None,
|
|
219
|
-
"repo_user_name": "",
|
|
220
214
|
"repo_name": "dstack",
|
|
221
215
|
},
|
|
222
216
|
"repo_creds": {
|
|
223
|
-
"protocol": "https",
|
|
224
217
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
225
218
|
"private_key": None,
|
|
226
219
|
"oauth_token": "test_token",
|
|
@@ -254,13 +247,9 @@ class TestInitRepo:
|
|
|
254
247
|
"repo_id": "test_repo",
|
|
255
248
|
"repo_info": {
|
|
256
249
|
"repo_type": "remote",
|
|
257
|
-
"repo_host_name": "",
|
|
258
|
-
"repo_port": None,
|
|
259
|
-
"repo_user_name": "",
|
|
260
250
|
"repo_name": "dstack",
|
|
261
251
|
},
|
|
262
252
|
"repo_creds": {
|
|
263
|
-
"protocol": "https",
|
|
264
253
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
265
254
|
"private_key": None,
|
|
266
255
|
"oauth_token": "test_token",
|
|
@@ -276,13 +265,9 @@ class TestInitRepo:
|
|
|
276
265
|
"repo_id": "test_repo",
|
|
277
266
|
"repo_info": {
|
|
278
267
|
"repo_type": "remote",
|
|
279
|
-
"repo_host_name": "",
|
|
280
|
-
"repo_port": None,
|
|
281
|
-
"repo_user_name": "",
|
|
282
268
|
"repo_name": "dstack",
|
|
283
269
|
},
|
|
284
270
|
"repo_creds": {
|
|
285
|
-
"protocol": "https",
|
|
286
271
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
287
272
|
"private_key": None,
|
|
288
273
|
"oauth_token": "test_token_updated",
|
|
@@ -28,15 +28,12 @@ from dstack._internal.core.models.instances import (
|
|
|
28
28
|
InstanceType,
|
|
29
29
|
Resources,
|
|
30
30
|
)
|
|
31
|
-
from dstack._internal.core.models.
|
|
32
|
-
from dstack._internal.core.models.resources import Range, ResourcesSpec
|
|
31
|
+
from dstack._internal.core.models.resources import Range
|
|
33
32
|
from dstack._internal.core.models.runs import (
|
|
34
33
|
ApplyRunPlanInput,
|
|
35
|
-
JobProvisioningData,
|
|
36
34
|
JobSpec,
|
|
37
35
|
JobStatus,
|
|
38
36
|
JobTerminationReason,
|
|
39
|
-
Requirements,
|
|
40
37
|
Run,
|
|
41
38
|
RunSpec,
|
|
42
39
|
RunStatus,
|
|
@@ -44,10 +41,9 @@ from dstack._internal.core.models.runs import (
|
|
|
44
41
|
)
|
|
45
42
|
from dstack._internal.core.models.users import GlobalRole, ProjectRole
|
|
46
43
|
from dstack._internal.core.models.volumes import InstanceMountPoint, MountPoint
|
|
47
|
-
from dstack._internal.server.background.tasks.process_instances import process_instances
|
|
48
44
|
from dstack._internal.server.main import app
|
|
49
45
|
from dstack._internal.server.models import JobModel, RunModel
|
|
50
|
-
from dstack._internal.server.schemas.runs import ApplyRunPlanRequest
|
|
46
|
+
from dstack._internal.server.schemas.runs import ApplyRunPlanRequest
|
|
51
47
|
from dstack._internal.server.services.projects import add_project_member
|
|
52
48
|
from dstack._internal.server.services.runs import run_model_to_run
|
|
53
49
|
from dstack._internal.server.testing.common import (
|
|
@@ -56,7 +52,6 @@ from dstack._internal.server.testing.common import (
|
|
|
56
52
|
create_gateway_compute,
|
|
57
53
|
create_instance,
|
|
58
54
|
create_job,
|
|
59
|
-
create_pool,
|
|
60
55
|
create_project,
|
|
61
56
|
create_repo,
|
|
62
57
|
create_run,
|
|
@@ -120,18 +115,13 @@ def get_dev_env_run_plan_dict(
|
|
|
120
115
|
"availability_zones": None,
|
|
121
116
|
"instance_types": None,
|
|
122
117
|
"creation_policy": None,
|
|
123
|
-
"instance_name": None,
|
|
124
118
|
"single_branch": None,
|
|
125
119
|
"max_duration": "off",
|
|
126
120
|
"stop_duration": None,
|
|
127
121
|
"max_price": None,
|
|
128
|
-
"pool_name": DEFAULT_POOL_NAME,
|
|
129
122
|
"retry": None,
|
|
130
|
-
"retry_policy": None,
|
|
131
123
|
"spot_policy": "spot",
|
|
132
124
|
"idle_duration": None,
|
|
133
|
-
"termination_idle_time": 300,
|
|
134
|
-
"termination_policy": None,
|
|
135
125
|
"utilization_policy": None,
|
|
136
126
|
"reservation": None,
|
|
137
127
|
},
|
|
@@ -143,18 +133,13 @@ def get_dev_env_run_plan_dict(
|
|
|
143
133
|
"instance_types": None,
|
|
144
134
|
"creation_policy": None,
|
|
145
135
|
"default": False,
|
|
146
|
-
"instance_name": None,
|
|
147
136
|
"max_duration": "off",
|
|
148
137
|
"stop_duration": None,
|
|
149
138
|
"max_price": None,
|
|
150
139
|
"name": "string",
|
|
151
|
-
"pool_name": DEFAULT_POOL_NAME,
|
|
152
140
|
"retry": None,
|
|
153
|
-
"retry_policy": None,
|
|
154
141
|
"spot_policy": "spot",
|
|
155
142
|
"idle_duration": None,
|
|
156
|
-
"termination_idle_time": 300,
|
|
157
|
-
"termination_policy": None,
|
|
158
143
|
"utilization_policy": None,
|
|
159
144
|
"reservation": None,
|
|
160
145
|
},
|
|
@@ -214,7 +199,7 @@ def get_dev_env_run_plan_dict(
|
|
|
214
199
|
},
|
|
215
200
|
"retry": None,
|
|
216
201
|
"volumes": volumes,
|
|
217
|
-
"
|
|
202
|
+
"ssh_key": None,
|
|
218
203
|
"working_dir": ".",
|
|
219
204
|
},
|
|
220
205
|
"offers": [json.loads(o.json()) for o in offers],
|
|
@@ -280,18 +265,13 @@ def get_dev_env_run_dict(
|
|
|
280
265
|
"availability_zones": None,
|
|
281
266
|
"instance_types": None,
|
|
282
267
|
"creation_policy": None,
|
|
283
|
-
"instance_name": None,
|
|
284
268
|
"single_branch": None,
|
|
285
269
|
"max_duration": "off",
|
|
286
270
|
"stop_duration": None,
|
|
287
271
|
"max_price": None,
|
|
288
|
-
"pool_name": DEFAULT_POOL_NAME,
|
|
289
272
|
"retry": None,
|
|
290
|
-
"retry_policy": None,
|
|
291
273
|
"spot_policy": "spot",
|
|
292
274
|
"idle_duration": None,
|
|
293
|
-
"termination_idle_time": 300,
|
|
294
|
-
"termination_policy": None,
|
|
295
275
|
"utilization_policy": None,
|
|
296
276
|
"reservation": None,
|
|
297
277
|
},
|
|
@@ -303,18 +283,13 @@ def get_dev_env_run_dict(
|
|
|
303
283
|
"instance_types": None,
|
|
304
284
|
"creation_policy": None,
|
|
305
285
|
"default": False,
|
|
306
|
-
"instance_name": None,
|
|
307
286
|
"max_duration": "off",
|
|
308
287
|
"stop_duration": None,
|
|
309
288
|
"max_price": None,
|
|
310
289
|
"name": "string",
|
|
311
|
-
"pool_name": DEFAULT_POOL_NAME,
|
|
312
290
|
"retry": None,
|
|
313
|
-
"retry_policy": None,
|
|
314
291
|
"spot_policy": "spot",
|
|
315
292
|
"idle_duration": None,
|
|
316
|
-
"termination_idle_time": 300,
|
|
317
|
-
"termination_policy": None,
|
|
318
293
|
"utilization_policy": None,
|
|
319
294
|
"reservation": None,
|
|
320
295
|
},
|
|
@@ -374,7 +349,7 @@ def get_dev_env_run_dict(
|
|
|
374
349
|
},
|
|
375
350
|
"retry": None,
|
|
376
351
|
"volumes": [],
|
|
377
|
-
"
|
|
352
|
+
"ssh_key": None,
|
|
378
353
|
"working_dir": ".",
|
|
379
354
|
},
|
|
380
355
|
"job_submissions": [
|
|
@@ -1341,11 +1316,9 @@ class TestStopRuns:
|
|
|
1341
1316
|
user=user,
|
|
1342
1317
|
status=RunStatus.RUNNING,
|
|
1343
1318
|
)
|
|
1344
|
-
pool = await create_pool(session=session, project=project)
|
|
1345
1319
|
instance = await create_instance(
|
|
1346
1320
|
session=session,
|
|
1347
1321
|
project=project,
|
|
1348
|
-
pool=pool,
|
|
1349
1322
|
status=InstanceStatus.BUSY,
|
|
1350
1323
|
)
|
|
1351
1324
|
job = await create_job(
|
|
@@ -1494,194 +1467,6 @@ class TestDeleteRuns:
|
|
|
1494
1467
|
assert len(res.scalars().all()) == 1
|
|
1495
1468
|
|
|
1496
1469
|
|
|
1497
|
-
class TestCreateInstance:
|
|
1498
|
-
@pytest.mark.asyncio
|
|
1499
|
-
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
1500
|
-
async def test_returns_403_if_not_project_member(
|
|
1501
|
-
self, test_db, session: AsyncSession, client: AsyncClient
|
|
1502
|
-
):
|
|
1503
|
-
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
1504
|
-
project = await create_project(session=session, owner=user)
|
|
1505
|
-
response = await client.post(
|
|
1506
|
-
f"/api/project/{project.name}/runs/create_instance",
|
|
1507
|
-
headers=get_auth_headers(user.token),
|
|
1508
|
-
)
|
|
1509
|
-
assert response.status_code == 403
|
|
1510
|
-
|
|
1511
|
-
@pytest.mark.asyncio
|
|
1512
|
-
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
1513
|
-
async def test_creates_instance(self, test_db, session: AsyncSession, client: AsyncClient):
|
|
1514
|
-
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
1515
|
-
project = await create_project(session=session, owner=user)
|
|
1516
|
-
await add_project_member(
|
|
1517
|
-
session=session, project=project, user=user, project_role=ProjectRole.USER
|
|
1518
|
-
)
|
|
1519
|
-
request = CreateInstanceRequest(
|
|
1520
|
-
profile=Profile(name="test_profile"),
|
|
1521
|
-
requirements=Requirements(resources=ResourcesSpec(cpu=1)),
|
|
1522
|
-
)
|
|
1523
|
-
instance_id = UUID("1b0e1b45-2f8c-4ab6-8010-a0d1a3e44e0e")
|
|
1524
|
-
with (
|
|
1525
|
-
patch(
|
|
1526
|
-
"dstack._internal.server.services.offers.get_offers_by_requirements"
|
|
1527
|
-
) as run_plan_by_req,
|
|
1528
|
-
patch("uuid.uuid4") as uuid_mock,
|
|
1529
|
-
):
|
|
1530
|
-
uuid_mock.return_value = instance_id
|
|
1531
|
-
offer = InstanceOfferWithAvailability(
|
|
1532
|
-
backend=BackendType.AWS,
|
|
1533
|
-
instance=InstanceType(
|
|
1534
|
-
name="instance",
|
|
1535
|
-
resources=Resources(cpus=1, memory_mib=512, spot=False, gpus=[]),
|
|
1536
|
-
),
|
|
1537
|
-
region="eu",
|
|
1538
|
-
price=1.0,
|
|
1539
|
-
availability=InstanceAvailability.AVAILABLE,
|
|
1540
|
-
)
|
|
1541
|
-
backend = Mock()
|
|
1542
|
-
backend.compute.return_value.get_offers_cached.return_value = [offer]
|
|
1543
|
-
backend.compute.return_value.create_instance.return_value = JobProvisioningData(
|
|
1544
|
-
backend=offer.backend,
|
|
1545
|
-
instance_type=offer.instance,
|
|
1546
|
-
instance_id="test_instance",
|
|
1547
|
-
hostname="1.1.1.1",
|
|
1548
|
-
internal_ip=None,
|
|
1549
|
-
region=offer.region,
|
|
1550
|
-
price=offer.price,
|
|
1551
|
-
username="ubuntu",
|
|
1552
|
-
ssh_port=22,
|
|
1553
|
-
ssh_proxy=None,
|
|
1554
|
-
dockerized=True,
|
|
1555
|
-
backend_data=None,
|
|
1556
|
-
)
|
|
1557
|
-
backend.TYPE = BackendType.AWS
|
|
1558
|
-
run_plan_by_req.return_value = [(backend, offer)]
|
|
1559
|
-
response = await client.post(
|
|
1560
|
-
f"/api/project/{project.name}/runs/create_instance",
|
|
1561
|
-
headers=get_auth_headers(user.token),
|
|
1562
|
-
json=request.dict(),
|
|
1563
|
-
)
|
|
1564
|
-
assert response.status_code == 200
|
|
1565
|
-
result = response.json()
|
|
1566
|
-
expected = {
|
|
1567
|
-
"id": str(instance_id),
|
|
1568
|
-
"project_name": project.name,
|
|
1569
|
-
"backend": None,
|
|
1570
|
-
"instance_type": None,
|
|
1571
|
-
"name": result["name"],
|
|
1572
|
-
"fleet_id": None,
|
|
1573
|
-
"fleet_name": None,
|
|
1574
|
-
"instance_num": 0,
|
|
1575
|
-
"job_name": None,
|
|
1576
|
-
"hostname": None,
|
|
1577
|
-
"status": "pending",
|
|
1578
|
-
"unreachable": False,
|
|
1579
|
-
"termination_reason": None,
|
|
1580
|
-
"created": result["created"],
|
|
1581
|
-
"pool_name": None,
|
|
1582
|
-
"region": None,
|
|
1583
|
-
"availability_zone": None,
|
|
1584
|
-
"price": None,
|
|
1585
|
-
"total_blocks": 1,
|
|
1586
|
-
"busy_blocks": 0,
|
|
1587
|
-
}
|
|
1588
|
-
assert result == expected
|
|
1589
|
-
|
|
1590
|
-
@pytest.mark.asyncio
|
|
1591
|
-
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
1592
|
-
async def test_error_if_backends_do_not_support_create_instance(
|
|
1593
|
-
self, test_db, session: AsyncSession, client: AsyncClient
|
|
1594
|
-
):
|
|
1595
|
-
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
1596
|
-
project = await create_project(session=session, owner=user)
|
|
1597
|
-
await add_project_member(
|
|
1598
|
-
session=session, project=project, user=user, project_role=ProjectRole.USER
|
|
1599
|
-
)
|
|
1600
|
-
request = CreateInstanceRequest(
|
|
1601
|
-
profile=Profile(name="test_profile"),
|
|
1602
|
-
requirements=Requirements(resources=ResourcesSpec(cpu=1)),
|
|
1603
|
-
)
|
|
1604
|
-
with patch(
|
|
1605
|
-
"dstack._internal.server.services.offers.get_offers_by_requirements"
|
|
1606
|
-
) as run_plan_by_req:
|
|
1607
|
-
offer = InstanceOfferWithAvailability(
|
|
1608
|
-
backend=BackendType.AZURE,
|
|
1609
|
-
instance=InstanceType(
|
|
1610
|
-
name="instance",
|
|
1611
|
-
resources=Resources(cpus=1, memory_mib=512, spot=False, gpus=[]),
|
|
1612
|
-
),
|
|
1613
|
-
region="eu",
|
|
1614
|
-
price=1.0,
|
|
1615
|
-
availability=InstanceAvailability.AVAILABLE,
|
|
1616
|
-
)
|
|
1617
|
-
backend = Mock()
|
|
1618
|
-
backend.TYPE = BackendType.AZURE
|
|
1619
|
-
backend.compute.return_value.get_offers_cached.return_value = [offer]
|
|
1620
|
-
backend.compute.return_value.create_instance.side_effect = NotImplementedError()
|
|
1621
|
-
run_plan_by_req.return_value = [(backend, offer)]
|
|
1622
|
-
response = await client.post(
|
|
1623
|
-
f"/api/project/{project.name}/runs/create_instance",
|
|
1624
|
-
headers=get_auth_headers(user.token),
|
|
1625
|
-
json=request.dict(),
|
|
1626
|
-
)
|
|
1627
|
-
assert response.status_code == 200
|
|
1628
|
-
await process_instances()
|
|
1629
|
-
|
|
1630
|
-
@pytest.mark.asyncio
|
|
1631
|
-
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
1632
|
-
async def test_backend_does_not_support_create_instance(
|
|
1633
|
-
self, test_db, session: AsyncSession, client: AsyncClient
|
|
1634
|
-
):
|
|
1635
|
-
user = await create_user(session=session, global_role=GlobalRole.USER)
|
|
1636
|
-
project = await create_project(session=session, owner=user)
|
|
1637
|
-
await add_project_member(
|
|
1638
|
-
session=session, project=project, user=user, project_role=ProjectRole.USER
|
|
1639
|
-
)
|
|
1640
|
-
request = CreateInstanceRequest(
|
|
1641
|
-
profile=Profile(name="test_profile"),
|
|
1642
|
-
requirements=Requirements(resources=ResourcesSpec(cpu=1)),
|
|
1643
|
-
)
|
|
1644
|
-
|
|
1645
|
-
with patch(
|
|
1646
|
-
"dstack._internal.server.services.offers.get_offers_by_requirements"
|
|
1647
|
-
) as run_plan_by_req:
|
|
1648
|
-
offers = InstanceOfferWithAvailability(
|
|
1649
|
-
backend=BackendType.VASTAI,
|
|
1650
|
-
instance=InstanceType(
|
|
1651
|
-
name="instance",
|
|
1652
|
-
resources=Resources(cpus=1, memory_mib=512, spot=False, gpus=[]),
|
|
1653
|
-
),
|
|
1654
|
-
region="eu",
|
|
1655
|
-
price=1.0,
|
|
1656
|
-
availability=InstanceAvailability.AVAILABLE,
|
|
1657
|
-
)
|
|
1658
|
-
|
|
1659
|
-
backend = Mock()
|
|
1660
|
-
backend.TYPE = BackendType.VASTAI
|
|
1661
|
-
backend.compute.return_value.get_offers_cached.return_value = [offers]
|
|
1662
|
-
backend.compute.return_value.create_instance.side_effect = NotImplementedError()
|
|
1663
|
-
run_plan_by_req.return_value = [(backend, offers)]
|
|
1664
|
-
|
|
1665
|
-
response = await client.post(
|
|
1666
|
-
f"/api/project/{project.name}/runs/create_instance",
|
|
1667
|
-
headers=get_auth_headers(user.token),
|
|
1668
|
-
json=request.dict(),
|
|
1669
|
-
)
|
|
1670
|
-
|
|
1671
|
-
assert response.status_code == 400
|
|
1672
|
-
|
|
1673
|
-
result = response.json()
|
|
1674
|
-
expected = {
|
|
1675
|
-
"detail": [
|
|
1676
|
-
{
|
|
1677
|
-
"msg": "Backends do not support create_instance. Try to select other backends.",
|
|
1678
|
-
"code": "error",
|
|
1679
|
-
}
|
|
1680
|
-
]
|
|
1681
|
-
}
|
|
1682
|
-
assert result == expected
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
1470
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
1686
1471
|
class TestSubmitService:
|
|
1687
1472
|
@pytest.fixture(autouse=True)
|
|
@@ -14,8 +14,8 @@ from dstack._internal.core.models.users import GlobalRole, ProjectRole
|
|
|
14
14
|
from dstack._internal.server.models import VolumeAttachmentModel, VolumeModel
|
|
15
15
|
from dstack._internal.server.services.projects import add_project_member
|
|
16
16
|
from dstack._internal.server.testing.common import (
|
|
17
|
+
ComputeMockSpec,
|
|
17
18
|
create_instance,
|
|
18
|
-
create_pool,
|
|
19
19
|
create_project,
|
|
20
20
|
create_user,
|
|
21
21
|
create_volume,
|
|
@@ -366,6 +366,7 @@ class TestDeleteVolumes:
|
|
|
366
366
|
) as m:
|
|
367
367
|
aws_mock = Mock()
|
|
368
368
|
m.return_value = aws_mock
|
|
369
|
+
aws_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
369
370
|
response = await client.post(
|
|
370
371
|
f"/api/project/{project.name}/volumes/delete",
|
|
371
372
|
headers=get_auth_headers(user.token),
|
|
@@ -383,7 +384,6 @@ class TestDeleteVolumes:
|
|
|
383
384
|
):
|
|
384
385
|
user = await create_user(session, global_role=GlobalRole.USER)
|
|
385
386
|
project = await create_project(session)
|
|
386
|
-
pool = await create_pool(session=session, project=project)
|
|
387
387
|
await add_project_member(
|
|
388
388
|
session=session, project=project, user=user, project_role=ProjectRole.USER
|
|
389
389
|
)
|
|
@@ -396,7 +396,6 @@ class TestDeleteVolumes:
|
|
|
396
396
|
instance = await create_instance(
|
|
397
397
|
session=session,
|
|
398
398
|
project=project,
|
|
399
|
-
pool=pool,
|
|
400
399
|
)
|
|
401
400
|
volume.attachments.append(VolumeAttachmentModel(instance=instance))
|
|
402
401
|
await session.commit()
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.models.configurations import TaskConfiguration
|
|
6
|
+
from dstack._internal.core.models.runs import JobSSHKey
|
|
7
|
+
from dstack._internal.server.services.jobs.configurators.task import TaskJobConfigurator
|
|
8
|
+
from dstack._internal.server.testing.common import get_run_spec
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.asyncio
|
|
12
|
+
@pytest.mark.usefixtures("image_config_mock")
|
|
13
|
+
class TestTaskJobConfigurator:
|
|
14
|
+
async def test_ssh_key_single_node(self):
|
|
15
|
+
configuration = TaskConfiguration(nodes=1, image="debian")
|
|
16
|
+
run_spec = get_run_spec(run_name="run", repo_id="id", configuration=configuration)
|
|
17
|
+
configurator = TaskJobConfigurator(run_spec)
|
|
18
|
+
|
|
19
|
+
job_specs = await configurator.get_job_specs(replica_num=0)
|
|
20
|
+
|
|
21
|
+
assert len(job_specs) == 1
|
|
22
|
+
assert job_specs[0].ssh_key is None
|
|
23
|
+
|
|
24
|
+
async def test_ssh_key_multi_node(self):
|
|
25
|
+
configuration = TaskConfiguration(nodes=2, image="debian")
|
|
26
|
+
run_spec = get_run_spec(run_name="run", repo_id="id", configuration=configuration)
|
|
27
|
+
configurator = TaskJobConfigurator(run_spec)
|
|
28
|
+
|
|
29
|
+
with patch("dstack._internal.utils.crypto.generate_rsa_key_pair_bytes") as gen_mock:
|
|
30
|
+
gen_mock.side_effect = [(b"private1", b"public1"), (b"private2", b"public2")]
|
|
31
|
+
job_specs = await configurator.get_job_specs(replica_num=0)
|
|
32
|
+
|
|
33
|
+
assert len(job_specs) == 2
|
|
34
|
+
assert job_specs[0].ssh_key == JobSSHKey(private="private1", public="public1")
|
|
35
|
+
assert job_specs[1].ssh_key == JobSSHKey(private="private1", public="public1")
|
|
@@ -6,11 +6,14 @@ import yaml
|
|
|
6
6
|
from sqlalchemy import select
|
|
7
7
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
8
8
|
|
|
9
|
-
from dstack._internal.core.
|
|
9
|
+
from dstack._internal.core.backends.azure.models import (
|
|
10
|
+
AzureBackendConfigWithCreds,
|
|
11
|
+
AzureDefaultCreds,
|
|
12
|
+
)
|
|
10
13
|
from dstack._internal.core.models.backends.base import BackendType
|
|
11
14
|
from dstack._internal.server import settings
|
|
12
15
|
from dstack._internal.server.models import BackendModel, ProjectModel
|
|
13
|
-
from dstack._internal.server.services.config import
|
|
16
|
+
from dstack._internal.server.services.config import ServerConfigManager
|
|
14
17
|
from dstack._internal.server.testing.common import (
|
|
15
18
|
create_project,
|
|
16
19
|
create_user,
|
|
@@ -38,7 +41,7 @@ class TestServerConfigManager:
|
|
|
38
41
|
) as create_backend_mock,
|
|
39
42
|
):
|
|
40
43
|
list_available_backend_types_mock.return_value = [BackendType.AZURE]
|
|
41
|
-
default_config =
|
|
44
|
+
default_config = AzureBackendConfigWithCreds(
|
|
42
45
|
tenant_id="test_tenant",
|
|
43
46
|
subscription_id="test_subscription",
|
|
44
47
|
locations=["westeurope"],
|
|
@@ -52,7 +55,7 @@ class TestServerConfigManager:
|
|
|
52
55
|
list_available_backend_types_mock.assert_called()
|
|
53
56
|
get_configurator_mock.assert_called()
|
|
54
57
|
create_backend_mock.assert_called()
|
|
55
|
-
assert manager.config.projects[0].backends[0] ==
|
|
58
|
+
assert manager.config.projects[0].backends[0] == AzureBackendConfigWithCreds(
|
|
56
59
|
tenant_id="test_tenant",
|
|
57
60
|
subscription_id="test_subscription",
|
|
58
61
|
regions=["westeurope"],
|
|
@@ -4,7 +4,7 @@ from unittest.mock import Mock
|
|
|
4
4
|
import pytest
|
|
5
5
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
6
|
|
|
7
|
-
from dstack._internal.core.backends.base import Backend
|
|
7
|
+
from dstack._internal.core.backends.base.backend import Backend
|
|
8
8
|
from dstack._internal.core.errors import ServerClientError
|
|
9
9
|
from dstack._internal.core.models.backends.base import BackendType
|
|
10
10
|
from dstack._internal.core.models.fleets import (
|
|
@@ -20,7 +20,6 @@ from dstack._internal.server.services.fleets import get_plan
|
|
|
20
20
|
from dstack._internal.server.testing.common import (
|
|
21
21
|
create_fleet,
|
|
22
22
|
create_instance,
|
|
23
|
-
create_pool,
|
|
24
23
|
create_project,
|
|
25
24
|
create_user,
|
|
26
25
|
get_fleet_spec,
|
|
@@ -45,7 +44,6 @@ class TestGetPlanSSHFleetHostsValidation:
|
|
|
45
44
|
self, session: AsyncSession, project: ProjectModel, spec: FleetSpec
|
|
46
45
|
) -> FleetModel:
|
|
47
46
|
assert spec.configuration.ssh_config is not None, spec.configuration
|
|
48
|
-
pool = await create_pool(session=session, project=project)
|
|
49
47
|
fleet = await create_fleet(session=session, project=project, spec=spec)
|
|
50
48
|
for host in spec.configuration.ssh_config.hosts:
|
|
51
49
|
if isinstance(host, SSHHostParams):
|
|
@@ -56,7 +54,6 @@ class TestGetPlanSSHFleetHostsValidation:
|
|
|
56
54
|
await create_instance(
|
|
57
55
|
session=session,
|
|
58
56
|
project=project,
|
|
59
|
-
pool=pool,
|
|
60
57
|
fleet=fleet,
|
|
61
58
|
backend=BackendType.REMOTE,
|
|
62
59
|
remote_connection_info=rci,
|