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
|
@@ -14,7 +14,7 @@ from dstack._internal.core.models.instances import (
|
|
|
14
14
|
InstanceType,
|
|
15
15
|
Resources,
|
|
16
16
|
)
|
|
17
|
-
from dstack._internal.core.models.profiles import Profile
|
|
17
|
+
from dstack._internal.core.models.profiles import Profile
|
|
18
18
|
from dstack._internal.core.models.runs import (
|
|
19
19
|
JobProvisioningData,
|
|
20
20
|
JobStatus,
|
|
@@ -29,10 +29,10 @@ from dstack._internal.core.models.volumes import (
|
|
|
29
29
|
from dstack._internal.server.background.tasks.process_submitted_jobs import process_submitted_jobs
|
|
30
30
|
from dstack._internal.server.models import InstanceModel, JobModel, VolumeAttachmentModel
|
|
31
31
|
from dstack._internal.server.testing.common import (
|
|
32
|
+
ComputeMockSpec,
|
|
32
33
|
create_fleet,
|
|
33
34
|
create_instance,
|
|
34
35
|
create_job,
|
|
35
|
-
create_pool,
|
|
36
36
|
create_project,
|
|
37
37
|
create_repo,
|
|
38
38
|
create_run,
|
|
@@ -52,7 +52,6 @@ class TestProcessSubmittedJobs:
|
|
|
52
52
|
async def test_fails_job_when_no_backends(self, test_db, session: AsyncSession):
|
|
53
53
|
project = await create_project(session=session)
|
|
54
54
|
user = await create_user(session=session)
|
|
55
|
-
await create_pool(session=session, project=project)
|
|
56
55
|
repo = await create_repo(
|
|
57
56
|
session=session,
|
|
58
57
|
project_id=project.id,
|
|
@@ -93,7 +92,6 @@ class TestProcessSubmittedJobs:
|
|
|
93
92
|
):
|
|
94
93
|
project = await create_project(session=session)
|
|
95
94
|
user = await create_user(session=session)
|
|
96
|
-
pool = await create_pool(session=session, project=project)
|
|
97
95
|
repo = await create_repo(
|
|
98
96
|
session=session,
|
|
99
97
|
project_id=project.id,
|
|
@@ -151,12 +149,6 @@ class TestProcessSubmittedJobs:
|
|
|
151
149
|
assert job is not None
|
|
152
150
|
assert job.status == JobStatus.PROVISIONING
|
|
153
151
|
|
|
154
|
-
await session.refresh(pool)
|
|
155
|
-
instance_offer = InstanceOfferWithAvailability.parse_raw(pool.instances[0].offer)
|
|
156
|
-
assert offer == instance_offer
|
|
157
|
-
pool_job_provisioning_data = pool.instances[0].job_provisioning_data
|
|
158
|
-
assert pool_job_provisioning_data == job.job_provisioning_data
|
|
159
|
-
|
|
160
152
|
@pytest.mark.asyncio
|
|
161
153
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
162
154
|
async def test_fails_job_when_privileged_true_and_no_offers_with_create_instance_support(
|
|
@@ -166,7 +158,6 @@ class TestProcessSubmittedJobs:
|
|
|
166
158
|
):
|
|
167
159
|
project = await create_project(session=session)
|
|
168
160
|
user = await create_user(session=session)
|
|
169
|
-
pool = await create_pool(session=session, project=project)
|
|
170
161
|
repo = await create_repo(
|
|
171
162
|
session=session,
|
|
172
163
|
project_id=project.id,
|
|
@@ -227,9 +218,6 @@ class TestProcessSubmittedJobs:
|
|
|
227
218
|
assert job.status == JobStatus.TERMINATING
|
|
228
219
|
assert job.termination_reason == JobTerminationReason.FAILED_TO_START_DUE_TO_NO_CAPACITY
|
|
229
220
|
|
|
230
|
-
await session.refresh(pool)
|
|
231
|
-
assert not pool.instances
|
|
232
|
-
|
|
233
221
|
@pytest.mark.asyncio
|
|
234
222
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
235
223
|
async def test_fails_job_when_instance_mounts_and_no_offers_with_create_instance_support(
|
|
@@ -239,7 +227,6 @@ class TestProcessSubmittedJobs:
|
|
|
239
227
|
):
|
|
240
228
|
project = await create_project(session=session)
|
|
241
229
|
user = await create_user(session=session)
|
|
242
|
-
pool = await create_pool(session=session, project=project)
|
|
243
230
|
repo = await create_repo(
|
|
244
231
|
session=session,
|
|
245
232
|
project_id=project.id,
|
|
@@ -300,9 +287,6 @@ class TestProcessSubmittedJobs:
|
|
|
300
287
|
assert job.status == JobStatus.TERMINATING
|
|
301
288
|
assert job.termination_reason == JobTerminationReason.FAILED_TO_START_DUE_TO_NO_CAPACITY
|
|
302
289
|
|
|
303
|
-
await session.refresh(pool)
|
|
304
|
-
assert not pool.instances
|
|
305
|
-
|
|
306
290
|
@pytest.mark.asyncio
|
|
307
291
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
308
292
|
async def test_provisions_job_with_optional_instance_volume_not_attached(
|
|
@@ -312,7 +296,6 @@ class TestProcessSubmittedJobs:
|
|
|
312
296
|
):
|
|
313
297
|
project = await create_project(session=session)
|
|
314
298
|
user = await create_user(session=session)
|
|
315
|
-
pool = await create_pool(session=session, project=project)
|
|
316
299
|
repo = await create_repo(
|
|
317
300
|
session=session,
|
|
318
301
|
project_id=project.id,
|
|
@@ -369,18 +352,11 @@ class TestProcessSubmittedJobs:
|
|
|
369
352
|
assert job is not None
|
|
370
353
|
assert job.status == JobStatus.PROVISIONING
|
|
371
354
|
|
|
372
|
-
await session.refresh(pool)
|
|
373
|
-
instance_offer = InstanceOfferWithAvailability.parse_raw(pool.instances[0].offer)
|
|
374
|
-
assert offer == instance_offer
|
|
375
|
-
pool_job_provisioning_data = pool.instances[0].job_provisioning_data
|
|
376
|
-
assert pool_job_provisioning_data == job.job_provisioning_data
|
|
377
|
-
|
|
378
355
|
@pytest.mark.asyncio
|
|
379
356
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
380
357
|
async def test_fails_job_when_no_capacity(self, test_db, session: AsyncSession):
|
|
381
358
|
project = await create_project(session=session)
|
|
382
359
|
user = await create_user(session=session)
|
|
383
|
-
pool = await create_pool(session=session, project=project)
|
|
384
360
|
repo = await create_repo(
|
|
385
361
|
session=session,
|
|
386
362
|
project_id=project.id,
|
|
@@ -396,7 +372,6 @@ class TestProcessSubmittedJobs:
|
|
|
396
372
|
repo_id=repo.name,
|
|
397
373
|
profile=Profile(
|
|
398
374
|
name="default",
|
|
399
|
-
retry_policy=ProfileRetryPolicy(retry=True, duration=3600),
|
|
400
375
|
),
|
|
401
376
|
),
|
|
402
377
|
)
|
|
@@ -414,15 +389,12 @@ class TestProcessSubmittedJobs:
|
|
|
414
389
|
assert job is not None
|
|
415
390
|
assert job.status == JobStatus.TERMINATING
|
|
416
391
|
assert job.termination_reason == JobTerminationReason.FAILED_TO_START_DUE_TO_NO_CAPACITY
|
|
417
|
-
await session.refresh(pool)
|
|
418
|
-
assert not pool.instances
|
|
419
392
|
|
|
420
393
|
@pytest.mark.asyncio
|
|
421
394
|
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
|
|
422
395
|
async def test_assignes_job_to_instance(self, test_db, session: AsyncSession):
|
|
423
396
|
project = await create_project(session)
|
|
424
397
|
user = await create_user(session)
|
|
425
|
-
pool = await create_pool(session=session, project=project)
|
|
426
398
|
repo = await create_repo(
|
|
427
399
|
session=session,
|
|
428
400
|
project_id=project.id,
|
|
@@ -430,10 +402,8 @@ class TestProcessSubmittedJobs:
|
|
|
430
402
|
instance = await create_instance(
|
|
431
403
|
session=session,
|
|
432
404
|
project=project,
|
|
433
|
-
pool=pool,
|
|
434
405
|
status=InstanceStatus.IDLE,
|
|
435
406
|
)
|
|
436
|
-
await session.refresh(pool)
|
|
437
407
|
run = await create_run(
|
|
438
408
|
session=session,
|
|
439
409
|
project=project,
|
|
@@ -459,7 +429,6 @@ class TestProcessSubmittedJobs:
|
|
|
459
429
|
async def test_assigns_job_to_instance_with_volumes(self, test_db, session: AsyncSession):
|
|
460
430
|
project = await create_project(session)
|
|
461
431
|
user = await create_user(session)
|
|
462
|
-
pool = await create_pool(session=session, project=project)
|
|
463
432
|
repo = await create_repo(
|
|
464
433
|
session=session,
|
|
465
434
|
project_id=project.id,
|
|
@@ -476,12 +445,10 @@ class TestProcessSubmittedJobs:
|
|
|
476
445
|
instance = await create_instance(
|
|
477
446
|
session=session,
|
|
478
447
|
project=project,
|
|
479
|
-
pool=pool,
|
|
480
448
|
status=InstanceStatus.IDLE,
|
|
481
449
|
backend=BackendType.AWS,
|
|
482
450
|
region="us-east-1",
|
|
483
451
|
)
|
|
484
|
-
await session.refresh(pool)
|
|
485
452
|
run_spec = get_run_spec(run_name="test-run", repo_id=repo.name)
|
|
486
453
|
run_spec.configuration.volumes = [
|
|
487
454
|
VolumeMountPoint(name=volume.name, path="/volume"),
|
|
@@ -506,6 +473,7 @@ class TestProcessSubmittedJobs:
|
|
|
506
473
|
backend_mock = Mock()
|
|
507
474
|
m.return_value = backend_mock
|
|
508
475
|
backend_mock.TYPE = BackendType.AWS
|
|
476
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
509
477
|
backend_mock.compute.return_value.attach_volume.return_value = VolumeAttachmentData()
|
|
510
478
|
# Submitted jobs processing happens in two steps
|
|
511
479
|
await process_submitted_jobs()
|
|
@@ -532,7 +500,6 @@ class TestProcessSubmittedJobs:
|
|
|
532
500
|
async def test_assigns_job_to_shared_instance(self, test_db, session: AsyncSession):
|
|
533
501
|
project = await create_project(session)
|
|
534
502
|
user = await create_user(session)
|
|
535
|
-
pool = await create_pool(session=session, project=project)
|
|
536
503
|
repo = await create_repo(
|
|
537
504
|
session=session,
|
|
538
505
|
project_id=project.id,
|
|
@@ -541,13 +508,11 @@ class TestProcessSubmittedJobs:
|
|
|
541
508
|
instance = await create_instance(
|
|
542
509
|
session=session,
|
|
543
510
|
project=project,
|
|
544
|
-
pool=pool,
|
|
545
511
|
status=InstanceStatus.IDLE,
|
|
546
512
|
offer=offer,
|
|
547
513
|
total_blocks=4,
|
|
548
514
|
busy_blocks=1,
|
|
549
515
|
)
|
|
550
|
-
await session.refresh(pool)
|
|
551
516
|
run = await create_run(
|
|
552
517
|
session=session,
|
|
553
518
|
project=project,
|
|
@@ -577,12 +542,10 @@ class TestProcessSubmittedJobs:
|
|
|
577
542
|
project = await create_project(session)
|
|
578
543
|
user = await create_user(session)
|
|
579
544
|
repo = await create_repo(session=session, project_id=project.id)
|
|
580
|
-
pool = await create_pool(session=session, project=project)
|
|
581
545
|
fleet = await create_fleet(session=session, project=project)
|
|
582
546
|
instance = await create_instance(
|
|
583
547
|
session=session,
|
|
584
548
|
project=project,
|
|
585
|
-
pool=pool,
|
|
586
549
|
instance_num=0,
|
|
587
550
|
status=InstanceStatus.BUSY,
|
|
588
551
|
)
|
|
@@ -7,6 +7,7 @@ from dstack._internal.core.models.backends.base import BackendType
|
|
|
7
7
|
from dstack._internal.core.models.volumes import VolumeProvisioningData, VolumeStatus
|
|
8
8
|
from dstack._internal.server.background.tasks.process_volumes import process_submitted_volumes
|
|
9
9
|
from dstack._internal.server.testing.common import (
|
|
10
|
+
ComputeMockSpec,
|
|
10
11
|
create_project,
|
|
11
12
|
create_user,
|
|
12
13
|
create_volume,
|
|
@@ -40,6 +41,7 @@ class TestProcessSubmittedVolumes:
|
|
|
40
41
|
) as m:
|
|
41
42
|
aws_mock = Mock()
|
|
42
43
|
m.return_value = aws_mock
|
|
44
|
+
aws_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
43
45
|
aws_mock.compute.return_value.create_volume.return_value = VolumeProvisioningData(
|
|
44
46
|
backend=BackendType.AWS,
|
|
45
47
|
volume_id="1234",
|
|
@@ -16,9 +16,9 @@ from dstack._internal.server.background.tasks.process_terminating_jobs import (
|
|
|
16
16
|
from dstack._internal.server.models import InstanceModel, JobModel, VolumeAttachmentModel
|
|
17
17
|
from dstack._internal.server.services.volumes import volume_model_to_volume
|
|
18
18
|
from dstack._internal.server.testing.common import (
|
|
19
|
+
ComputeMockSpec,
|
|
19
20
|
create_instance,
|
|
20
21
|
create_job,
|
|
21
|
-
create_pool,
|
|
22
22
|
create_project,
|
|
23
23
|
create_repo,
|
|
24
24
|
create_run,
|
|
@@ -39,11 +39,9 @@ class TestProcessTerminatingJobs:
|
|
|
39
39
|
async def test_terminates_job(self, session: AsyncSession):
|
|
40
40
|
project = await create_project(session=session)
|
|
41
41
|
user = await create_user(session=session)
|
|
42
|
-
pool = await create_pool(session=session, project=project)
|
|
43
42
|
instance = await create_instance(
|
|
44
43
|
session=session,
|
|
45
44
|
project=project,
|
|
46
|
-
pool=pool,
|
|
47
45
|
status=InstanceStatus.BUSY,
|
|
48
46
|
)
|
|
49
47
|
repo = await create_repo(session=session, project_id=project.id)
|
|
@@ -78,7 +76,6 @@ class TestProcessTerminatingJobs:
|
|
|
78
76
|
async def test_detaches_job_volumes(self, session: AsyncSession):
|
|
79
77
|
project = await create_project(session=session)
|
|
80
78
|
user = await create_user(session=session)
|
|
81
|
-
pool = await create_pool(session=session, project=project)
|
|
82
79
|
volume = await create_volume(
|
|
83
80
|
session=session,
|
|
84
81
|
project=project,
|
|
@@ -90,7 +87,6 @@ class TestProcessTerminatingJobs:
|
|
|
90
87
|
instance = await create_instance(
|
|
91
88
|
session=session,
|
|
92
89
|
project=project,
|
|
93
|
-
pool=pool,
|
|
94
90
|
status=InstanceStatus.BUSY,
|
|
95
91
|
volumes=[volume],
|
|
96
92
|
)
|
|
@@ -114,6 +110,7 @@ class TestProcessTerminatingJobs:
|
|
|
114
110
|
with patch("dstack._internal.server.services.backends.get_project_backend_by_type") as m:
|
|
115
111
|
backend_mock = Mock()
|
|
116
112
|
m.return_value = backend_mock
|
|
113
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
117
114
|
backend_mock.compute.return_value.is_volume_detached.return_value = True
|
|
118
115
|
await process_terminating_jobs()
|
|
119
116
|
m.assert_awaited_once()
|
|
@@ -125,7 +122,6 @@ class TestProcessTerminatingJobs:
|
|
|
125
122
|
async def test_force_detaches_job_volumes(self, session: AsyncSession):
|
|
126
123
|
project = await create_project(session=session)
|
|
127
124
|
user = await create_user(session=session)
|
|
128
|
-
pool = await create_pool(session=session, project=project)
|
|
129
125
|
volume = await create_volume(
|
|
130
126
|
session=session,
|
|
131
127
|
project=project,
|
|
@@ -137,7 +133,6 @@ class TestProcessTerminatingJobs:
|
|
|
137
133
|
instance = await create_instance(
|
|
138
134
|
session=session,
|
|
139
135
|
project=project,
|
|
140
|
-
pool=pool,
|
|
141
136
|
status=InstanceStatus.BUSY,
|
|
142
137
|
volumes=[volume],
|
|
143
138
|
)
|
|
@@ -163,6 +158,7 @@ class TestProcessTerminatingJobs:
|
|
|
163
158
|
with patch("dstack._internal.server.services.backends.get_project_backend_by_type") as m:
|
|
164
159
|
backend_mock = Mock()
|
|
165
160
|
m.return_value = backend_mock
|
|
161
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
166
162
|
backend_mock.compute.return_value.is_volume_detached.return_value = False
|
|
167
163
|
await process_terminating_jobs()
|
|
168
164
|
m.assert_awaited_once()
|
|
@@ -188,6 +184,7 @@ class TestProcessTerminatingJobs:
|
|
|
188
184
|
) + timedelta(minutes=30)
|
|
189
185
|
backend_mock = Mock()
|
|
190
186
|
m.return_value = backend_mock
|
|
187
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
191
188
|
backend_mock.compute.return_value.is_volume_detached.return_value = False
|
|
192
189
|
await process_terminating_jobs()
|
|
193
190
|
m.assert_awaited_once()
|
|
@@ -205,6 +202,7 @@ class TestProcessTerminatingJobs:
|
|
|
205
202
|
with patch("dstack._internal.server.services.backends.get_project_backend_by_type") as m:
|
|
206
203
|
backend_mock = Mock()
|
|
207
204
|
m.return_value = backend_mock
|
|
205
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
208
206
|
backend_mock.compute.return_value.is_volume_detached.return_value = True
|
|
209
207
|
await process_terminating_jobs()
|
|
210
208
|
m.assert_awaited_once()
|
|
@@ -223,7 +221,6 @@ class TestProcessTerminatingJobs:
|
|
|
223
221
|
async def test_terminates_job_on_shared_instance(self, session: AsyncSession):
|
|
224
222
|
project = await create_project(session)
|
|
225
223
|
user = await create_user(session)
|
|
226
|
-
pool = await create_pool(session=session, project=project)
|
|
227
224
|
repo = await create_repo(
|
|
228
225
|
session=session,
|
|
229
226
|
project_id=project.id,
|
|
@@ -231,12 +228,10 @@ class TestProcessTerminatingJobs:
|
|
|
231
228
|
instance = await create_instance(
|
|
232
229
|
session=session,
|
|
233
230
|
project=project,
|
|
234
|
-
pool=pool,
|
|
235
231
|
status=InstanceStatus.BUSY,
|
|
236
232
|
total_blocks=4,
|
|
237
233
|
busy_blocks=3,
|
|
238
234
|
)
|
|
239
|
-
await session.refresh(pool)
|
|
240
235
|
run = await create_run(
|
|
241
236
|
session=session,
|
|
242
237
|
project=project,
|
|
@@ -270,7 +265,6 @@ class TestProcessTerminatingJobs:
|
|
|
270
265
|
async def test_detaches_job_volumes_on_shared_instance(self, session: AsyncSession):
|
|
271
266
|
project = await create_project(session=session)
|
|
272
267
|
user = await create_user(session=session)
|
|
273
|
-
pool = await create_pool(session=session, project=project)
|
|
274
268
|
volume_conf_1 = get_volume_configuration(name="vol-1")
|
|
275
269
|
volume_1 = await create_volume(
|
|
276
270
|
session=session,
|
|
@@ -294,7 +288,6 @@ class TestProcessTerminatingJobs:
|
|
|
294
288
|
instance = await create_instance(
|
|
295
289
|
session=session,
|
|
296
290
|
project=project,
|
|
297
|
-
pool=pool,
|
|
298
291
|
status=InstanceStatus.BUSY,
|
|
299
292
|
volumes=[volume_1, volume_2],
|
|
300
293
|
)
|
|
@@ -319,13 +312,15 @@ class TestProcessTerminatingJobs:
|
|
|
319
312
|
with patch("dstack._internal.server.services.backends.get_project_backend_by_type") as m:
|
|
320
313
|
backend_mock = Mock()
|
|
321
314
|
m.return_value = backend_mock
|
|
315
|
+
backend_mock.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
322
316
|
backend_mock.compute.return_value.is_volume_detached.return_value = True
|
|
323
317
|
|
|
324
318
|
await process_terminating_jobs()
|
|
325
319
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
320
|
+
m.assert_awaited_once()
|
|
321
|
+
backend_mock.compute.return_value.detach_volume.assert_called_once()
|
|
322
|
+
backend_mock.compute.return_value.is_volume_detached.assert_called_once()
|
|
323
|
+
|
|
329
324
|
await session.refresh(job)
|
|
330
325
|
await session.refresh(instance)
|
|
331
326
|
assert job.status == JobStatus.TERMINATED
|