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
dstack/api/_public/runs.py
CHANGED
|
@@ -16,9 +16,7 @@ import dstack.api as api
|
|
|
16
16
|
from dstack._internal.core.consts import DSTACK_RUNNER_HTTP_PORT, DSTACK_RUNNER_SSH_PORT
|
|
17
17
|
from dstack._internal.core.errors import ClientError, ConfigurationError, ResourceNotExistsError
|
|
18
18
|
from dstack._internal.core.models.backends.base import BackendType
|
|
19
|
-
from dstack._internal.core.models.common import ApplyAction
|
|
20
19
|
from dstack._internal.core.models.configurations import AnyRunConfiguration, PortMapping
|
|
21
|
-
from dstack._internal.core.models.pools import Instance
|
|
22
20
|
from dstack._internal.core.models.profiles import (
|
|
23
21
|
CreationPolicy,
|
|
24
22
|
Profile,
|
|
@@ -28,12 +26,11 @@ from dstack._internal.core.models.profiles import (
|
|
|
28
26
|
UtilizationPolicy,
|
|
29
27
|
)
|
|
30
28
|
from dstack._internal.core.models.repos.base import Repo
|
|
29
|
+
from dstack._internal.core.models.repos.virtual import VirtualRepo
|
|
31
30
|
from dstack._internal.core.models.resources import ResourcesSpec
|
|
32
31
|
from dstack._internal.core.models.runs import (
|
|
33
32
|
Job,
|
|
34
33
|
JobSpec,
|
|
35
|
-
PoolInstanceOffers,
|
|
36
|
-
Requirements,
|
|
37
34
|
RunPlan,
|
|
38
35
|
RunSpec,
|
|
39
36
|
RunStatus,
|
|
@@ -191,14 +188,14 @@ class Run(ABC):
|
|
|
191
188
|
job_num: int = 0,
|
|
192
189
|
) -> Iterable[bytes]:
|
|
193
190
|
"""
|
|
194
|
-
Iterate through run's log messages
|
|
191
|
+
Iterate through run's log messages.
|
|
195
192
|
|
|
196
193
|
Args:
|
|
197
|
-
start_time:
|
|
198
|
-
diagnose:
|
|
194
|
+
start_time: Minimal log timestamp.
|
|
195
|
+
diagnose: Return runner logs if `True`.
|
|
199
196
|
|
|
200
197
|
Yields:
|
|
201
|
-
|
|
198
|
+
Log messages.
|
|
202
199
|
"""
|
|
203
200
|
if diagnose is False and self._ssh_attach is not None:
|
|
204
201
|
yield from self._attached_logs()
|
|
@@ -228,17 +225,17 @@ class Run(ABC):
|
|
|
228
225
|
|
|
229
226
|
def refresh(self):
|
|
230
227
|
"""
|
|
231
|
-
Get up-to-date run info
|
|
228
|
+
Get up-to-date run info.
|
|
232
229
|
"""
|
|
233
230
|
self._run = self._api_client.runs.get(self._project, self._run.run_spec.run_name)
|
|
234
231
|
logger.debug("Refreshed run %s: %s", self.name, self.status)
|
|
235
232
|
|
|
236
233
|
def stop(self, abort: bool = False):
|
|
237
234
|
"""
|
|
238
|
-
Terminate the instance and detach
|
|
235
|
+
Terminate the instance and detach.
|
|
239
236
|
|
|
240
237
|
Args:
|
|
241
|
-
abort:
|
|
238
|
+
abort: Gracefully stop the run if `False`.
|
|
242
239
|
"""
|
|
243
240
|
self._api_client.runs.stop(self._project, [self.name], abort)
|
|
244
241
|
logger.debug("%s run %s", "Aborted" if abort else "Stopped", self.name)
|
|
@@ -256,7 +253,7 @@ class Run(ABC):
|
|
|
256
253
|
Establish an SSH tunnel to the instance and update SSH config
|
|
257
254
|
|
|
258
255
|
Args:
|
|
259
|
-
ssh_identity_file: SSH keypair to access instances
|
|
256
|
+
ssh_identity_file: SSH keypair to access instances.
|
|
260
257
|
|
|
261
258
|
Raises:
|
|
262
259
|
dstack.api.PortUsedError: If ports are in use or the run is attached by another process.
|
|
@@ -393,7 +390,7 @@ class ServiceModel:
|
|
|
393
390
|
|
|
394
391
|
class RunCollection:
|
|
395
392
|
"""
|
|
396
|
-
Operations with runs
|
|
393
|
+
Operations with runs.
|
|
397
394
|
"""
|
|
398
395
|
|
|
399
396
|
def __init__(
|
|
@@ -406,6 +403,122 @@ class RunCollection:
|
|
|
406
403
|
self._project = project
|
|
407
404
|
self._client = client
|
|
408
405
|
|
|
406
|
+
def get_run_plan(
|
|
407
|
+
self,
|
|
408
|
+
configuration: AnyRunConfiguration,
|
|
409
|
+
repo: Optional[Repo] = None,
|
|
410
|
+
profile: Optional[Profile] = None,
|
|
411
|
+
configuration_path: Optional[str] = None,
|
|
412
|
+
) -> RunPlan:
|
|
413
|
+
"""
|
|
414
|
+
Get a run plan.
|
|
415
|
+
Use this method to see the run plan before applying the cofiguration.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
configuration (Union[Task, Service, DevEnvironment]): The run configuration.
|
|
419
|
+
repo (Union[LocalRepo, RemoteRepo, VirtualRepo, None]):
|
|
420
|
+
The repo to use for the run. Pass `None` if repo is not needed.
|
|
421
|
+
profile: The profile to use for the run.
|
|
422
|
+
configuration_path: The path to the configuration file. Omit if the configuration is not loaded from a file.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Run plan.
|
|
426
|
+
"""
|
|
427
|
+
if repo is None:
|
|
428
|
+
repo = VirtualRepo()
|
|
429
|
+
|
|
430
|
+
run_spec = RunSpec(
|
|
431
|
+
run_name=configuration.name,
|
|
432
|
+
repo_id=repo.repo_id,
|
|
433
|
+
repo_data=repo.run_repo_data,
|
|
434
|
+
repo_code_hash=None, # `apply_plan` will fill it
|
|
435
|
+
working_dir=configuration.working_dir,
|
|
436
|
+
configuration_path=configuration_path,
|
|
437
|
+
configuration=configuration,
|
|
438
|
+
profile=profile,
|
|
439
|
+
ssh_key_pub=Path(self._client.ssh_identity_file + ".pub").read_text().strip(),
|
|
440
|
+
)
|
|
441
|
+
logger.debug("Getting run plan")
|
|
442
|
+
run_plan = self._api_client.runs.get_plan(self._project, run_spec)
|
|
443
|
+
return run_plan
|
|
444
|
+
|
|
445
|
+
def apply_plan(
|
|
446
|
+
self,
|
|
447
|
+
run_plan: RunPlan,
|
|
448
|
+
repo: Optional[Repo] = None,
|
|
449
|
+
reserve_ports: bool = True,
|
|
450
|
+
) -> Run:
|
|
451
|
+
"""
|
|
452
|
+
Apply the run plan.
|
|
453
|
+
Use this method to apply run plans returned by `get_run_plan`.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
run_plan: The result of `get_run_plan` call.
|
|
457
|
+
repo (Union[LocalRepo, RemoteRepo, VirtualRepo, None]):
|
|
458
|
+
The repo to use for the run. Should be the same repo that is passed to `get_run_plan`.
|
|
459
|
+
reserve_ports: Reserve local ports before applying. Use if you'll attach to the run.
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
Submitted run.
|
|
463
|
+
"""
|
|
464
|
+
ports_lock = None
|
|
465
|
+
if reserve_ports:
|
|
466
|
+
# TODO handle multiple jobs
|
|
467
|
+
ports_lock = _reserve_ports(run_plan.job_plans[0].job_spec)
|
|
468
|
+
|
|
469
|
+
if repo is None:
|
|
470
|
+
repo = VirtualRepo()
|
|
471
|
+
else:
|
|
472
|
+
# Do not upload the diff without a repo (a default virtual repo)
|
|
473
|
+
# since upload_code() requires a repo to be initialized.
|
|
474
|
+
with tempfile.TemporaryFile("w+b") as fp:
|
|
475
|
+
run_plan.run_spec.repo_code_hash = repo.write_code_file(fp)
|
|
476
|
+
fp.seek(0)
|
|
477
|
+
self._api_client.repos.upload_code(
|
|
478
|
+
project_name=self._project,
|
|
479
|
+
repo_id=repo.repo_id,
|
|
480
|
+
code_hash=run_plan.run_spec.repo_code_hash,
|
|
481
|
+
fp=fp,
|
|
482
|
+
)
|
|
483
|
+
run = self._api_client.runs.apply_plan(self._project, run_plan)
|
|
484
|
+
return self._model_to_submitted_run(run, ports_lock)
|
|
485
|
+
|
|
486
|
+
def apply_configuration(
|
|
487
|
+
self,
|
|
488
|
+
configuration: AnyRunConfiguration,
|
|
489
|
+
repo: Optional[Repo] = None,
|
|
490
|
+
profile: Optional[Profile] = None,
|
|
491
|
+
configuration_path: Optional[str] = None,
|
|
492
|
+
reserve_ports: bool = True,
|
|
493
|
+
) -> Run:
|
|
494
|
+
"""
|
|
495
|
+
Apply the run configuration.
|
|
496
|
+
Use this method to apply configurations without getting a run plan first.
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
configuration (Union[Task, Service, DevEnvironment]): The run configuration.
|
|
500
|
+
repo (Union[LocalRepo, RemoteRepo, VirtualRepo, None]):
|
|
501
|
+
The repo to use for the run. Pass `None` if repo is not needed.
|
|
502
|
+
profile: The profile to use for the run.
|
|
503
|
+
configuration_path: The path to the configuration file. Omit if the configuration is not loaded from a file.
|
|
504
|
+
reserve_ports: Reserve local ports before applying. Use if you'll attach to the run.
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Submitted run.
|
|
508
|
+
"""
|
|
509
|
+
run_plan = self.get_run_plan(
|
|
510
|
+
configuration=configuration,
|
|
511
|
+
repo=repo,
|
|
512
|
+
profile=profile,
|
|
513
|
+
configuration_path=configuration_path,
|
|
514
|
+
)
|
|
515
|
+
run = self.apply_plan(
|
|
516
|
+
run_plan=run_plan,
|
|
517
|
+
repo=repo,
|
|
518
|
+
reserve_ports=reserve_ports,
|
|
519
|
+
)
|
|
520
|
+
return run
|
|
521
|
+
|
|
409
522
|
def submit(
|
|
410
523
|
self,
|
|
411
524
|
configuration: AnyRunConfiguration,
|
|
@@ -423,31 +536,30 @@ class RunCollection:
|
|
|
423
536
|
run_name: Optional[str] = None,
|
|
424
537
|
reserve_ports: bool = True,
|
|
425
538
|
) -> Run:
|
|
426
|
-
"""
|
|
427
|
-
Submit a run
|
|
539
|
+
# """
|
|
540
|
+
# Submit a run
|
|
428
541
|
|
|
429
|
-
Args:
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
542
|
+
# Args:
|
|
543
|
+
# configuration (Union[Task, Service]): A run configuration.
|
|
544
|
+
# configuration_path: The path to the configuration file, relative to the root directory of the repo.
|
|
545
|
+
# repo (Union[LocalRepo, RemoteRepo, VirtualRepo]): A repo to mount to the run.
|
|
546
|
+
# backends: A list of allowed backend for provisioning.
|
|
547
|
+
# regions: A list of cloud regions for provisioning.
|
|
548
|
+
# resources: The requirements to run the configuration. Overrides the configuration's resources.
|
|
549
|
+
# spot_policy: A spot policy for provisioning.
|
|
550
|
+
# retry_policy (RetryPolicy): A retry policy.
|
|
551
|
+
# max_duration: The max instance running duration in seconds.
|
|
552
|
+
# max_price: The max instance price in dollars per hour for provisioning.
|
|
553
|
+
# working_dir: A working directory relative to the repo root directory
|
|
554
|
+
# run_name: A desired name of the run. Must be unique in the project. If not specified, a random name is assigned.
|
|
555
|
+
# reserve_ports: Whether local ports should be reserved in advance.
|
|
443
556
|
|
|
444
|
-
Returns:
|
|
445
|
-
|
|
446
|
-
"""
|
|
557
|
+
# Returns:
|
|
558
|
+
# Submitted run.
|
|
559
|
+
# """
|
|
560
|
+
logger.warning("The submit() method is deprecated in favor of apply_configuration().")
|
|
447
561
|
if repo is None:
|
|
448
|
-
repo =
|
|
449
|
-
if repo is None:
|
|
450
|
-
raise ConfigurationError("Repo is required for this type of configuration")
|
|
562
|
+
repo = VirtualRepo()
|
|
451
563
|
# TODO: Add Git credentials to RemoteRepo and if they are set, pass them here to RepoCollection.init
|
|
452
564
|
self._client.repos.init(repo)
|
|
453
565
|
|
|
@@ -468,18 +580,14 @@ class RunCollection:
|
|
|
468
580
|
)
|
|
469
581
|
return self.exec_plan(run_plan, repo, reserve_ports=reserve_ports)
|
|
470
582
|
|
|
471
|
-
|
|
472
|
-
return self._api_client.runs.get_offers(self._project, profile, requirements)
|
|
473
|
-
|
|
474
|
-
def create_instance(self, profile: Profile, requirements: Requirements) -> Instance:
|
|
475
|
-
return self._api_client.runs.create_instance(self._project, profile, requirements)
|
|
476
|
-
|
|
477
|
-
# TODO: [Andrey] I guess we need to drop profile-related fields (currently retry is not reflected there)
|
|
583
|
+
# Deprecated in favor of get_run_plan()
|
|
478
584
|
def get_plan(
|
|
479
585
|
self,
|
|
480
586
|
configuration: AnyRunConfiguration,
|
|
481
587
|
repo: Optional[Repo] = None,
|
|
482
588
|
configuration_path: Optional[str] = None,
|
|
589
|
+
# Unused profile args are deprecated and removed but
|
|
590
|
+
# kept for signature backward compatibility.
|
|
483
591
|
backends: Optional[List[BackendType]] = None,
|
|
484
592
|
regions: Optional[List[str]] = None,
|
|
485
593
|
instance_types: Optional[List[str]] = None,
|
|
@@ -506,11 +614,9 @@ class RunCollection:
|
|
|
506
614
|
# Returns:
|
|
507
615
|
# run plan
|
|
508
616
|
# """
|
|
509
|
-
|
|
617
|
+
logger.warning("The get_plan() method is deprecated in favor of get_run_plan().")
|
|
510
618
|
if repo is None:
|
|
511
|
-
repo =
|
|
512
|
-
if repo is None:
|
|
513
|
-
raise ConfigurationError("Repo is required for this type of configuration")
|
|
619
|
+
repo = VirtualRepo()
|
|
514
620
|
|
|
515
621
|
if working_dir is None:
|
|
516
622
|
working_dir = "."
|
|
@@ -536,17 +642,12 @@ class RunCollection:
|
|
|
536
642
|
reservation=reservation,
|
|
537
643
|
spot_policy=spot_policy,
|
|
538
644
|
retry=None,
|
|
539
|
-
retry_policy=retry_policy,
|
|
540
645
|
utilization_policy=utilization_policy,
|
|
541
646
|
max_duration=max_duration,
|
|
542
647
|
stop_duration=stop_duration,
|
|
543
648
|
max_price=max_price,
|
|
544
|
-
pool_name=pool_name,
|
|
545
|
-
instance_name=instance_name,
|
|
546
649
|
creation_policy=creation_policy,
|
|
547
650
|
idle_duration=idle_duration,
|
|
548
|
-
termination_policy=termination_policy,
|
|
549
|
-
termination_idle_time=termination_policy_idle,
|
|
550
651
|
)
|
|
551
652
|
run_spec = RunSpec(
|
|
552
653
|
run_name=run_name,
|
|
@@ -577,45 +678,28 @@ class RunCollection:
|
|
|
577
678
|
reserve_ports: bool = True,
|
|
578
679
|
) -> Run:
|
|
579
680
|
# """
|
|
580
|
-
# Execute run plan
|
|
581
|
-
|
|
681
|
+
# Execute the run plan.
|
|
682
|
+
|
|
582
683
|
# Args:
|
|
583
|
-
# run_plan:
|
|
584
|
-
# repo:
|
|
585
|
-
# reserve_ports:
|
|
586
|
-
|
|
684
|
+
# run_plan: Result of `get_run_plan` call.
|
|
685
|
+
# repo: Repo to use for the run.
|
|
686
|
+
# reserve_ports: Reserve local ports before submit.
|
|
687
|
+
|
|
587
688
|
# Returns:
|
|
588
|
-
#
|
|
689
|
+
# Submitted run.
|
|
589
690
|
# """
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
# TODO handle multiple jobs
|
|
593
|
-
ports_lock = _reserve_ports(run_plan.job_plans[0].job_spec)
|
|
594
|
-
|
|
595
|
-
with tempfile.TemporaryFile("w+b") as fp:
|
|
596
|
-
run_plan.run_spec.repo_code_hash = repo.write_code_file(fp)
|
|
597
|
-
fp.seek(0)
|
|
598
|
-
self._api_client.repos.upload_code(
|
|
599
|
-
self._project, repo.repo_id, run_plan.run_spec.repo_code_hash, fp
|
|
600
|
-
)
|
|
601
|
-
# Calling submit when action is CREATE since apply_plan is not backward-compatible.
|
|
602
|
-
# Otherwise, apply_plan can replace submit, i.e. it creates the run if it does not exist.
|
|
603
|
-
# TODO: Remove in 0.19
|
|
604
|
-
if run_plan.action == ApplyAction.UPDATE:
|
|
605
|
-
run = self._api_client.runs.apply_plan(self._project, run_plan)
|
|
606
|
-
else:
|
|
607
|
-
run = self._api_client.runs.submit(self._project, run_plan.run_spec)
|
|
608
|
-
return self._model_to_submitted_run(run, ports_lock)
|
|
691
|
+
logger.warning("The exec_plan() method is deprecated in favor of apply_plan().")
|
|
692
|
+
return self.apply_plan(run_plan=run_plan, repo=repo, reserve_ports=reserve_ports)
|
|
609
693
|
|
|
610
694
|
def list(self, all: bool = False) -> List[Run]:
|
|
611
695
|
"""
|
|
612
|
-
List runs
|
|
696
|
+
List runs.
|
|
613
697
|
|
|
614
698
|
Args:
|
|
615
|
-
all:
|
|
699
|
+
all: Show all runs (active and finished) if `True`.
|
|
616
700
|
|
|
617
701
|
Returns:
|
|
618
|
-
|
|
702
|
+
List of runs.
|
|
619
703
|
"""
|
|
620
704
|
# Return only one page of latest runs (<=100). Returning all the pages may be costly.
|
|
621
705
|
# TODO: Consider introducing `since` filter with a reasonable default.
|
|
@@ -634,13 +718,13 @@ class RunCollection:
|
|
|
634
718
|
|
|
635
719
|
def get(self, run_name: str) -> Optional[Run]:
|
|
636
720
|
"""
|
|
637
|
-
Get run by run name
|
|
721
|
+
Get run by run name.
|
|
638
722
|
|
|
639
723
|
Args:
|
|
640
|
-
run_name:
|
|
724
|
+
run_name: Run name.
|
|
641
725
|
|
|
642
726
|
Returns:
|
|
643
|
-
The run or `None` if not found
|
|
727
|
+
The run or `None` if not found.
|
|
644
728
|
"""
|
|
645
729
|
try:
|
|
646
730
|
run = self._api_client.runs.get(self._project, run_name)
|
dstack/api/server/__init__.py
CHANGED
|
@@ -13,7 +13,6 @@ from dstack.api.server._fleets import FleetsAPIClient
|
|
|
13
13
|
from dstack.api.server._gateways import GatewaysAPIClient
|
|
14
14
|
from dstack.api.server._logs import LogsAPIClient
|
|
15
15
|
from dstack.api.server._metrics import MetricsAPIClient
|
|
16
|
-
from dstack.api.server._pools import PoolAPIClient
|
|
17
16
|
from dstack.api.server._projects import ProjectsAPIClient
|
|
18
17
|
from dstack.api.server._repos import ReposAPIClient
|
|
19
18
|
from dstack.api.server._runs import RunsAPIClient
|
|
@@ -30,23 +29,26 @@ _RETRY_INTERVAL = 1
|
|
|
30
29
|
|
|
31
30
|
class APIClient:
|
|
32
31
|
"""
|
|
33
|
-
Low-level API client for interacting with dstack server.
|
|
32
|
+
Low-level API client for interacting with the `dstack` server.
|
|
33
|
+
Supports all HTTP API endpoints.
|
|
34
34
|
|
|
35
35
|
Attributes:
|
|
36
36
|
users: operations with users
|
|
37
37
|
projects: operations with projects
|
|
38
38
|
backends: operations with backends
|
|
39
|
+
fleets: operations with fleets
|
|
39
40
|
runs: operations with runs
|
|
41
|
+
metrics: operations with metrics
|
|
40
42
|
logs: operations with logs
|
|
41
43
|
gateways: operations with gateways
|
|
42
|
-
|
|
44
|
+
volumes: operations with volumes
|
|
43
45
|
"""
|
|
44
46
|
|
|
45
47
|
def __init__(self, base_url: str, token: str):
|
|
46
48
|
"""
|
|
47
49
|
Args:
|
|
48
|
-
base_url: API endpoints prefix, e.g. `http://127.0.0.1:3000
|
|
49
|
-
token: API token
|
|
50
|
+
base_url: The API endpoints prefix, e.g. `http://127.0.0.1:3000/`.
|
|
51
|
+
token: The API token.
|
|
50
52
|
"""
|
|
51
53
|
self._base_url = base_url.rstrip("/")
|
|
52
54
|
self._token = token
|
|
@@ -72,6 +74,10 @@ class APIClient:
|
|
|
72
74
|
def backends(self) -> BackendsAPIClient:
|
|
73
75
|
return BackendsAPIClient(self._request)
|
|
74
76
|
|
|
77
|
+
@property
|
|
78
|
+
def fleets(self) -> FleetsAPIClient:
|
|
79
|
+
return FleetsAPIClient(self._request)
|
|
80
|
+
|
|
75
81
|
@property
|
|
76
82
|
def repos(self) -> ReposAPIClient:
|
|
77
83
|
return ReposAPIClient(self._request)
|
|
@@ -96,14 +102,6 @@ class APIClient:
|
|
|
96
102
|
def gateways(self) -> GatewaysAPIClient:
|
|
97
103
|
return GatewaysAPIClient(self._request)
|
|
98
104
|
|
|
99
|
-
@property
|
|
100
|
-
def pool(self) -> PoolAPIClient:
|
|
101
|
-
return PoolAPIClient(self._request)
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def fleets(self) -> FleetsAPIClient:
|
|
105
|
-
return FleetsAPIClient(self._request)
|
|
106
|
-
|
|
107
105
|
@property
|
|
108
106
|
def volumes(self) -> VolumesAPIClient:
|
|
109
107
|
return VolumesAPIClient(self._request)
|
dstack/api/server/_backends.py
CHANGED
|
@@ -2,10 +2,8 @@ from typing import List
|
|
|
2
2
|
|
|
3
3
|
from pydantic import parse_obj_as
|
|
4
4
|
|
|
5
|
-
from dstack._internal.core.models
|
|
6
|
-
|
|
7
|
-
AnyConfigInfoWithCredsPartial,
|
|
8
|
-
AnyConfigValues,
|
|
5
|
+
from dstack._internal.core.backends.models import (
|
|
6
|
+
AnyBackendConfigWithCreds,
|
|
9
7
|
)
|
|
10
8
|
from dstack._internal.core.models.backends.base import BackendType
|
|
11
9
|
from dstack._internal.server.schemas.backends import DeleteBackendsRequest
|
|
@@ -17,26 +15,24 @@ class BackendsAPIClient(APIClientGroup):
|
|
|
17
15
|
resp = self._request("/api/backends/list_types")
|
|
18
16
|
return parse_obj_as(List[BackendType], resp.json())
|
|
19
17
|
|
|
20
|
-
def config_values(self, config: AnyConfigInfoWithCredsPartial) -> AnyConfigValues:
|
|
21
|
-
resp = self._request("/api/backends/config_values", body=config.json())
|
|
22
|
-
return parse_obj_as(AnyConfigValues, resp.json())
|
|
23
|
-
|
|
24
18
|
def create(
|
|
25
|
-
self, project_name: str, config:
|
|
26
|
-
) ->
|
|
19
|
+
self, project_name: str, config: AnyBackendConfigWithCreds
|
|
20
|
+
) -> AnyBackendConfigWithCreds:
|
|
27
21
|
resp = self._request(f"/api/project/{project_name}/backends/create", body=config.json())
|
|
28
|
-
return parse_obj_as(
|
|
22
|
+
return parse_obj_as(AnyBackendConfigWithCreds, resp.json())
|
|
29
23
|
|
|
30
24
|
def update(
|
|
31
|
-
self, project_name: str, config:
|
|
32
|
-
) ->
|
|
25
|
+
self, project_name: str, config: AnyBackendConfigWithCreds
|
|
26
|
+
) -> AnyBackendConfigWithCreds:
|
|
33
27
|
resp = self._request(f"/api/project/{project_name}/backends/update", body=config.json())
|
|
34
|
-
return parse_obj_as(
|
|
28
|
+
return parse_obj_as(AnyBackendConfigWithCreds, resp.json())
|
|
35
29
|
|
|
36
30
|
def delete(self, project_name: str, backends_names: List[BackendType]):
|
|
37
31
|
body = DeleteBackendsRequest(backends_names=backends_names)
|
|
38
32
|
self._request(f"/api/project/{project_name}/backends/delete", body=body.json())
|
|
39
33
|
|
|
40
|
-
def config_info(
|
|
34
|
+
def config_info(
|
|
35
|
+
self, project_name: str, backend_name: BackendType
|
|
36
|
+
) -> AnyBackendConfigWithCreds:
|
|
41
37
|
resp = self._request(f"/api/project/{project_name}/backends/{backend_name}/config_info")
|
|
42
|
-
return parse_obj_as(
|
|
38
|
+
return parse_obj_as(AnyBackendConfigWithCreds, resp.json())
|
dstack/api/server/_fleets.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from pydantic import parse_obj_as
|
|
4
4
|
|
|
@@ -22,7 +22,7 @@ class FleetsAPIClient(APIClientGroup):
|
|
|
22
22
|
body = GetFleetRequest(name=name)
|
|
23
23
|
resp = self._request(
|
|
24
24
|
f"/api/project/{project_name}/fleets/get",
|
|
25
|
-
body=body.json(
|
|
25
|
+
body=body.json(),
|
|
26
26
|
)
|
|
27
27
|
return parse_obj_as(Fleet.__response__, resp.json())
|
|
28
28
|
|
|
@@ -55,62 +55,20 @@ class FleetsAPIClient(APIClientGroup):
|
|
|
55
55
|
self._request(f"/api/project/{project_name}/fleets/delete_instances", body=body.json())
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
def _get_fleet_spec_excludes(fleet_spec: FleetSpec) -> Optional[Dict]:
|
|
59
|
+
"""
|
|
60
|
+
Returns `fleet_spec` exclude mapping to exclude certain fields from the request.
|
|
61
|
+
Use this method to exclude new fields when they are not set to keep
|
|
62
|
+
clients backward-compatibility with older servers.
|
|
63
|
+
"""
|
|
64
|
+
spec_excludes: Dict[str, Any] = {}
|
|
65
|
+
configuration_excludes: Dict[str, Any] = {}
|
|
64
66
|
profile_excludes: set[str] = set()
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
spec_excludes["configuration_path"] = True
|
|
71
|
-
if fleet_spec.configuration.ssh_config is not None:
|
|
72
|
-
if fleet_spec.configuration.ssh_config.proxy_jump is None:
|
|
73
|
-
ssh_config_excludes["proxy_jump"] = True
|
|
74
|
-
if all(
|
|
75
|
-
isinstance(h, str) or h.proxy_jump is None
|
|
76
|
-
for h in fleet_spec.configuration.ssh_config.hosts
|
|
77
|
-
):
|
|
78
|
-
ssh_hosts_excludes.add("proxy_jump")
|
|
79
|
-
if all(
|
|
80
|
-
isinstance(h, str) or h.internal_ip is None
|
|
81
|
-
for h in fleet_spec.configuration.ssh_config.hosts
|
|
82
|
-
):
|
|
83
|
-
ssh_hosts_excludes.add("internal_ip")
|
|
84
|
-
if all(
|
|
85
|
-
isinstance(h, str) or h.blocks == 1 for h in fleet_spec.configuration.ssh_config.hosts
|
|
86
|
-
):
|
|
87
|
-
ssh_hosts_excludes.add("blocks")
|
|
88
|
-
# client >= 0.18.30 / server <= 0.18.29 compatibility tweak
|
|
89
|
-
if fleet_spec.configuration.reservation is None:
|
|
90
|
-
configuration_excludes["reservation"] = True
|
|
91
|
-
if fleet_spec.profile is not None and fleet_spec.profile.reservation is None:
|
|
92
|
-
profile_excludes.add("reservation")
|
|
93
|
-
if fleet_spec.configuration.idle_duration is None:
|
|
94
|
-
configuration_excludes["idle_duration"] = True
|
|
95
|
-
if fleet_spec.profile is not None and fleet_spec.profile.idle_duration is None:
|
|
96
|
-
profile_excludes.add("idle_duration")
|
|
97
|
-
# client >= 0.18.38 / server <= 0.18.37 compatibility tweak
|
|
98
|
-
if fleet_spec.profile is not None and fleet_spec.profile.stop_duration is None:
|
|
99
|
-
profile_excludes.add("stop_duration")
|
|
100
|
-
# client >= 0.18.41 / server <= 0.18.40 compatibility tweak
|
|
101
|
-
if fleet_spec.configuration.availability_zones is None:
|
|
102
|
-
configuration_excludes["availability_zones"] = True
|
|
103
|
-
if fleet_spec.profile is not None and fleet_spec.profile.availability_zones is None:
|
|
104
|
-
profile_excludes.add("availability_zones")
|
|
105
|
-
if fleet_spec.configuration.blocks == 1:
|
|
106
|
-
configuration_excludes["blocks"] = True
|
|
107
|
-
if fleet_spec.profile is not None and fleet_spec.profile.utilization_policy is None:
|
|
108
|
-
profile_excludes.add("utilization_policy")
|
|
109
|
-
|
|
110
|
-
if ssh_hosts_excludes:
|
|
111
|
-
ssh_config_excludes["hosts"] = {"__all__": ssh_hosts_excludes}
|
|
112
|
-
if ssh_config_excludes:
|
|
113
|
-
configuration_excludes["ssh_config"] = ssh_config_excludes
|
|
67
|
+
# Fields can be excluded like this:
|
|
68
|
+
# if fleet_spec.configuration.availability_zones is None:
|
|
69
|
+
# configuration_excludes["availability_zones"] = True
|
|
70
|
+
# if fleet_spec.profile is not None and fleet_spec.profile.availability_zones is None:
|
|
71
|
+
# profile_excludes.add("availability_zones")
|
|
114
72
|
if configuration_excludes:
|
|
115
73
|
spec_excludes["configuration"] = configuration_excludes
|
|
116
74
|
if profile_excludes:
|
dstack/api/server/_gateways.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
from typing import List
|
|
1
|
+
from typing import List
|
|
2
2
|
|
|
3
3
|
from pydantic import parse_obj_as
|
|
4
4
|
|
|
5
|
-
from dstack._internal.core.models.backends.base import BackendType
|
|
6
5
|
from dstack._internal.core.models.gateways import Gateway, GatewayConfiguration
|
|
7
6
|
from dstack._internal.server.schemas.gateways import (
|
|
8
7
|
CreateGatewayRequest,
|
|
@@ -24,22 +23,12 @@ class GatewaysAPIClient(APIClientGroup):
|
|
|
24
23
|
resp = self._request(f"/api/project/{project_name}/gateways/get", body=body.json())
|
|
25
24
|
return parse_obj_as(Gateway.__response__, resp.json())
|
|
26
25
|
|
|
27
|
-
# gateway_name, backend_type, region are left for backward-compatibility with 0.18.x
|
|
28
|
-
# TODO: Remove in 0.19
|
|
29
26
|
def create(
|
|
30
27
|
self,
|
|
31
28
|
project_name: str,
|
|
32
|
-
|
|
33
|
-
backend_type: Optional[BackendType] = None,
|
|
34
|
-
region: Optional[str] = None,
|
|
35
|
-
configuration: Optional[GatewayConfiguration] = None,
|
|
29
|
+
configuration: GatewayConfiguration,
|
|
36
30
|
) -> Gateway:
|
|
37
|
-
body = CreateGatewayRequest(
|
|
38
|
-
name=gateway_name,
|
|
39
|
-
backend_type=backend_type,
|
|
40
|
-
region=region,
|
|
41
|
-
configuration=configuration,
|
|
42
|
-
)
|
|
31
|
+
body = CreateGatewayRequest(configuration=configuration)
|
|
43
32
|
resp = self._request(f"/api/project/{project_name}/gateways/create", body=body.json())
|
|
44
33
|
return parse_obj_as(Gateway.__response__, resp.json())
|
|
45
34
|
|
dstack/api/server/_repos.py
CHANGED
|
@@ -6,7 +6,6 @@ from dstack._internal.core.models.repos import AnyRepoInfo, RemoteRepoCreds, Rep
|
|
|
6
6
|
from dstack._internal.server.schemas.repos import (
|
|
7
7
|
DeleteReposRequest,
|
|
8
8
|
GetRepoRequest,
|
|
9
|
-
RemoteRepoCredsDto,
|
|
10
9
|
SaveRepoCredsRequest,
|
|
11
10
|
)
|
|
12
11
|
from dstack.api.server._group import APIClientGroup
|
|
@@ -32,9 +31,7 @@ class ReposAPIClient(APIClientGroup):
|
|
|
32
31
|
body = SaveRepoCredsRequest(
|
|
33
32
|
repo_id=repo_id,
|
|
34
33
|
repo_info=repo_info,
|
|
35
|
-
repo_creds=
|
|
36
|
-
if repo_creds
|
|
37
|
-
else None,
|
|
34
|
+
repo_creds=repo_creds,
|
|
38
35
|
)
|
|
39
36
|
self._request(f"/api/project/{project_name}/repos/init", body=body.json())
|
|
40
37
|
|