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
|
@@ -8,6 +8,16 @@ from uuid import UUID
|
|
|
8
8
|
import gpuhunt
|
|
9
9
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
10
10
|
|
|
11
|
+
from dstack._internal.core.backends.base.compute import (
|
|
12
|
+
Compute,
|
|
13
|
+
ComputeWithCreateInstanceSupport,
|
|
14
|
+
ComputeWithGatewaySupport,
|
|
15
|
+
ComputeWithMultinodeSupport,
|
|
16
|
+
ComputeWithPlacementGroupSupport,
|
|
17
|
+
ComputeWithPrivateGatewaySupport,
|
|
18
|
+
ComputeWithReservationSupport,
|
|
19
|
+
ComputeWithVolumeSupport,
|
|
20
|
+
)
|
|
11
21
|
from dstack._internal.core.models.backends.base import BackendType
|
|
12
22
|
from dstack._internal.core.models.common import NetworkMode
|
|
13
23
|
from dstack._internal.core.models.configurations import (
|
|
@@ -35,8 +45,7 @@ from dstack._internal.core.models.placement import (
|
|
|
35
45
|
PlacementStrategy,
|
|
36
46
|
)
|
|
37
47
|
from dstack._internal.core.models.profiles import (
|
|
38
|
-
|
|
39
|
-
DEFAULT_POOL_TERMINATION_IDLE_TIME,
|
|
48
|
+
DEFAULT_FLEET_TERMINATION_IDLE_TIME,
|
|
40
49
|
Profile,
|
|
41
50
|
TerminationPolicy,
|
|
42
51
|
)
|
|
@@ -71,7 +80,6 @@ from dstack._internal.server.models import (
|
|
|
71
80
|
JobModel,
|
|
72
81
|
JobPrometheusMetrics,
|
|
73
82
|
PlacementGroupModel,
|
|
74
|
-
PoolModel,
|
|
75
83
|
ProjectModel,
|
|
76
84
|
RepoCredsModel,
|
|
77
85
|
RepoModel,
|
|
@@ -181,9 +189,6 @@ async def create_repo(
|
|
|
181
189
|
if info is None:
|
|
182
190
|
info = {
|
|
183
191
|
"repo_type": "remote",
|
|
184
|
-
"repo_host_name": "",
|
|
185
|
-
"repo_port": None,
|
|
186
|
-
"repo_user_name": "",
|
|
187
192
|
"repo_name": "dstack",
|
|
188
193
|
}
|
|
189
194
|
repo = RepoModel(
|
|
@@ -206,7 +211,6 @@ async def create_repo_creds(
|
|
|
206
211
|
) -> RepoCredsModel:
|
|
207
212
|
if creds is None:
|
|
208
213
|
creds = {
|
|
209
|
-
"protocol": "https",
|
|
210
214
|
"clone_url": "https://github.com/dstackai/dstack.git",
|
|
211
215
|
"private_key": None,
|
|
212
216
|
"oauth_token": "test_token",
|
|
@@ -325,13 +329,22 @@ def get_job_provisioning_data(
|
|
|
325
329
|
backend: BackendType = BackendType.AWS,
|
|
326
330
|
region: str = "us-east-1",
|
|
327
331
|
gpu_count: int = 0,
|
|
332
|
+
gpu_memory_gib: float = 16,
|
|
333
|
+
gpu_name: str = "T4",
|
|
328
334
|
cpu_count: int = 1,
|
|
329
335
|
memory_gib: float = 0.5,
|
|
330
336
|
spot: bool = False,
|
|
331
337
|
hostname: str = "127.0.0.4",
|
|
332
338
|
internal_ip: Optional[str] = "127.0.0.4",
|
|
339
|
+
price: float = 10.5,
|
|
333
340
|
) -> JobProvisioningData:
|
|
334
|
-
gpus = [
|
|
341
|
+
gpus = [
|
|
342
|
+
Gpu(
|
|
343
|
+
name=gpu_name,
|
|
344
|
+
memory_mib=int(gpu_memory_gib * 1024),
|
|
345
|
+
vendor=gpuhunt.AcceleratorVendor.NVIDIA,
|
|
346
|
+
)
|
|
347
|
+
] * gpu_count
|
|
335
348
|
return JobProvisioningData(
|
|
336
349
|
backend=backend,
|
|
337
350
|
instance_type=InstanceType(
|
|
@@ -344,7 +357,7 @@ def get_job_provisioning_data(
|
|
|
344
357
|
hostname=hostname,
|
|
345
358
|
internal_ip=internal_ip,
|
|
346
359
|
region=region,
|
|
347
|
-
price=
|
|
360
|
+
price=price,
|
|
348
361
|
username="ubuntu",
|
|
349
362
|
ssh_port=22,
|
|
350
363
|
dockerized=dockerized,
|
|
@@ -439,22 +452,6 @@ def get_gateway_compute_configuration(
|
|
|
439
452
|
)
|
|
440
453
|
|
|
441
454
|
|
|
442
|
-
async def create_pool(
|
|
443
|
-
session: AsyncSession,
|
|
444
|
-
project: ProjectModel,
|
|
445
|
-
pool_name: Optional[str] = None,
|
|
446
|
-
) -> PoolModel:
|
|
447
|
-
pool_name = pool_name if pool_name is not None else DEFAULT_POOL_NAME
|
|
448
|
-
pool = PoolModel(
|
|
449
|
-
name=pool_name,
|
|
450
|
-
project=project,
|
|
451
|
-
project_id=project.id,
|
|
452
|
-
)
|
|
453
|
-
session.add(pool)
|
|
454
|
-
await session.commit()
|
|
455
|
-
return pool
|
|
456
|
-
|
|
457
|
-
|
|
458
455
|
async def create_fleet(
|
|
459
456
|
session: AsyncSession,
|
|
460
457
|
project: ProjectModel,
|
|
@@ -463,11 +460,14 @@ async def create_fleet(
|
|
|
463
460
|
fleet_id: Optional[UUID] = None,
|
|
464
461
|
status: FleetStatus = FleetStatus.ACTIVE,
|
|
465
462
|
deleted: bool = False,
|
|
463
|
+
name: Optional[str] = None,
|
|
466
464
|
) -> FleetModel:
|
|
467
465
|
if fleet_id is None:
|
|
468
466
|
fleet_id = uuid.uuid4()
|
|
469
467
|
if spec is None:
|
|
470
468
|
spec = get_fleet_spec()
|
|
469
|
+
if name is not None:
|
|
470
|
+
spec.configuration.name = name
|
|
471
471
|
fm = FleetModel(
|
|
472
472
|
id=fleet_id,
|
|
473
473
|
project=project,
|
|
@@ -507,7 +507,6 @@ def get_fleet_configuration(
|
|
|
507
507
|
async def create_instance(
|
|
508
508
|
session: AsyncSession,
|
|
509
509
|
project: ProjectModel,
|
|
510
|
-
pool: PoolModel,
|
|
511
510
|
fleet: Optional[FleetModel] = None,
|
|
512
511
|
status: InstanceStatus = InstanceStatus.IDLE,
|
|
513
512
|
unreachable: bool = False,
|
|
@@ -522,7 +521,7 @@ async def create_instance(
|
|
|
522
521
|
instance_num: int = 0,
|
|
523
522
|
backend: BackendType = BackendType.DATACRUNCH,
|
|
524
523
|
termination_policy: Optional[TerminationPolicy] = None,
|
|
525
|
-
termination_idle_time: int =
|
|
524
|
+
termination_idle_time: int = DEFAULT_FLEET_TERMINATION_IDLE_TIME,
|
|
526
525
|
region: str = "eu-west",
|
|
527
526
|
remote_connection_info: Optional[RemoteConnectionInfo] = None,
|
|
528
527
|
offer: Optional[InstanceOfferWithAvailability] = None,
|
|
@@ -531,6 +530,7 @@ async def create_instance(
|
|
|
531
530
|
busy_blocks: int = 0,
|
|
532
531
|
name: str = "test_instance",
|
|
533
532
|
volumes: Optional[List[VolumeModel]] = None,
|
|
533
|
+
price: float = 1.0,
|
|
534
534
|
) -> InstanceModel:
|
|
535
535
|
if instance_id is None:
|
|
536
536
|
instance_id = uuid.uuid4()
|
|
@@ -564,7 +564,6 @@ async def create_instance(
|
|
|
564
564
|
id=instance_id,
|
|
565
565
|
name=name,
|
|
566
566
|
instance_num=instance_num,
|
|
567
|
-
pool=pool,
|
|
568
567
|
fleet=fleet,
|
|
569
568
|
project=project,
|
|
570
569
|
status=status,
|
|
@@ -574,7 +573,7 @@ async def create_instance(
|
|
|
574
573
|
finished_at=finished_at,
|
|
575
574
|
job_provisioning_data=job_provisioning_data.json(),
|
|
576
575
|
offer=offer.json(),
|
|
577
|
-
price=
|
|
576
|
+
price=price,
|
|
578
577
|
region=region,
|
|
579
578
|
backend=backend,
|
|
580
579
|
termination_policy=termination_policy,
|
|
@@ -611,6 +610,8 @@ def get_instance_offer_with_availability(
|
|
|
611
610
|
backend: BackendType = BackendType.AWS,
|
|
612
611
|
region: str = "eu-west",
|
|
613
612
|
gpu_count: int = 0,
|
|
613
|
+
gpu_name: str = "T4",
|
|
614
|
+
gpu_memory_gib: float = 16,
|
|
614
615
|
cpu_count: int = 2,
|
|
615
616
|
memory_gib: float = 12,
|
|
616
617
|
disk_gib: float = 100.0,
|
|
@@ -618,12 +619,20 @@ def get_instance_offer_with_availability(
|
|
|
618
619
|
blocks: int = 1,
|
|
619
620
|
total_blocks: int = 1,
|
|
620
621
|
availability_zones: Optional[List[str]] = None,
|
|
622
|
+
price: float = 1.0,
|
|
623
|
+
instance_type: str = "instance",
|
|
621
624
|
):
|
|
622
|
-
gpus = [
|
|
625
|
+
gpus = [
|
|
626
|
+
Gpu(
|
|
627
|
+
name=gpu_name,
|
|
628
|
+
memory_mib=int(gpu_memory_gib * 1024),
|
|
629
|
+
vendor=gpuhunt.AcceleratorVendor.NVIDIA,
|
|
630
|
+
)
|
|
631
|
+
] * gpu_count
|
|
623
632
|
return InstanceOfferWithAvailability(
|
|
624
633
|
backend=backend,
|
|
625
634
|
instance=InstanceType(
|
|
626
|
-
name=
|
|
635
|
+
name=instance_type,
|
|
627
636
|
resources=Resources(
|
|
628
637
|
cpus=cpu_count,
|
|
629
638
|
memory_mib=int(memory_gib * 1024),
|
|
@@ -634,7 +643,7 @@ def get_instance_offer_with_availability(
|
|
|
634
643
|
),
|
|
635
644
|
),
|
|
636
645
|
region=region,
|
|
637
|
-
price=
|
|
646
|
+
price=price,
|
|
638
647
|
availability=InstanceAvailability.AVAILABLE,
|
|
639
648
|
availability_zones=availability_zones,
|
|
640
649
|
blocks=blocks,
|
|
@@ -947,3 +956,20 @@ class AsyncContextManager:
|
|
|
947
956
|
|
|
948
957
|
async def __aexit__(self, exc_type, exc, traceback):
|
|
949
958
|
pass
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
class ComputeMockSpec(
|
|
962
|
+
Compute,
|
|
963
|
+
ComputeWithCreateInstanceSupport,
|
|
964
|
+
ComputeWithMultinodeSupport,
|
|
965
|
+
ComputeWithReservationSupport,
|
|
966
|
+
ComputeWithPlacementGroupSupport,
|
|
967
|
+
ComputeWithGatewaySupport,
|
|
968
|
+
ComputeWithPrivateGatewaySupport,
|
|
969
|
+
ComputeWithVolumeSupport,
|
|
970
|
+
):
|
|
971
|
+
"""
|
|
972
|
+
Can be used to create Compute mocks that pass all isinstance asserts.
|
|
973
|
+
"""
|
|
974
|
+
|
|
975
|
+
pass
|
dstack/_internal/utils/ssh.py
CHANGED
|
@@ -128,7 +128,8 @@ def include_ssh_config(path: PathLike, ssh_config_path: PathLike = default_ssh_c
|
|
|
128
128
|
except PermissionError:
|
|
129
129
|
logger.warning(
|
|
130
130
|
f"Couldn't update `{ssh_config_path}` due to a permissions problem.\n"
|
|
131
|
-
f"The `vscode://vscode-remote/ssh-remote+<run name>/workflow`
|
|
131
|
+
f"The `vscode://vscode-remote/ssh-remote+<run name>/workflow` and "
|
|
132
|
+
f"`cursor://vscode-remote/ssh-remote+<run name>/workflow` links and "
|
|
132
133
|
f"the `ssh <run name>` command won't work.\n"
|
|
133
134
|
f"To fix this, make sure `{ssh_config_path}` is writable, or add "
|
|
134
135
|
f"`Include {path}` to the top of `{ssh_config_path}` manually.",
|
dstack/api/__init__.py
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
from dstack._internal.core.errors import ClientError
|
|
3
3
|
from dstack._internal.core.models.backends.base import BackendType
|
|
4
4
|
from dstack._internal.core.models.common import RegistryAuth
|
|
5
|
+
from dstack._internal.core.models.configurations import (
|
|
6
|
+
DevEnvironmentConfiguration as _DevEnvironmentConfiguration,
|
|
7
|
+
)
|
|
5
8
|
from dstack._internal.core.models.configurations import ScalingSpec as Scaling
|
|
6
9
|
from dstack._internal.core.models.configurations import (
|
|
7
10
|
ServiceConfiguration as _ServiceConfiguration,
|
|
@@ -22,3 +25,4 @@ from dstack.api._public.runs import Run, RunStatus
|
|
|
22
25
|
|
|
23
26
|
Service = _ServiceConfiguration
|
|
24
27
|
Task = _TaskConfiguration
|
|
28
|
+
DevEnvironment = _DevEnvironmentConfiguration
|
dstack/api/_public/__init__.py
CHANGED
|
@@ -6,7 +6,6 @@ from dstack._internal.core.services.configs import ConfigManager
|
|
|
6
6
|
from dstack._internal.utils.logging import get_logger
|
|
7
7
|
from dstack._internal.utils.path import PathLike
|
|
8
8
|
from dstack.api._public.backends import BackendCollection
|
|
9
|
-
from dstack.api._public.pools import PoolCollection
|
|
10
9
|
from dstack.api._public.repos import RepoCollection, get_ssh_keypair
|
|
11
10
|
from dstack.api._public.runs import RunCollection
|
|
12
11
|
from dstack.api.server import APIClient
|
|
@@ -16,12 +15,14 @@ logger = get_logger(__name__)
|
|
|
16
15
|
|
|
17
16
|
class Client:
|
|
18
17
|
"""
|
|
19
|
-
High-level API client for interacting with dstack server
|
|
18
|
+
High-level API client for interacting with the `dstack` server
|
|
20
19
|
|
|
21
20
|
Attributes:
|
|
21
|
+
project: The project name.
|
|
22
22
|
runs: Operations with runs.
|
|
23
23
|
repos: Operations with repositories.
|
|
24
24
|
backends: Operations with backends.
|
|
25
|
+
client: Low-level API client that supports all API endpoints.
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
28
|
def __init__(
|
|
@@ -41,7 +42,6 @@ class Client:
|
|
|
41
42
|
self._repos = RepoCollection(api_client, project_name)
|
|
42
43
|
self._backends = BackendCollection(api_client, project_name)
|
|
43
44
|
self._runs = RunCollection(api_client, project_name, self)
|
|
44
|
-
self._pool = PoolCollection(api_client, project_name)
|
|
45
45
|
if ssh_identity_file:
|
|
46
46
|
self.ssh_identity_file = str(ssh_identity_file)
|
|
47
47
|
else:
|
|
@@ -58,13 +58,13 @@ class Client:
|
|
|
58
58
|
Creates a Client using the default configuration from `~/.dstack/config.yml` if it exists.
|
|
59
59
|
|
|
60
60
|
Args:
|
|
61
|
-
project_name: The name of the project
|
|
62
|
-
server_url: The dstack server URL (e.g. `http://localhost:3000/` or `https://sky.dstack.ai`)
|
|
63
|
-
user_token: The dstack user token
|
|
64
|
-
ssh_identity_file: The private SSH key path for SSH tunneling
|
|
61
|
+
project_name: The name of the project. required if `server_url` and `user_token` are specified.
|
|
62
|
+
server_url: The dstack server URL (e.g. `http://localhost:3000/` or `https://sky.dstack.ai`).
|
|
63
|
+
user_token: The dstack user token.
|
|
64
|
+
ssh_identity_file: The private SSH key path for SSH tunneling.
|
|
65
65
|
|
|
66
66
|
Returns:
|
|
67
|
-
A client instance
|
|
67
|
+
A client instance.
|
|
68
68
|
"""
|
|
69
69
|
if server_url is not None and user_token is not None:
|
|
70
70
|
if project_name is None:
|
|
@@ -79,25 +79,21 @@ class Client:
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
@property
|
|
82
|
-
def
|
|
83
|
-
return self.
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
def backends(self) -> BackendCollection:
|
|
87
|
-
return self._backends
|
|
82
|
+
def project(self) -> str:
|
|
83
|
+
return self._project
|
|
88
84
|
|
|
89
85
|
@property
|
|
90
86
|
def runs(self) -> RunCollection:
|
|
91
87
|
return self._runs
|
|
92
88
|
|
|
93
89
|
@property
|
|
94
|
-
def
|
|
95
|
-
return self.
|
|
90
|
+
def repos(self) -> RepoCollection:
|
|
91
|
+
return self._repos
|
|
96
92
|
|
|
97
93
|
@property
|
|
98
|
-
def
|
|
99
|
-
return self.
|
|
94
|
+
def backends(self) -> BackendCollection:
|
|
95
|
+
return self._backends
|
|
100
96
|
|
|
101
97
|
@property
|
|
102
|
-
def
|
|
103
|
-
return self.
|
|
98
|
+
def client(self) -> APIClient:
|
|
99
|
+
return self._client
|
dstack/api/_public/backends.py
CHANGED
dstack/api/_public/repos.py
CHANGED
|
@@ -55,7 +55,7 @@ class RepoCollection:
|
|
|
55
55
|
Once the repo is initialized, you can pass the repo object to the run:
|
|
56
56
|
|
|
57
57
|
```python
|
|
58
|
-
run = client.runs.
|
|
58
|
+
run = client.runs.apply_configuration(
|
|
59
59
|
configuration=...,
|
|
60
60
|
repo=repo,
|
|
61
61
|
)
|
|
@@ -78,25 +78,6 @@ class RepoCollection:
|
|
|
78
78
|
raise ConfigurationError(*e.args)
|
|
79
79
|
self._api_client.repos.init(self._project, repo.repo_id, repo.get_repo_info(), creds)
|
|
80
80
|
|
|
81
|
-
def is_initialized(
|
|
82
|
-
self,
|
|
83
|
-
repo: Repo,
|
|
84
|
-
) -> bool:
|
|
85
|
-
# """
|
|
86
|
-
# Checks if the remote repo is initialized in the project
|
|
87
|
-
#
|
|
88
|
-
# Args:
|
|
89
|
-
# repo: repo to check
|
|
90
|
-
#
|
|
91
|
-
# Returns:
|
|
92
|
-
# repo is initialized
|
|
93
|
-
# """
|
|
94
|
-
try:
|
|
95
|
-
self._api_client.repos.get(self._project, repo.repo_id, include_creds=False)
|
|
96
|
-
return True
|
|
97
|
-
except ResourceNotExistsError:
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
81
|
def load(
|
|
101
82
|
self,
|
|
102
83
|
repo_dir: PathLike,
|
|
@@ -105,22 +86,22 @@ class RepoCollection:
|
|
|
105
86
|
git_identity_file: Optional[PathLike] = None,
|
|
106
87
|
oauth_token: Optional[str] = None,
|
|
107
88
|
) -> Union[RemoteRepo, LocalRepo]:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
89
|
+
"""
|
|
90
|
+
Loads the repo from the local directory using global config
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
repo_dir: Repo root directory.
|
|
94
|
+
local: Do not try to load `RemoteRepo` first.
|
|
95
|
+
init: Initialize the repo if it's not initialized.
|
|
96
|
+
git_identity_file: Path to an SSH private key to access the remote repo.
|
|
97
|
+
oauth_token: GitHub OAuth token to access the remote repo.
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ConfigurationError: If the repo is not initialized and `init` is `False`.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
repo: Initialized repo.
|
|
104
|
+
"""
|
|
124
105
|
config = ConfigManager()
|
|
125
106
|
if not init:
|
|
126
107
|
logger.debug("Loading repo config")
|
|
@@ -155,6 +136,25 @@ class RepoCollection:
|
|
|
155
136
|
)
|
|
156
137
|
return repo
|
|
157
138
|
|
|
139
|
+
def is_initialized(
|
|
140
|
+
self,
|
|
141
|
+
repo: Repo,
|
|
142
|
+
) -> bool:
|
|
143
|
+
"""
|
|
144
|
+
Checks if the remote repo is initialized in the project
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
repo: The repo to check.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Whether the repo is initialized or not.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
self._api_client.repos.get(self._project, repo.repo_id, include_creds=False)
|
|
154
|
+
return True
|
|
155
|
+
except ResourceNotExistsError:
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
158
|
|
|
159
159
|
def get_ssh_keypair(key_path: Optional[PathLike], dstack_key_path: Path) -> str:
|
|
160
160
|
"""Returns a path to the private key"""
|