dstack 0.19.9__py3-none-any.whl → 0.19.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dstack might be problematic. Click here for more details.
- dstack/_internal/cli/commands/config.py +1 -1
- dstack/_internal/cli/commands/metrics.py +25 -10
- dstack/_internal/cli/commands/offer.py +2 -0
- dstack/_internal/cli/commands/project.py +161 -0
- dstack/_internal/cli/commands/ps.py +9 -2
- dstack/_internal/cli/main.py +2 -0
- dstack/_internal/cli/services/configurators/run.py +1 -1
- dstack/_internal/cli/utils/updates.py +13 -1
- dstack/_internal/core/backends/aws/compute.py +21 -9
- dstack/_internal/core/backends/azure/compute.py +8 -3
- dstack/_internal/core/backends/base/compute.py +9 -4
- dstack/_internal/core/backends/gcp/compute.py +43 -20
- dstack/_internal/core/backends/gcp/resources.py +18 -2
- dstack/_internal/core/backends/local/compute.py +4 -2
- dstack/_internal/core/models/configurations.py +21 -4
- dstack/_internal/core/models/runs.py +2 -1
- dstack/_internal/proxy/gateway/resources/nginx/00-log-format.conf +11 -1
- dstack/_internal/proxy/gateway/resources/nginx/service.jinja2 +12 -6
- dstack/_internal/proxy/gateway/services/stats.py +17 -3
- dstack/_internal/server/background/tasks/process_metrics.py +23 -21
- dstack/_internal/server/background/tasks/process_submitted_jobs.py +24 -15
- dstack/_internal/server/migrations/versions/bca2fdf130bf_add_runmodel_priority.py +34 -0
- dstack/_internal/server/models.py +1 -0
- dstack/_internal/server/routers/repos.py +13 -4
- dstack/_internal/server/services/fleets.py +2 -2
- dstack/_internal/server/services/gateways/__init__.py +1 -1
- dstack/_internal/server/services/instances.py +6 -2
- dstack/_internal/server/services/jobs/__init__.py +4 -4
- dstack/_internal/server/services/jobs/configurators/base.py +18 -4
- dstack/_internal/server/services/jobs/configurators/extensions/cursor.py +3 -1
- dstack/_internal/server/services/jobs/configurators/extensions/vscode.py +3 -1
- dstack/_internal/server/services/plugins.py +64 -32
- dstack/_internal/server/services/runs.py +33 -20
- dstack/_internal/server/services/volumes.py +1 -1
- dstack/_internal/server/settings.py +1 -0
- dstack/_internal/server/statics/index.html +1 -1
- dstack/_internal/server/statics/{main-b4f65323f5df007e1664.js → main-5b9786c955b42bf93581.js} +8 -8
- dstack/_internal/server/statics/{main-b4f65323f5df007e1664.js.map → main-5b9786c955b42bf93581.js.map} +1 -1
- dstack/_internal/server/testing/common.py +2 -0
- dstack/_internal/server/utils/routers.py +3 -6
- dstack/_internal/settings.py +4 -0
- dstack/api/_public/runs.py +6 -3
- dstack/api/server/_runs.py +2 -0
- dstack/plugins/builtin/__init__.py +0 -0
- dstack/plugins/builtin/rest_plugin/__init__.py +18 -0
- dstack/plugins/builtin/rest_plugin/_models.py +48 -0
- dstack/plugins/builtin/rest_plugin/_plugin.py +127 -0
- dstack/version.py +2 -2
- {dstack-0.19.9.dist-info → dstack-0.19.11.dist-info}/METADATA +10 -6
- {dstack-0.19.9.dist-info → dstack-0.19.11.dist-info}/RECORD +53 -47
- {dstack-0.19.9.dist-info → dstack-0.19.11.dist-info}/WHEEL +0 -0
- {dstack-0.19.9.dist-info → dstack-0.19.11.dist-info}/entry_points.txt +0 -0
- {dstack-0.19.9.dist-info → dstack-0.19.11.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -262,6 +262,7 @@ async def create_run(
|
|
|
262
262
|
run_spec: Optional[RunSpec] = None,
|
|
263
263
|
run_id: Optional[UUID] = None,
|
|
264
264
|
deleted: bool = False,
|
|
265
|
+
priority: int = 0,
|
|
265
266
|
) -> RunModel:
|
|
266
267
|
if run_spec is None:
|
|
267
268
|
run_spec = get_run_spec(
|
|
@@ -282,6 +283,7 @@ async def create_run(
|
|
|
282
283
|
run_spec=run_spec.json(),
|
|
283
284
|
last_processed_at=submitted_at,
|
|
284
285
|
jobs=[],
|
|
286
|
+
priority=priority,
|
|
285
287
|
)
|
|
286
288
|
session.add(run)
|
|
287
289
|
await session.commit()
|
|
@@ -93,13 +93,10 @@ def get_server_client_error_details(error: ServerClientError) -> List[Dict]:
|
|
|
93
93
|
return details
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
def
|
|
96
|
+
def get_request_size(request: Request) -> int:
|
|
97
97
|
if "content-length" not in request.headers:
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
if content_length > limit:
|
|
101
|
-
return True
|
|
102
|
-
return False
|
|
98
|
+
return 0
|
|
99
|
+
return int(request.headers["content-length"])
|
|
103
100
|
|
|
104
101
|
|
|
105
102
|
def check_client_server_compatibility(
|
dstack/_internal/settings.py
CHANGED
|
@@ -12,6 +12,10 @@ DSTACK_RELEASE = os.getenv("DSTACK_RELEASE") is not None or version.__is_release
|
|
|
12
12
|
DSTACK_USE_LATEST_FROM_BRANCH = os.getenv("DSTACK_USE_LATEST_FROM_BRANCH") is not None
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
DSTACK_BASE_IMAGE = os.getenv("DSTACK_BASE_IMAGE", "dstackai/base")
|
|
16
|
+
DSTACK_BASE_IMAGE_VERSION = os.getenv("DSTACK_BASE_IMAGE_VERSION", version.base_image)
|
|
17
|
+
|
|
18
|
+
|
|
15
19
|
class FeatureFlags:
|
|
16
20
|
"""
|
|
17
21
|
dstack feature flags. Feature flags are temporary and can be used when developing
|
dstack/api/_public/runs.py
CHANGED
|
@@ -691,29 +691,32 @@ class RunCollection:
|
|
|
691
691
|
logger.warning("The exec_plan() method is deprecated in favor of apply_plan().")
|
|
692
692
|
return self.apply_plan(run_plan=run_plan, repo=repo, reserve_ports=reserve_ports)
|
|
693
693
|
|
|
694
|
-
def list(self, all: bool = False) -> List[Run]:
|
|
694
|
+
def list(self, all: bool = False, limit: Optional[int] = None) -> List[Run]:
|
|
695
695
|
"""
|
|
696
696
|
List runs.
|
|
697
697
|
|
|
698
698
|
Args:
|
|
699
699
|
all: Show all runs (active and finished) if `True`.
|
|
700
|
+
limit: Limit the number of runs to return. Must be less than 100.
|
|
700
701
|
|
|
701
702
|
Returns:
|
|
702
703
|
List of runs.
|
|
703
704
|
"""
|
|
704
705
|
# Return only one page of latest runs (<=100). Returning all the pages may be costly.
|
|
705
706
|
# TODO: Consider introducing `since` filter with a reasonable default.
|
|
706
|
-
only_active = not all
|
|
707
|
+
only_active = not all and limit is None
|
|
707
708
|
runs = self._api_client.runs.list(
|
|
708
709
|
project_name=self._project,
|
|
709
710
|
repo_id=None,
|
|
710
711
|
only_active=only_active,
|
|
712
|
+
limit=limit or 100,
|
|
711
713
|
)
|
|
712
714
|
if only_active and len(runs) == 0:
|
|
713
715
|
runs = self._api_client.runs.list(
|
|
714
716
|
project_name=self._project,
|
|
715
717
|
repo_id=None,
|
|
716
|
-
|
|
718
|
+
limit=1,
|
|
719
|
+
)
|
|
717
720
|
return [self._model_to_run(run) for run in runs]
|
|
718
721
|
|
|
719
722
|
def get(self, run_name: str) -> Optional[Run]:
|
dstack/api/server/_runs.py
CHANGED
|
@@ -186,6 +186,8 @@ def _get_run_spec_excludes(run_spec: RunSpec) -> Optional[Dict]:
|
|
|
186
186
|
configuration_excludes["rate_limits"] = True
|
|
187
187
|
if configuration.shell is None:
|
|
188
188
|
configuration_excludes["shell"] = True
|
|
189
|
+
if configuration.priority is None:
|
|
190
|
+
configuration_excludes["priority"] = True
|
|
189
191
|
|
|
190
192
|
if configuration_excludes:
|
|
191
193
|
spec_excludes["configuration"] = configuration_excludes
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# ruff: noqa: F401
|
|
2
|
+
from dstack.plugins.builtin.rest_plugin._models import (
|
|
3
|
+
FleetSpecRequest,
|
|
4
|
+
FleetSpecResponse,
|
|
5
|
+
GatewaySpecRequest,
|
|
6
|
+
GatewaySpecResponse,
|
|
7
|
+
RunSpecRequest,
|
|
8
|
+
RunSpecResponse,
|
|
9
|
+
SpecApplyRequest,
|
|
10
|
+
SpecApplyResponse,
|
|
11
|
+
VolumeSpecRequest,
|
|
12
|
+
VolumeSpecResponse,
|
|
13
|
+
)
|
|
14
|
+
from dstack.plugins.builtin.rest_plugin._plugin import (
|
|
15
|
+
PLUGIN_SERVICE_URI_ENV_VAR_NAME,
|
|
16
|
+
CustomApplyPolicy,
|
|
17
|
+
RESTPlugin,
|
|
18
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Generic, Optional, TypeVar
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
|
|
6
|
+
from dstack._internal.core.models.fleets import FleetSpec
|
|
7
|
+
from dstack._internal.core.models.gateways import GatewaySpec
|
|
8
|
+
from dstack._internal.core.models.runs import RunSpec
|
|
9
|
+
from dstack._internal.core.models.volumes import VolumeSpec
|
|
10
|
+
|
|
11
|
+
SpecType = TypeVar("SpecType", RunSpec, FleetSpec, VolumeSpec, GatewaySpec)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SpecApplyRequest(BaseModel, Generic[SpecType]):
|
|
15
|
+
user: Annotated[str, Field(description="The name of the user making the apply request")]
|
|
16
|
+
project: Annotated[str, Field(description="The name of the project the request is for")]
|
|
17
|
+
spec: Annotated[SpecType, Field(description="The spec to be applied")]
|
|
18
|
+
|
|
19
|
+
# Override dict() to remove __orig_class__ attribute and avoid "TypeError: Object of type _GenericAlias is not JSON serializable"
|
|
20
|
+
# error. This issue doesn't happen though when running the code in pytest, only when running the server.
|
|
21
|
+
def dict(self, *args, **kwargs):
|
|
22
|
+
d = super().dict(*args, **kwargs)
|
|
23
|
+
d.pop("__orig_class__", None)
|
|
24
|
+
return d
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
RunSpecRequest = SpecApplyRequest[RunSpec]
|
|
28
|
+
FleetSpecRequest = SpecApplyRequest[FleetSpec]
|
|
29
|
+
VolumeSpecRequest = SpecApplyRequest[VolumeSpec]
|
|
30
|
+
GatewaySpecRequest = SpecApplyRequest[GatewaySpec]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SpecApplyResponse(BaseModel, Generic[SpecType]):
|
|
34
|
+
spec: Annotated[
|
|
35
|
+
SpecType,
|
|
36
|
+
Field(
|
|
37
|
+
description="The spec to apply, original spec if error otherwise original or mutated by plugin service if approved"
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
error: Annotated[
|
|
41
|
+
Optional[str], Field(description="Error message if request is rejected", min_length=1)
|
|
42
|
+
] = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
RunSpecResponse = SpecApplyResponse[RunSpec]
|
|
46
|
+
FleetSpecResponse = SpecApplyResponse[FleetSpec]
|
|
47
|
+
VolumeSpecResponse = SpecApplyResponse[VolumeSpec]
|
|
48
|
+
GatewaySpecResponse = SpecApplyResponse[GatewaySpec]
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from typing import Type
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from pydantic import ValidationError
|
|
7
|
+
|
|
8
|
+
from dstack._internal.core.errors import ServerClientError
|
|
9
|
+
from dstack._internal.core.models.fleets import FleetSpec
|
|
10
|
+
from dstack._internal.core.models.gateways import GatewaySpec
|
|
11
|
+
from dstack._internal.core.models.volumes import VolumeSpec
|
|
12
|
+
from dstack.plugins import ApplyPolicy, ApplySpec, Plugin, RunSpec, get_plugin_logger
|
|
13
|
+
from dstack.plugins.builtin.rest_plugin import (
|
|
14
|
+
FleetSpecRequest,
|
|
15
|
+
FleetSpecResponse,
|
|
16
|
+
GatewaySpecRequest,
|
|
17
|
+
GatewaySpecResponse,
|
|
18
|
+
RunSpecRequest,
|
|
19
|
+
RunSpecResponse,
|
|
20
|
+
SpecApplyRequest,
|
|
21
|
+
SpecApplyResponse,
|
|
22
|
+
VolumeSpecRequest,
|
|
23
|
+
VolumeSpecResponse,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = get_plugin_logger(__name__)
|
|
27
|
+
|
|
28
|
+
PLUGIN_SERVICE_URI_ENV_VAR_NAME = "DSTACK_PLUGIN_SERVICE_URI"
|
|
29
|
+
PLUGIN_REQUEST_TIMEOUT_SEC = 8
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CustomApplyPolicy(ApplyPolicy):
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self._plugin_service_uri = os.getenv(PLUGIN_SERVICE_URI_ENV_VAR_NAME)
|
|
35
|
+
logger.info(f"Found plugin service at {self._plugin_service_uri}")
|
|
36
|
+
if not self._plugin_service_uri:
|
|
37
|
+
logger.error(
|
|
38
|
+
f"Cannot create policy because {PLUGIN_SERVICE_URI_ENV_VAR_NAME} is not set"
|
|
39
|
+
)
|
|
40
|
+
raise ServerClientError(f"{PLUGIN_SERVICE_URI_ENV_VAR_NAME} is not set")
|
|
41
|
+
|
|
42
|
+
def _check_request_rejected(self, response: SpecApplyResponse):
|
|
43
|
+
if response.error is not None:
|
|
44
|
+
logger.error(f"Plugin service rejected apply request: {response.error}")
|
|
45
|
+
raise ServerClientError(f"Apply request rejected: {response.error}")
|
|
46
|
+
|
|
47
|
+
def _call_plugin_service(self, spec_request: SpecApplyRequest, endpoint: str) -> ApplySpec:
|
|
48
|
+
response = None
|
|
49
|
+
try:
|
|
50
|
+
response = requests.post(
|
|
51
|
+
f"{self._plugin_service_uri}{endpoint}",
|
|
52
|
+
json=spec_request.dict(),
|
|
53
|
+
headers={"accept": "application/json", "Content-Type": "application/json"},
|
|
54
|
+
timeout=PLUGIN_REQUEST_TIMEOUT_SEC,
|
|
55
|
+
)
|
|
56
|
+
response.raise_for_status()
|
|
57
|
+
spec_json = json.loads(response.text)
|
|
58
|
+
return spec_json
|
|
59
|
+
except requests.exceptions.ConnectionError as e:
|
|
60
|
+
logger.error(
|
|
61
|
+
f"Could not connect to plugin service at {self._plugin_service_uri}: %s", e
|
|
62
|
+
)
|
|
63
|
+
raise ServerClientError(
|
|
64
|
+
f"Could not connect to plugin service at {self._plugin_service_uri}"
|
|
65
|
+
)
|
|
66
|
+
except requests.RequestException as e:
|
|
67
|
+
logger.error("Request to the plugin service failed: %s", e)
|
|
68
|
+
raise ServerClientError("Request to the plugin service failed")
|
|
69
|
+
|
|
70
|
+
def _on_apply(
|
|
71
|
+
self,
|
|
72
|
+
request_cls: Type[SpecApplyRequest],
|
|
73
|
+
response_cls: Type[SpecApplyResponse],
|
|
74
|
+
endpoint: str,
|
|
75
|
+
user: str,
|
|
76
|
+
project: str,
|
|
77
|
+
spec: ApplySpec,
|
|
78
|
+
) -> ApplySpec:
|
|
79
|
+
try:
|
|
80
|
+
spec_request = request_cls(user=user, project=project, spec=spec)
|
|
81
|
+
spec_json = self._call_plugin_service(spec_request, endpoint)
|
|
82
|
+
response = response_cls(**spec_json)
|
|
83
|
+
self._check_request_rejected(response)
|
|
84
|
+
return response.spec
|
|
85
|
+
except ValidationError:
|
|
86
|
+
logger.error(f"Plugin service returned invalid response:\n{spec_json}")
|
|
87
|
+
raise ServerClientError("Plugin service returned an invalid response")
|
|
88
|
+
|
|
89
|
+
def on_run_apply(self, user: str, project: str, spec: RunSpec) -> RunSpec:
|
|
90
|
+
return self._on_apply(
|
|
91
|
+
RunSpecRequest, RunSpecResponse, "/apply_policies/on_run_apply", user, project, spec
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def on_fleet_apply(self, user: str, project: str, spec: FleetSpec) -> FleetSpec:
|
|
95
|
+
return self._on_apply(
|
|
96
|
+
FleetSpecRequest,
|
|
97
|
+
FleetSpecResponse,
|
|
98
|
+
"/apply_policies/on_fleet_apply",
|
|
99
|
+
user,
|
|
100
|
+
project,
|
|
101
|
+
spec,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def on_volume_apply(self, user: str, project: str, spec: VolumeSpec) -> VolumeSpec:
|
|
105
|
+
return self._on_apply(
|
|
106
|
+
VolumeSpecRequest,
|
|
107
|
+
VolumeSpecResponse,
|
|
108
|
+
"/apply_policies/on_volume_apply",
|
|
109
|
+
user,
|
|
110
|
+
project,
|
|
111
|
+
spec,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def on_gateway_apply(self, user: str, project: str, spec: GatewaySpec) -> GatewaySpec:
|
|
115
|
+
return self._on_apply(
|
|
116
|
+
GatewaySpecRequest,
|
|
117
|
+
GatewaySpecResponse,
|
|
118
|
+
"/apply_policies/on_gateway_apply",
|
|
119
|
+
user,
|
|
120
|
+
project,
|
|
121
|
+
spec,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class RESTPlugin(Plugin):
|
|
126
|
+
def get_apply_policies(self) -> list[ApplyPolicy]:
|
|
127
|
+
return [CustomApplyPolicy()]
|
dstack/version.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
__version__ = "0.19.
|
|
1
|
+
__version__ = "0.19.11"
|
|
2
2
|
__is_release__ = True
|
|
3
|
-
base_image = "0.
|
|
3
|
+
base_image = "0.8"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dstack
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.11
|
|
4
4
|
Summary: dstack is an open-source orchestration engine for running AI workloads on any cloud or on-premises.
|
|
5
5
|
Project-URL: Homepage, https://dstack.ai
|
|
6
6
|
Project-URL: Source, https://github.com/dstackai/dstack
|
|
@@ -21,7 +21,7 @@ Requires-Dist: cryptography
|
|
|
21
21
|
Requires-Dist: cursor
|
|
22
22
|
Requires-Dist: filelock
|
|
23
23
|
Requires-Dist: gitpython
|
|
24
|
-
Requires-Dist: gpuhunt==0.1.
|
|
24
|
+
Requires-Dist: gpuhunt==0.1.6
|
|
25
25
|
Requires-Dist: jsonschema
|
|
26
26
|
Requires-Dist: packaging
|
|
27
27
|
Requires-Dist: paramiko>=3.2.0
|
|
@@ -56,6 +56,7 @@ Requires-Dist: azure-mgmt-subscription>=3.1.1; extra == 'all'
|
|
|
56
56
|
Requires-Dist: backports-entry-points-selectable; extra == 'all'
|
|
57
57
|
Requires-Dist: boto3>=1.38.13; extra == 'all'
|
|
58
58
|
Requires-Dist: botocore; extra == 'all'
|
|
59
|
+
Requires-Dist: cryptography>=44.0.3; extra == 'all'
|
|
59
60
|
Requires-Dist: datacrunch; extra == 'all'
|
|
60
61
|
Requires-Dist: docker>=6.0.0; extra == 'all'
|
|
61
62
|
Requires-Dist: fastapi; extra == 'all'
|
|
@@ -71,8 +72,9 @@ Requires-Dist: httpx; extra == 'all'
|
|
|
71
72
|
Requires-Dist: jinja2; extra == 'all'
|
|
72
73
|
Requires-Dist: kubernetes; extra == 'all'
|
|
73
74
|
Requires-Dist: nebius<0.3,>=0.2.19; (python_version >= '3.10') and extra == 'all'
|
|
74
|
-
Requires-Dist: oci; extra == 'all'
|
|
75
|
+
Requires-Dist: oci>=2.150.0; extra == 'all'
|
|
75
76
|
Requires-Dist: prometheus-client; extra == 'all'
|
|
77
|
+
Requires-Dist: pyopenssl>=23.2.0; extra == 'all'
|
|
76
78
|
Requires-Dist: python-dxf==12.1.0; extra == 'all'
|
|
77
79
|
Requires-Dist: python-json-logger>=3.1.0; extra == 'all'
|
|
78
80
|
Requires-Dist: sentry-sdk[fastapi]; extra == 'all'
|
|
@@ -280,13 +282,15 @@ Requires-Dist: alembic>=1.10.2; extra == 'oci'
|
|
|
280
282
|
Requires-Dist: apscheduler<4; extra == 'oci'
|
|
281
283
|
Requires-Dist: asyncpg; extra == 'oci'
|
|
282
284
|
Requires-Dist: backports-entry-points-selectable; extra == 'oci'
|
|
285
|
+
Requires-Dist: cryptography>=44.0.3; extra == 'oci'
|
|
283
286
|
Requires-Dist: docker>=6.0.0; extra == 'oci'
|
|
284
287
|
Requires-Dist: fastapi; extra == 'oci'
|
|
285
288
|
Requires-Dist: grpcio>=1.50; extra == 'oci'
|
|
286
289
|
Requires-Dist: httpx; extra == 'oci'
|
|
287
290
|
Requires-Dist: jinja2; extra == 'oci'
|
|
288
|
-
Requires-Dist: oci; extra == 'oci'
|
|
291
|
+
Requires-Dist: oci>=2.150.0; extra == 'oci'
|
|
289
292
|
Requires-Dist: prometheus-client; extra == 'oci'
|
|
293
|
+
Requires-Dist: pyopenssl>=23.2.0; extra == 'oci'
|
|
290
294
|
Requires-Dist: python-dxf==12.1.0; extra == 'oci'
|
|
291
295
|
Requires-Dist: python-json-logger>=3.1.0; extra == 'oci'
|
|
292
296
|
Requires-Dist: sentry-sdk[fastapi]; extra == 'oci'
|
|
@@ -423,9 +427,9 @@ To point the CLI to the `dstack` server, configure it
|
|
|
423
427
|
with the server address, user token, and project name:
|
|
424
428
|
|
|
425
429
|
```shell
|
|
426
|
-
$ dstack
|
|
430
|
+
$ dstack project add \
|
|
431
|
+
--name main \
|
|
427
432
|
--url http://127.0.0.1:3000 \
|
|
428
|
-
--project main \
|
|
429
433
|
--token bbae0f28-d3dd-4820-bf61-8f4bb40815da
|
|
430
434
|
|
|
431
435
|
Configuration is updated at ~/.dstack/config.yml
|