anyscale 0.26.70__py3-none-any.whl → 0.26.72__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.
- anyscale/_private/anyscale_client/anyscale_client.py +63 -6
- anyscale/_private/anyscale_client/common.py +33 -3
- anyscale/_private/anyscale_client/fake_anyscale_client.py +27 -2
- anyscale/client/README.md +29 -0
- anyscale/client/openapi_client/__init__.py +19 -0
- anyscale/client/openapi_client/api/default_api.py +1307 -4
- anyscale/client/openapi_client/models/__init__.py +19 -0
- anyscale/client/openapi_client/models/apply_multi_version_update_weights_update_model.py +152 -0
- anyscale/client/openapi_client/models/apply_version_weight_update_model.py +181 -0
- anyscale/client/openapi_client/models/backend_server_api_product_models_catalog_client_models_table_metadata.py +546 -0
- anyscale/client/openapi_client/models/backend_server_api_product_models_data_catalogs_table_metadata.py +178 -0
- anyscale/client/openapi_client/models/baseimagesenum.py +70 -1
- anyscale/client/openapi_client/models/catalog_metadata.py +150 -0
- anyscale/client/openapi_client/models/column_info.py +265 -0
- anyscale/client/openapi_client/models/compute_node_type.py +29 -1
- anyscale/client/openapi_client/models/connection_metadata.py +206 -0
- anyscale/client/openapi_client/models/create_workspace_template_version.py +31 -3
- anyscale/client/openapi_client/models/data_catalog.py +45 -31
- anyscale/client/openapi_client/models/data_catalog_connection.py +74 -58
- anyscale/client/openapi_client/models/data_catalog_object_type.py +100 -0
- anyscale/client/openapi_client/models/data_catalog_schema.py +324 -0
- anyscale/client/openapi_client/models/data_catalog_table.py +437 -0
- anyscale/client/openapi_client/models/data_catalog_volume.py +437 -0
- anyscale/client/openapi_client/models/datacatalogschema_list_response.py +147 -0
- anyscale/client/openapi_client/models/datacatalogtable_list_response.py +147 -0
- anyscale/client/openapi_client/models/datacatalogvolume_list_response.py +147 -0
- anyscale/client/openapi_client/models/decorated_serve_deployment.py +27 -1
- anyscale/client/openapi_client/models/decoratedproductionservicev2_versionapimodel_response.py +121 -0
- anyscale/client/openapi_client/models/describe_machine_pool_machines_filters.py +2 -2
- anyscale/client/openapi_client/models/describe_machine_pool_requests_filters.py +33 -5
- anyscale/client/openapi_client/models/describe_machine_pool_workloads_filters.py +2 -2
- anyscale/client/openapi_client/models/physical_resources.py +178 -0
- anyscale/client/openapi_client/models/schema_metadata.py +150 -0
- anyscale/client/openapi_client/models/sso_config.py +18 -18
- anyscale/client/openapi_client/models/supportedbaseimagesenum.py +70 -1
- anyscale/client/openapi_client/models/table_data_preview.py +209 -0
- anyscale/client/openapi_client/models/volume_metadata.py +150 -0
- anyscale/client/openapi_client/models/worker_node_type.py +29 -1
- anyscale/client/openapi_client/models/workspace_template_version.py +29 -1
- anyscale/client/openapi_client/models/workspace_template_version_data_object.py +29 -1
- anyscale/commands/job_commands.py +120 -0
- anyscale/commands/job_queue_commands.py +99 -2
- anyscale/commands/service_commands.py +139 -2
- anyscale/commands/util.py +104 -1
- anyscale/commands/workspace_commands.py +123 -5
- anyscale/commands/workspace_commands_v2.py +17 -1
- anyscale/compute_config/_private/compute_config_sdk.py +25 -12
- anyscale/compute_config/models.py +15 -0
- anyscale/controllers/job_controller.py +12 -0
- anyscale/controllers/workspace_controller.py +67 -5
- anyscale/job/_private/job_sdk.py +3 -1
- anyscale/job/models.py +16 -0
- anyscale/job_queue/__init__.py +37 -1
- anyscale/job_queue/_private/job_queue_sdk.py +28 -1
- anyscale/job_queue/commands.py +61 -1
- anyscale/sdk/anyscale_client/__init__.py +1 -0
- anyscale/sdk/anyscale_client/api/default_api.py +12 -2
- anyscale/sdk/anyscale_client/models/__init__.py +1 -0
- anyscale/sdk/anyscale_client/models/baseimagesenum.py +70 -1
- anyscale/sdk/anyscale_client/models/compute_node_type.py +29 -1
- anyscale/sdk/anyscale_client/models/physical_resources.py +178 -0
- anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +70 -1
- anyscale/sdk/anyscale_client/models/worker_node_type.py +29 -1
- anyscale/service/__init__.py +40 -0
- anyscale/service/_private/service_sdk.py +121 -24
- anyscale/service/commands.py +75 -1
- anyscale/service/models.py +46 -2
- anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
- anyscale/version.py +1 -1
- anyscale/workspace/_private/workspace_sdk.py +1 -0
- anyscale/workspace/models.py +19 -0
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/METADATA +1 -1
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/RECORD +78 -58
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/WHEEL +0 -0
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/entry_points.txt +0 -0
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/licenses/LICENSE +0 -0
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/licenses/NOTICE +0 -0
- {anyscale-0.26.70.dist-info → anyscale-0.26.72.dist-info}/top_level.txt +0 -0
|
@@ -29,6 +29,7 @@ from anyscale.client.openapi_client.models.decorated_production_job import (
|
|
|
29
29
|
DecoratedProductionJob,
|
|
30
30
|
)
|
|
31
31
|
from anyscale.client.openapi_client.models.ha_job_states import HaJobStates
|
|
32
|
+
from anyscale.commands.util import flatten_tag_dict_to_api_list
|
|
32
33
|
from anyscale.controllers.base_controller import BaseController
|
|
33
34
|
from anyscale.models.job_model import JobConfig
|
|
34
35
|
from anyscale.project_utils import infer_project_id
|
|
@@ -213,6 +214,7 @@ class JobController(BaseController):
|
|
|
213
214
|
workspace_id=job_config.workspace_id,
|
|
214
215
|
config=config_object,
|
|
215
216
|
job_queue_config=job_queue_config,
|
|
217
|
+
tags=getattr(job_config, "tags", None),
|
|
216
218
|
)
|
|
217
219
|
).result
|
|
218
220
|
self.log.info(
|
|
@@ -288,6 +290,13 @@ class JobController(BaseController):
|
|
|
288
290
|
).result
|
|
289
291
|
return job.state.current_state
|
|
290
292
|
|
|
293
|
+
def resolve_job_id(self, job_id: Optional[str], job_name: Optional[str]) -> str:
|
|
294
|
+
"""Resolve and return a job's ID from either an explicit ID or a name.
|
|
295
|
+
|
|
296
|
+
Raises click.ClickException if neither is provided or if the name is ambiguous.
|
|
297
|
+
"""
|
|
298
|
+
return self._resolve_job_object(job_id, job_name).id
|
|
299
|
+
|
|
291
300
|
def list( # noqa: PLR0913
|
|
292
301
|
self,
|
|
293
302
|
include_all_users: bool,
|
|
@@ -297,6 +306,7 @@ class JobController(BaseController):
|
|
|
297
306
|
include_archived: bool,
|
|
298
307
|
max_items: int,
|
|
299
308
|
states: List[HaJobStates],
|
|
309
|
+
tags: Optional[Dict[str, List[str]]] = None,
|
|
300
310
|
) -> None:
|
|
301
311
|
"""
|
|
302
312
|
This function will list jobs.
|
|
@@ -349,6 +359,7 @@ class JobController(BaseController):
|
|
|
349
359
|
archive_status="ALL" if include_archived else "NOT_ARCHIVED",
|
|
350
360
|
count=DEFAULT_PAGE_LIMIT,
|
|
351
361
|
state_filter=states,
|
|
362
|
+
tag_filter=flatten_tag_dict_to_api_list(tags),
|
|
352
363
|
)
|
|
353
364
|
jobs_list.extend(resp.results)
|
|
354
365
|
paging_token = resp.metadata.next_paging_token
|
|
@@ -363,6 +374,7 @@ class JobController(BaseController):
|
|
|
363
374
|
count=DEFAULT_PAGE_LIMIT,
|
|
364
375
|
paging_token=paging_token,
|
|
365
376
|
state_filter=states,
|
|
377
|
+
tag_filter=flatten_tag_dict_to_api_list(tags),
|
|
366
378
|
)
|
|
367
379
|
jobs_list.extend(resp.results)
|
|
368
380
|
paging_token = resp.metadata.next_paging_token
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shlex
|
|
3
3
|
import subprocess
|
|
4
|
-
from typing import Any, List, Optional
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
import tabulate
|
|
@@ -10,9 +10,19 @@ from anyscale.cli_logger import BlockLogger
|
|
|
10
10
|
from anyscale.client.openapi_client.models.create_experimental_workspace import (
|
|
11
11
|
CreateExperimentalWorkspace,
|
|
12
12
|
)
|
|
13
|
+
from anyscale.client.openapi_client.models.delete_resource_tags_request import (
|
|
14
|
+
DeleteResourceTagsRequest,
|
|
15
|
+
)
|
|
13
16
|
from anyscale.client.openapi_client.models.experimental_workspace import (
|
|
14
17
|
ExperimentalWorkspace,
|
|
15
18
|
)
|
|
19
|
+
from anyscale.client.openapi_client.models.resource_tag_resource_type import (
|
|
20
|
+
ResourceTagResourceType,
|
|
21
|
+
)
|
|
22
|
+
from anyscale.client.openapi_client.models.upsert_resource_tags_request import (
|
|
23
|
+
UpsertResourceTagsRequest,
|
|
24
|
+
)
|
|
25
|
+
from anyscale.commands.util import flatten_tag_dict_to_api_list
|
|
16
26
|
from anyscale.controllers.base_controller import BaseController
|
|
17
27
|
from anyscale.feature_flags import FLAG_DEFAULT_WORKING_DIR_FOR_PROJ
|
|
18
28
|
from anyscale.project_utils import get_default_project
|
|
@@ -84,13 +94,21 @@ class WorkspaceController(BaseController):
|
|
|
84
94
|
)
|
|
85
95
|
)
|
|
86
96
|
|
|
87
|
-
def list(self) -> None:
|
|
97
|
+
def list(self, tags_filter: Optional[Dict[str, List[str]]] = None) -> None:
|
|
88
98
|
"""
|
|
89
99
|
prints a non-exhaustive tabular list of information about non-deleted workspaces.
|
|
90
100
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
params = {}
|
|
102
|
+
if tags_filter:
|
|
103
|
+
api_tag_filter = flatten_tag_dict_to_api_list(tags_filter)
|
|
104
|
+
if api_tag_filter:
|
|
105
|
+
params["tag_filter"] = api_tag_filter
|
|
106
|
+
|
|
107
|
+
workspaces_data: List[ExperimentalWorkspace] = (
|
|
108
|
+
self.api_client.list_workspaces_api_v2_experimental_workspaces_get(
|
|
109
|
+
**params
|
|
110
|
+
).results
|
|
111
|
+
)
|
|
94
112
|
|
|
95
113
|
workspaces_table: List[List[Any]] = [
|
|
96
114
|
[
|
|
@@ -109,6 +127,50 @@ class WorkspaceController(BaseController):
|
|
|
109
127
|
|
|
110
128
|
print(f"Workspaces:\n{table}")
|
|
111
129
|
|
|
130
|
+
def _resolve_workspace_id(
|
|
131
|
+
self, *, workspace_id: Optional[str], name: Optional[str]
|
|
132
|
+
) -> str:
|
|
133
|
+
if workspace_id:
|
|
134
|
+
return workspace_id
|
|
135
|
+
if not name:
|
|
136
|
+
raise click.ClickException("Provide either --id or --name for workspace.")
|
|
137
|
+
results = self.api_client.list_workspaces_api_v2_experimental_workspaces_get(
|
|
138
|
+
name=name
|
|
139
|
+
).results
|
|
140
|
+
if len(results) == 0:
|
|
141
|
+
raise click.ClickException(f"No workspace with name '{name}' found.")
|
|
142
|
+
if len(results) > 1:
|
|
143
|
+
raise click.ClickException(
|
|
144
|
+
f"Multiple workspaces with name '{name}' found. Please use --id."
|
|
145
|
+
)
|
|
146
|
+
return results[0].id
|
|
147
|
+
|
|
148
|
+
def add_tags(
|
|
149
|
+
self,
|
|
150
|
+
*,
|
|
151
|
+
workspace_id: Optional[str] = None,
|
|
152
|
+
name: Optional[str] = None,
|
|
153
|
+
tags: Dict[str, str],
|
|
154
|
+
) -> None:
|
|
155
|
+
wid = self._resolve_workspace_id(workspace_id=workspace_id, name=name)
|
|
156
|
+
req = UpsertResourceTagsRequest(
|
|
157
|
+
resource_type=ResourceTagResourceType.WORKSPACE, resource_id=wid, tags=tags,
|
|
158
|
+
)
|
|
159
|
+
self.api_client.upsert_resource_tags_api_v2_tags_resource_put(req)
|
|
160
|
+
|
|
161
|
+
def remove_tags(
|
|
162
|
+
self,
|
|
163
|
+
*,
|
|
164
|
+
workspace_id: Optional[str] = None,
|
|
165
|
+
name: Optional[str] = None,
|
|
166
|
+
keys: List[str],
|
|
167
|
+
) -> None:
|
|
168
|
+
wid = self._resolve_workspace_id(workspace_id=workspace_id, name=name)
|
|
169
|
+
req = DeleteResourceTagsRequest(
|
|
170
|
+
resource_type=ResourceTagResourceType.WORKSPACE, resource_id=wid, keys=keys,
|
|
171
|
+
)
|
|
172
|
+
self.api_client.delete_resource_tags_api_v2_tags_resource_delete(req)
|
|
173
|
+
|
|
112
174
|
def clone(self, workspace: ExperimentalWorkspace) -> None:
|
|
113
175
|
dir_name = workspace.name
|
|
114
176
|
os.makedirs(dir_name)
|
anyscale/job/_private/job_sdk.py
CHANGED
|
@@ -46,7 +46,8 @@ HA_JOB_STATE_TO_JOB_STATE = {
|
|
|
46
46
|
HaJobStates.PENDING: JobState.STARTING,
|
|
47
47
|
HaJobStates.AWAITING_CLUSTER_START: JobState.STARTING,
|
|
48
48
|
HaJobStates.SUCCESS: JobState.SUCCEEDED,
|
|
49
|
-
|
|
49
|
+
# ERRORED is a transient state that can transition to RESTARTING when retries remain.
|
|
50
|
+
HaJobStates.ERRORED: JobState.RUNNING,
|
|
50
51
|
HaJobStates.TERMINATED: JobState.FAILED,
|
|
51
52
|
HaJobStates.BROKEN: JobState.FAILED,
|
|
52
53
|
HaJobStates.OUT_OF_RETRIES: JobState.FAILED,
|
|
@@ -280,6 +281,7 @@ class PrivateJobSDK(WorkloadSDK):
|
|
|
280
281
|
workspace_id=self.client.get_current_workspace_id(),
|
|
281
282
|
config=prod_job_config,
|
|
282
283
|
job_queue_config=job_queue_config,
|
|
284
|
+
tags=getattr(config, "tags", None),
|
|
283
285
|
)
|
|
284
286
|
)
|
|
285
287
|
|
anyscale/job/models.py
CHANGED
|
@@ -300,6 +300,9 @@ py_modules: # (Optional) A list of local directories or remote URIs that will be
|
|
|
300
300
|
cloud: anyscale-prod # (Optional) The name of the Anyscale Cloud.
|
|
301
301
|
project: my-project # (Optional) The name of the Anyscale Project.
|
|
302
302
|
max_retries: 3 # (Optional) Maximum number of times the job will be retried before being marked failed. Defaults to `1`.
|
|
303
|
+
tags:
|
|
304
|
+
team: mlops
|
|
305
|
+
purpose: training
|
|
303
306
|
|
|
304
307
|
"""
|
|
305
308
|
|
|
@@ -377,6 +380,19 @@ max_retries: 3 # (Optional) Maximum number of times the job will be retried befo
|
|
|
377
380
|
if timeout_s < 0:
|
|
378
381
|
raise ValueError("'timeout_s' must be >= 0.")
|
|
379
382
|
|
|
383
|
+
tags: Optional[Dict[str, str]] = field(
|
|
384
|
+
default=None, metadata={"docstring": "Tags to associate with the job."},
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
def _validate_tags(self, tags: Optional[Dict[str, str]]):
|
|
388
|
+
if tags is None:
|
|
389
|
+
return
|
|
390
|
+
if not isinstance(tags, dict):
|
|
391
|
+
raise TypeError("'tags' must be a Dict[str, str].")
|
|
392
|
+
for k, v in tags.items():
|
|
393
|
+
if not isinstance(k, str) or not isinstance(v, str):
|
|
394
|
+
raise TypeError("'tags' must be a Dict[str, str].")
|
|
395
|
+
|
|
380
396
|
|
|
381
397
|
class JobRunState(ModelEnum):
|
|
382
398
|
"""Current state of an individual job run."""
|
anyscale/job_queue/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from anyscale._private.anyscale_client import AnyscaleClient
|
|
4
4
|
from anyscale._private.models.model_base import ResultIterator
|
|
@@ -16,9 +16,15 @@ from anyscale.job_queue.commands import (
|
|
|
16
16
|
_LIST_EXAMPLE,
|
|
17
17
|
_STATUS_ARG_DOCSTRINGS,
|
|
18
18
|
_STATUS_EXAMPLE,
|
|
19
|
+
_TAGS_ADD_ARG_DOCSTRINGS,
|
|
20
|
+
_TAGS_ADD_EXAMPLE,
|
|
21
|
+
_TAGS_REMOVE_ARG_DOCSTRINGS,
|
|
22
|
+
_TAGS_REMOVE_EXAMPLE,
|
|
19
23
|
_UPDATE_ARG_DOCSTRINGS,
|
|
20
24
|
_UPDATE_EXAMPLE,
|
|
25
|
+
add_tags,
|
|
21
26
|
list,
|
|
27
|
+
remove_tags,
|
|
22
28
|
status,
|
|
23
29
|
update,
|
|
24
30
|
)
|
|
@@ -49,6 +55,7 @@ class JobQueueSDK:
|
|
|
49
55
|
cloud: Optional[str] = None,
|
|
50
56
|
project: Optional[str] = None,
|
|
51
57
|
cluster_status: Optional[SessionState] = None,
|
|
58
|
+
tags_filter: Optional[Dict[str, List[str]]] = None,
|
|
52
59
|
page_size: Optional[int] = None,
|
|
53
60
|
max_items: Optional[int] = None,
|
|
54
61
|
sorting_directives: Optional[List[JobQueueSortDirective]] = None,
|
|
@@ -61,6 +68,7 @@ class JobQueueSDK:
|
|
|
61
68
|
cloud=cloud,
|
|
62
69
|
project=project,
|
|
63
70
|
cluster_status=cluster_status,
|
|
71
|
+
tags_filter=tags_filter,
|
|
64
72
|
page_size=page_size,
|
|
65
73
|
max_items=max_items,
|
|
66
74
|
sorting_directives=sorting_directives,
|
|
@@ -87,3 +95,31 @@ class JobQueueSDK:
|
|
|
87
95
|
max_concurrency=max_concurrency,
|
|
88
96
|
idle_timeout_s=idle_timeout_s,
|
|
89
97
|
)
|
|
98
|
+
|
|
99
|
+
@sdk_docs(doc_py_example=_TAGS_ADD_EXAMPLE, arg_docstrings=_TAGS_ADD_ARG_DOCSTRINGS)
|
|
100
|
+
def add_tags( # noqa: F811
|
|
101
|
+
self,
|
|
102
|
+
*,
|
|
103
|
+
job_queue_id: Optional[str] = None,
|
|
104
|
+
name: Optional[str] = None,
|
|
105
|
+
tags: Dict[str, str],
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Upsert (add/update) tag key/value pairs for a job queue."""
|
|
108
|
+
return self._private_sdk.add_tags(
|
|
109
|
+
job_queue_id=job_queue_id, name=name, tags=tags
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@sdk_docs(
|
|
113
|
+
doc_py_example=_TAGS_REMOVE_EXAMPLE, arg_docstrings=_TAGS_REMOVE_ARG_DOCSTRINGS
|
|
114
|
+
)
|
|
115
|
+
def remove_tags( # noqa: F811
|
|
116
|
+
self,
|
|
117
|
+
*,
|
|
118
|
+
job_queue_id: Optional[str] = None,
|
|
119
|
+
name: Optional[str] = None,
|
|
120
|
+
keys: List[str],
|
|
121
|
+
) -> None:
|
|
122
|
+
"""Remove tags by key from a job queue."""
|
|
123
|
+
return self._private_sdk.remove_tags(
|
|
124
|
+
job_queue_id=job_queue_id, name=name, keys=keys
|
|
125
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from anyscale._private.models.model_base import ResultIterator
|
|
4
4
|
from anyscale._private.workload import WorkloadSDK
|
|
@@ -12,6 +12,9 @@ from anyscale.client.openapi_client.models.job_queue_sort_directive import (
|
|
|
12
12
|
from anyscale.client.openapi_client.models.list_response_metadata import (
|
|
13
13
|
ListResponseMetadata,
|
|
14
14
|
)
|
|
15
|
+
from anyscale.client.openapi_client.models.resource_tag_resource_type import (
|
|
16
|
+
ResourceTagResourceType,
|
|
17
|
+
)
|
|
15
18
|
from anyscale.client.openapi_client.models.session_state import SessionState
|
|
16
19
|
from anyscale.job_queue.models import JobQueueStatus
|
|
17
20
|
|
|
@@ -28,6 +31,7 @@ class PrivateJobQueueSDK(WorkloadSDK):
|
|
|
28
31
|
cloud: Optional[str] = None,
|
|
29
32
|
project: Optional[str] = None,
|
|
30
33
|
cluster_status: Optional[SessionState] = None,
|
|
34
|
+
tags_filter: Optional[Dict[str, List[str]]] = None,
|
|
31
35
|
page_size: Optional[int] = None,
|
|
32
36
|
max_items: Optional[int] = None,
|
|
33
37
|
sorting_directives: Optional[List[JobQueueSortDirective]] = None,
|
|
@@ -69,6 +73,7 @@ class PrivateJobQueueSDK(WorkloadSDK):
|
|
|
69
73
|
cloud=cloud,
|
|
70
74
|
project=project,
|
|
71
75
|
cluster_status=cluster_status,
|
|
76
|
+
tags_filter=tags_filter,
|
|
72
77
|
count=page_size,
|
|
73
78
|
paging_token=token,
|
|
74
79
|
sorting_directives=sorting_directives,
|
|
@@ -112,6 +117,28 @@ class PrivateJobQueueSDK(WorkloadSDK):
|
|
|
112
117
|
|
|
113
118
|
return _parse_decorated_jq_to_status(updated_jq)
|
|
114
119
|
|
|
120
|
+
def add_tags(
|
|
121
|
+
self,
|
|
122
|
+
*,
|
|
123
|
+
job_queue_id: Optional[str] = None,
|
|
124
|
+
name: Optional[str] = None,
|
|
125
|
+
tags: Dict[str, str],
|
|
126
|
+
) -> None:
|
|
127
|
+
jq = self._resolve_to_job_queue_model(job_queue_id=job_queue_id, name=name)
|
|
128
|
+
assert jq.id is not None
|
|
129
|
+
self.client.upsert_resource_tags(ResourceTagResourceType.JOB_QUEUE, jq.id, tags)
|
|
130
|
+
|
|
131
|
+
def remove_tags(
|
|
132
|
+
self,
|
|
133
|
+
*,
|
|
134
|
+
job_queue_id: Optional[str] = None,
|
|
135
|
+
name: Optional[str] = None,
|
|
136
|
+
keys: List[str],
|
|
137
|
+
) -> None:
|
|
138
|
+
jq = self._resolve_to_job_queue_model(job_queue_id=job_queue_id, name=name)
|
|
139
|
+
assert jq.id is not None
|
|
140
|
+
self.client.delete_resource_tags(ResourceTagResourceType.JOB_QUEUE, jq.id, keys)
|
|
141
|
+
|
|
115
142
|
def _resolve_to_job_queue_model(
|
|
116
143
|
self, *, job_queue_id: Optional[str] = None, name: Optional[str] = None,
|
|
117
144
|
) -> DecoratedJobQueue:
|
anyscale/job_queue/commands.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from anyscale._private.models.model_base import ResultIterator
|
|
4
4
|
from anyscale._private.sdk import sdk_command
|
|
@@ -58,6 +58,30 @@ _UPDATE_ARG_DOCSTRINGS = {
|
|
|
58
58
|
"idle_timeout_s": "New idle timeout in seconds.",
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
_TAGS_ADD_EXAMPLE = """
|
|
62
|
+
import anyscale
|
|
63
|
+
|
|
64
|
+
anyscale.job_queue.add_tags(job_queue_id="jobq_abc123", tags={"team": "mlops"})
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
_TAGS_ADD_ARG_DOCSTRINGS = {
|
|
68
|
+
"job_queue_id": "ID of the job queue to tag (alternative to name).",
|
|
69
|
+
"name": "Name of the job queue to tag (alternative to ID).",
|
|
70
|
+
"tags": "Key/value tags to upsert as a map {key: value}.",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_TAGS_REMOVE_EXAMPLE = """
|
|
74
|
+
import anyscale
|
|
75
|
+
|
|
76
|
+
anyscale.job_queue.remove_tags(job_queue_id="jobq_abc123", keys=["team"])
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
_TAGS_REMOVE_ARG_DOCSTRINGS = {
|
|
80
|
+
"job_queue_id": "ID of the job queue to modify (alternative to name).",
|
|
81
|
+
"name": "Name of the job queue to modify (alternative to ID).",
|
|
82
|
+
"keys": "List of tag keys to remove.",
|
|
83
|
+
}
|
|
84
|
+
|
|
61
85
|
|
|
62
86
|
@sdk_command(
|
|
63
87
|
_JOB_QUEUE_SDK_SINGLETON_KEY,
|
|
@@ -73,6 +97,7 @@ def list( # noqa: A001
|
|
|
73
97
|
cloud: Optional[str] = None,
|
|
74
98
|
project: Optional[str] = None,
|
|
75
99
|
cluster_status: Optional[SessionState] = None,
|
|
100
|
+
tags_filter: Optional[Dict[str, List[str]]] = None,
|
|
76
101
|
page_size: Optional[int] = None,
|
|
77
102
|
max_items: Optional[int] = None,
|
|
78
103
|
sorting_directives: Optional[List[JobQueueSortDirective]] = None,
|
|
@@ -86,6 +111,7 @@ def list( # noqa: A001
|
|
|
86
111
|
cloud=cloud,
|
|
87
112
|
project=project,
|
|
88
113
|
cluster_status=cluster_status,
|
|
114
|
+
tags_filter=tags_filter,
|
|
89
115
|
page_size=page_size,
|
|
90
116
|
max_items=max_items,
|
|
91
117
|
sorting_directives=sorting_directives,
|
|
@@ -128,3 +154,37 @@ def update(
|
|
|
128
154
|
max_concurrency=max_concurrency,
|
|
129
155
|
idle_timeout_s=idle_timeout_s,
|
|
130
156
|
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@sdk_command(
|
|
160
|
+
_JOB_QUEUE_SDK_SINGLETON_KEY,
|
|
161
|
+
PrivateJobQueueSDK,
|
|
162
|
+
doc_py_example=_TAGS_ADD_EXAMPLE,
|
|
163
|
+
arg_docstrings=_TAGS_ADD_ARG_DOCSTRINGS,
|
|
164
|
+
)
|
|
165
|
+
def add_tags(
|
|
166
|
+
*,
|
|
167
|
+
job_queue_id: Optional[str] = None,
|
|
168
|
+
name: Optional[str] = None,
|
|
169
|
+
tags: Dict[str, str],
|
|
170
|
+
_private_sdk: Optional[PrivateJobQueueSDK] = None,
|
|
171
|
+
) -> None:
|
|
172
|
+
"""Upsert tags for a job queue."""
|
|
173
|
+
return _private_sdk.add_tags(job_queue_id=job_queue_id, name=name, tags=tags) # type: ignore
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@sdk_command(
|
|
177
|
+
_JOB_QUEUE_SDK_SINGLETON_KEY,
|
|
178
|
+
PrivateJobQueueSDK,
|
|
179
|
+
doc_py_example=_TAGS_REMOVE_EXAMPLE,
|
|
180
|
+
arg_docstrings=_TAGS_REMOVE_ARG_DOCSTRINGS,
|
|
181
|
+
)
|
|
182
|
+
def remove_tags(
|
|
183
|
+
*,
|
|
184
|
+
job_queue_id: Optional[str] = None,
|
|
185
|
+
name: Optional[str] = None,
|
|
186
|
+
keys: List[str],
|
|
187
|
+
_private_sdk: Optional[PrivateJobQueueSDK] = None,
|
|
188
|
+
) -> None:
|
|
189
|
+
"""Remove tags by key from a job queue."""
|
|
190
|
+
return _private_sdk.remove_tags(job_queue_id=job_queue_id, name=name, keys=keys) # type: ignore
|
|
@@ -133,6 +133,7 @@ from anyscale_client.models.organization import Organization
|
|
|
133
133
|
from anyscale_client.models.organization_response import OrganizationResponse
|
|
134
134
|
from anyscale_client.models.page_query import PageQuery
|
|
135
135
|
from anyscale_client.models.pause_schedule import PauseSchedule
|
|
136
|
+
from anyscale_client.models.physical_resources import PhysicalResources
|
|
136
137
|
from anyscale_client.models.production_job import ProductionJob
|
|
137
138
|
from anyscale_client.models.production_job_config import ProductionJobConfig
|
|
138
139
|
from anyscale_client.models.production_job_state_transition import ProductionJobStateTransition
|
|
@@ -2696,6 +2696,7 @@ class DefaultApi(object):
|
|
|
2696
2696
|
|
|
2697
2697
|
:param async_req bool: execute request asynchronously
|
|
2698
2698
|
:param str cloud_id: The cloud id whose default cluster compute you want to fetch. If None, will use the default cloud.
|
|
2699
|
+
:param str cloud_resource_id: The cloud resource ID to fetch the default cluster compute for. If None, will use the primary cloud resource of the cloud.
|
|
2699
2700
|
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
|
2700
2701
|
be returned without reading/decoding response
|
|
2701
2702
|
data. Default is True.
|
|
@@ -2721,6 +2722,7 @@ class DefaultApi(object):
|
|
|
2721
2722
|
|
|
2722
2723
|
:param async_req bool: execute request asynchronously
|
|
2723
2724
|
:param str cloud_id: The cloud id whose default cluster compute you want to fetch. If None, will use the default cloud.
|
|
2725
|
+
:param str cloud_resource_id: The cloud resource ID to fetch the default cluster compute for. If None, will use the primary cloud resource of the cloud.
|
|
2724
2726
|
:param _return_http_data_only: response data without head status code
|
|
2725
2727
|
and headers
|
|
2726
2728
|
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
|
@@ -2738,7 +2740,8 @@ class DefaultApi(object):
|
|
|
2738
2740
|
local_var_params = locals()
|
|
2739
2741
|
|
|
2740
2742
|
all_params = [
|
|
2741
|
-
'cloud_id'
|
|
2743
|
+
'cloud_id',
|
|
2744
|
+
'cloud_resource_id'
|
|
2742
2745
|
]
|
|
2743
2746
|
all_params.extend(
|
|
2744
2747
|
[
|
|
@@ -2765,6 +2768,8 @@ class DefaultApi(object):
|
|
|
2765
2768
|
query_params = []
|
|
2766
2769
|
if 'cloud_id' in local_var_params and local_var_params['cloud_id'] is not None: # noqa: E501
|
|
2767
2770
|
query_params.append(('cloud_id', local_var_params['cloud_id'])) # noqa: E501
|
|
2771
|
+
if 'cloud_resource_id' in local_var_params and local_var_params['cloud_resource_id'] is not None: # noqa: E501
|
|
2772
|
+
query_params.append(('cloud_resource_id', local_var_params['cloud_resource_id'])) # noqa: E501
|
|
2768
2773
|
|
|
2769
2774
|
header_params = {}
|
|
2770
2775
|
|
|
@@ -2929,6 +2934,7 @@ class DefaultApi(object):
|
|
|
2929
2934
|
|
|
2930
2935
|
:param async_req bool: execute request asynchronously
|
|
2931
2936
|
:param str cloud_id: (required)
|
|
2937
|
+
:param str cloud_resource_id:
|
|
2932
2938
|
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
|
2933
2939
|
be returned without reading/decoding response
|
|
2934
2940
|
data. Default is True.
|
|
@@ -2954,6 +2960,7 @@ class DefaultApi(object):
|
|
|
2954
2960
|
|
|
2955
2961
|
:param async_req bool: execute request asynchronously
|
|
2956
2962
|
:param str cloud_id: (required)
|
|
2963
|
+
:param str cloud_resource_id:
|
|
2957
2964
|
:param _return_http_data_only: response data without head status code
|
|
2958
2965
|
and headers
|
|
2959
2966
|
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
|
@@ -2971,7 +2978,8 @@ class DefaultApi(object):
|
|
|
2971
2978
|
local_var_params = locals()
|
|
2972
2979
|
|
|
2973
2980
|
all_params = [
|
|
2974
|
-
'cloud_id'
|
|
2981
|
+
'cloud_id',
|
|
2982
|
+
'cloud_resource_id'
|
|
2975
2983
|
]
|
|
2976
2984
|
all_params.extend(
|
|
2977
2985
|
[
|
|
@@ -3002,6 +3010,8 @@ class DefaultApi(object):
|
|
|
3002
3010
|
path_params['cloud_id'] = local_var_params['cloud_id'] # noqa: E501
|
|
3003
3011
|
|
|
3004
3012
|
query_params = []
|
|
3013
|
+
if 'cloud_resource_id' in local_var_params and local_var_params['cloud_resource_id'] is not None: # noqa: E501
|
|
3014
|
+
query_params.append(('cloud_resource_id', local_var_params['cloud_resource_id'])) # noqa: E501
|
|
3005
3015
|
|
|
3006
3016
|
header_params = {}
|
|
3007
3017
|
|
|
@@ -119,6 +119,7 @@ from anyscale_client.models.organization import Organization
|
|
|
119
119
|
from anyscale_client.models.organization_response import OrganizationResponse
|
|
120
120
|
from anyscale_client.models.page_query import PageQuery
|
|
121
121
|
from anyscale_client.models.pause_schedule import PauseSchedule
|
|
122
|
+
from anyscale_client.models.physical_resources import PhysicalResources
|
|
122
123
|
from anyscale_client.models.production_job import ProductionJob
|
|
123
124
|
from anyscale_client.models.production_job_config import ProductionJobConfig
|
|
124
125
|
from anyscale_client.models.production_job_state_transition import ProductionJobStateTransition
|