anyscale 0.26.69__py3-none-any.whl → 0.26.71__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 +126 -3
- anyscale/_private/anyscale_client/common.py +51 -2
- anyscale/_private/anyscale_client/fake_anyscale_client.py +103 -11
- anyscale/client/README.md +43 -4
- anyscale/client/openapi_client/__init__.py +30 -4
- anyscale/client/openapi_client/api/default_api.py +1769 -27
- anyscale/client/openapi_client/models/__init__.py +30 -4
- anyscale/client/openapi_client/models/api_key_info.py +29 -3
- anyscale/client/openapi_client/models/apply_autoscaling_config_update_model.py +350 -0
- anyscale/client/openapi_client/models/apply_multi_version_update_weights_update_model.py +152 -0
- anyscale/client/openapi_client/models/apply_production_service_multi_version_v2_model.py +207 -0
- anyscale/client/openapi_client/models/apply_production_service_v2_model.py +31 -3
- 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 +139 -1
- anyscale/client/openapi_client/models/catalog_metadata.py +150 -0
- anyscale/client/openapi_client/models/cloud_data_bucket_file_type.py +2 -1
- anyscale/client/openapi_client/models/{oauthconnectionresponse_response.py → clouddeployment_response.py} +11 -11
- 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_experimental_workspace.py +29 -1
- anyscale/client/openapi_client/models/create_workspace_from_template.py +29 -1
- anyscale/client/openapi_client/models/create_workspace_template_version.py +59 -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/{ha_job_event_level.py → data_catalog_object_type.py} +7 -8
- 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_list_service_api_model.py +58 -1
- anyscale/client/openapi_client/models/decorated_production_service_v2_api_model.py +60 -3
- anyscale/client/openapi_client/models/decorated_serve_deployment.py +27 -1
- anyscale/client/openapi_client/models/decorated_service_event_api_model.py +3 -3
- anyscale/client/openapi_client/models/decoratedproductionservicev2_versionapimodel_response.py +121 -0
- anyscale/client/openapi_client/models/describe_machine_pool_machines_filters.py +33 -5
- anyscale/client/openapi_client/models/describe_machine_pool_requests_filters.py +33 -5
- anyscale/client/openapi_client/models/describe_machine_pool_workloads_filters.py +33 -5
- anyscale/client/openapi_client/models/{service_event_level.py → entity_type.py} +9 -9
- anyscale/client/openapi_client/models/event_level.py +2 -1
- anyscale/client/openapi_client/models/job_event_fields.py +206 -0
- anyscale/client/openapi_client/models/machine_type_partition_filter.py +152 -0
- anyscale/client/openapi_client/models/partition_info.py +30 -1
- anyscale/client/openapi_client/models/physical_resources.py +178 -0
- anyscale/client/openapi_client/models/production_job_event.py +3 -3
- anyscale/client/openapi_client/models/rollout_strategy.py +2 -1
- anyscale/client/openapi_client/models/schema_metadata.py +150 -0
- anyscale/client/openapi_client/models/service_event_fields.py +318 -0
- anyscale/client/openapi_client/models/sso_config.py +18 -18
- anyscale/client/openapi_client/models/supportedbaseimagesenum.py +139 -1
- anyscale/client/openapi_client/models/table_data_preview.py +209 -0
- anyscale/client/openapi_client/models/task_summary_config.py +29 -3
- anyscale/client/openapi_client/models/task_table_config.py +29 -3
- anyscale/client/openapi_client/models/unified_event.py +377 -0
- anyscale/client/openapi_client/models/unified_origin_filter.py +113 -0
- anyscale/client/openapi_client/models/unifiedevent_list_response.py +147 -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_event_fields.py +122 -0
- anyscale/client/openapi_client/models/workspace_template_version.py +58 -1
- anyscale/client/openapi_client/models/workspace_template_version_data_object.py +58 -1
- anyscale/cloud/models.py +2 -2
- anyscale/commands/cloud_commands.py +133 -2
- anyscale/commands/job_commands.py +121 -1
- anyscale/commands/job_queue_commands.py +99 -2
- anyscale/commands/service_commands.py +267 -67
- anyscale/commands/setup_k8s.py +546 -31
- 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/cloud_controller.py +15 -2
- anyscale/controllers/job_controller.py +12 -0
- anyscale/controllers/kubernetes_verifier.py +80 -66
- anyscale/controllers/workspace_controller.py +67 -5
- anyscale/job/_private/job_sdk.py +50 -2
- anyscale/job/commands.py +3 -0
- 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/apply_production_service_v2_model.py +31 -3
- anyscale/sdk/anyscale_client/models/apply_service_model.py +31 -3
- anyscale/sdk/anyscale_client/models/baseimagesenum.py +139 -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/rollout_strategy.py +2 -1
- anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +139 -1
- anyscale/sdk/anyscale_client/models/worker_node_type.py +29 -1
- anyscale/service/__init__.py +51 -3
- anyscale/service/_private/service_sdk.py +481 -58
- anyscale/service/commands.py +90 -4
- anyscale/service/models.py +56 -0
- 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.69.dist-info → anyscale-0.26.71.dist-info}/METADATA +1 -1
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/RECORD +112 -85
- anyscale/client/openapi_client/models/o_auth_connection_response.py +0 -229
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/WHEEL +0 -0
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/entry_points.txt +0 -0
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/licenses/LICENSE +0 -0
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/licenses/NOTICE +0 -0
- {anyscale-0.26.69.dist-info → anyscale-0.26.71.dist-info}/top_level.txt +0 -0
|
@@ -34,6 +34,7 @@ from anyscale.client.openapi_client.models import (
|
|
|
34
34
|
AdminCreateUser,
|
|
35
35
|
AnyscaleServiceAccount,
|
|
36
36
|
ApiKeyParameters,
|
|
37
|
+
ApplyProductionServiceMultiVersionV2Model,
|
|
37
38
|
ArchiveStatus,
|
|
38
39
|
Cloud,
|
|
39
40
|
CloudDataBucketAccessMode,
|
|
@@ -54,11 +55,14 @@ from anyscale.client.openapi_client.models import (
|
|
|
54
55
|
CreateOrganizationInvitation,
|
|
55
56
|
CreateResourceQuota,
|
|
56
57
|
CreateUserProjectCollaborator,
|
|
58
|
+
DecoratedCloudResource,
|
|
57
59
|
DecoratedComputeTemplate,
|
|
58
60
|
DecoratedjobqueueListResponse,
|
|
59
61
|
DecoratedlistserviceapimodelListResponse,
|
|
60
62
|
DecoratedProductionServiceV2APIModel,
|
|
63
|
+
DecoratedProductionServiceV2VersionAPIModel,
|
|
61
64
|
DecoratedSession,
|
|
65
|
+
DeleteResourceTagsRequest,
|
|
62
66
|
ExperimentalWorkspace,
|
|
63
67
|
GetOrCreateBuildFromImageUriRequest,
|
|
64
68
|
InternalProductionJob,
|
|
@@ -72,12 +76,14 @@ from anyscale.client.openapi_client.models import (
|
|
|
72
76
|
ProjectListResponse,
|
|
73
77
|
ResourceQuota,
|
|
74
78
|
ResourceQuotaStatus,
|
|
79
|
+
ResourceTagResourceType,
|
|
75
80
|
ServerSessionToken,
|
|
76
81
|
SessionSshKey,
|
|
77
82
|
SessionState,
|
|
78
83
|
StartSessionOptions,
|
|
79
84
|
StopSessionOptions,
|
|
80
85
|
SystemWorkloadName,
|
|
86
|
+
UpsertResourceTagsRequest,
|
|
81
87
|
WorkspaceDataplaneProxiedArtifacts,
|
|
82
88
|
WriteProject,
|
|
83
89
|
)
|
|
@@ -575,6 +581,14 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
575
581
|
cloud_id = self.get_cloud_id(cloud_name=name)
|
|
576
582
|
return self.get_cloud(cloud_id=cloud_id)
|
|
577
583
|
|
|
584
|
+
@handle_api_exceptions
|
|
585
|
+
def get_cloud_resource_by_name(
|
|
586
|
+
self, cloud_id: str, cloud_resource_name: str
|
|
587
|
+
) -> Optional[DecoratedCloudResource]:
|
|
588
|
+
return self._internal_api_client.find_cloud_resource_by_name_api_v2_clouds_cloud_id_find_cloud_resource_by_name_post(
|
|
589
|
+
cloud_id=cloud_id, cloud_resource_name=cloud_resource_name,
|
|
590
|
+
).result
|
|
591
|
+
|
|
578
592
|
@handle_api_exceptions
|
|
579
593
|
def get_default_cloud(self) -> Optional[Cloud]:
|
|
580
594
|
try:
|
|
@@ -702,9 +716,11 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
702
716
|
)
|
|
703
717
|
|
|
704
718
|
@handle_api_exceptions
|
|
705
|
-
def get_default_compute_config(
|
|
719
|
+
def get_default_compute_config(
|
|
720
|
+
self, *, cloud_id: str, cloud_resource_id: Optional[str] = None
|
|
721
|
+
) -> ClusterCompute:
|
|
706
722
|
return self._external_api_client.get_default_cluster_compute(
|
|
707
|
-
cloud_id=cloud_id,
|
|
723
|
+
cloud_id=cloud_id, cloud_resource_id=cloud_resource_id
|
|
708
724
|
).result
|
|
709
725
|
|
|
710
726
|
def _build_standard_compute_template_from_existing_auto_config(
|
|
@@ -1022,6 +1038,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1022
1038
|
*,
|
|
1023
1039
|
name: Optional[str] = None,
|
|
1024
1040
|
state_filter: Optional[List[str]] = None,
|
|
1041
|
+
tag_filter: Optional[List[str]] = None,
|
|
1025
1042
|
creator_id: Optional[str] = None,
|
|
1026
1043
|
cloud: Optional[str] = None,
|
|
1027
1044
|
project: Optional[str] = None,
|
|
@@ -1047,12 +1064,38 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1047
1064
|
archive_status=ArchiveStatus.ALL
|
|
1048
1065
|
if include_archived
|
|
1049
1066
|
else ArchiveStatus.NOT_ARCHIVED,
|
|
1067
|
+
tag_filter=tag_filter,
|
|
1050
1068
|
count=count if count else self.LIST_ENDPOINT_COUNT,
|
|
1051
1069
|
paging_token=paging_token,
|
|
1052
1070
|
sort_field=sort_field,
|
|
1053
1071
|
sort_order=sort_order,
|
|
1054
1072
|
)
|
|
1055
1073
|
|
|
1074
|
+
def get_service_versions(
|
|
1075
|
+
self, service_id: str, read_all_versions: bool = False,
|
|
1076
|
+
) -> List[DecoratedProductionServiceV2VersionAPIModel]:
|
|
1077
|
+
resp = self._internal_api_client.get_service_versions_api_v2_services_v2_service_id_versions_get(
|
|
1078
|
+
service_id=service_id,
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
if not read_all_versions:
|
|
1082
|
+
return resp.results
|
|
1083
|
+
|
|
1084
|
+
all_versions: List[DecoratedProductionServiceV2VersionAPIModel] = []
|
|
1085
|
+
all_versions.extend(resp.results)
|
|
1086
|
+
paging_token = resp.metadata.next_paging_token
|
|
1087
|
+
|
|
1088
|
+
while paging_token is not None:
|
|
1089
|
+
resp = self._internal_api_client.get_service_versions_api_v2_services_v2_service_id_versions_get(
|
|
1090
|
+
service_id=service_id,
|
|
1091
|
+
count=self.LIST_ENDPOINT_COUNT,
|
|
1092
|
+
paging_token=paging_token,
|
|
1093
|
+
)
|
|
1094
|
+
all_versions.extend(resp.results)
|
|
1095
|
+
paging_token = resp.metadata.next_paging_token
|
|
1096
|
+
|
|
1097
|
+
return all_versions
|
|
1098
|
+
|
|
1056
1099
|
@handle_api_exceptions
|
|
1057
1100
|
def get_project(self, project_id: str) -> Project:
|
|
1058
1101
|
return self._internal_api_client.get_project_api_v2_projects_project_id_get(
|
|
@@ -1206,6 +1249,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1206
1249
|
cluster_status: Optional[SessionState] = None,
|
|
1207
1250
|
project: Optional[str] = None,
|
|
1208
1251
|
cloud: Optional[str] = None,
|
|
1252
|
+
tags_filter: Optional[Dict[str, List[str]]] = None,
|
|
1209
1253
|
count: Optional[int] = None,
|
|
1210
1254
|
paging_token: Optional[str] = None,
|
|
1211
1255
|
sorting_directives: Optional[List[JobQueueSortDirective]] = None,
|
|
@@ -1224,6 +1268,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1224
1268
|
cluster_status=cluster_status,
|
|
1225
1269
|
project_id=project_id,
|
|
1226
1270
|
cloud_id=cloud_id,
|
|
1271
|
+
tags_filter=tags_filter,
|
|
1227
1272
|
paging=PageQuery(count=count, paging_token=paging_token),
|
|
1228
1273
|
sorting_directives=sorting_directives,
|
|
1229
1274
|
),
|
|
@@ -1238,6 +1283,15 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1238
1283
|
).result
|
|
1239
1284
|
return result
|
|
1240
1285
|
|
|
1286
|
+
@handle_api_exceptions
|
|
1287
|
+
def rollout_service_multi_version(
|
|
1288
|
+
self, model: ApplyProductionServiceMultiVersionV2Model
|
|
1289
|
+
) -> DecoratedProductionServiceV2APIModel:
|
|
1290
|
+
result = self._internal_api_client.apply_service_multi_version_api_v2_services_v2_apply_multi_version_put(
|
|
1291
|
+
model
|
|
1292
|
+
).result
|
|
1293
|
+
return result
|
|
1294
|
+
|
|
1241
1295
|
@handle_api_exceptions
|
|
1242
1296
|
def rollback_service(
|
|
1243
1297
|
self, service_id: str, *, max_surge_percent: Optional[int] = None
|
|
@@ -1493,7 +1547,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1493
1547
|
|
|
1494
1548
|
return all_log_chunk_urls, bearer_token
|
|
1495
1549
|
|
|
1496
|
-
def _read_log_lines(
|
|
1550
|
+
def _read_log_lines( # noqa: PLR0912
|
|
1497
1551
|
self,
|
|
1498
1552
|
log_chunk_urls: List[str],
|
|
1499
1553
|
head: bool,
|
|
@@ -1558,6 +1612,8 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1558
1612
|
if line_count == max_lines:
|
|
1559
1613
|
break
|
|
1560
1614
|
|
|
1615
|
+
if not result_lines:
|
|
1616
|
+
return ""
|
|
1561
1617
|
return "\n".join(result_lines) + "\n"
|
|
1562
1618
|
|
|
1563
1619
|
@handle_api_exceptions
|
|
@@ -1584,6 +1640,52 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
1584
1640
|
)
|
|
1585
1641
|
return logs
|
|
1586
1642
|
|
|
1643
|
+
@handle_api_exceptions
|
|
1644
|
+
def stream_logs_for_job_run(
|
|
1645
|
+
self, job_run_id: str, next_page_token: Optional[str] = None,
|
|
1646
|
+
) -> Tuple[str, Optional[str]]:
|
|
1647
|
+
"""Stream logs incrementally for a job run with pagination support.
|
|
1648
|
+
|
|
1649
|
+
Args:
|
|
1650
|
+
job_run_id: The ID of the job run to fetch logs for
|
|
1651
|
+
next_page_token: Token for fetching the next page of logs (for incremental streaming)
|
|
1652
|
+
|
|
1653
|
+
Returns:
|
|
1654
|
+
Tuple of (logs, next_page_token) where next_page_token can be used for the next call
|
|
1655
|
+
"""
|
|
1656
|
+
# Fetch only the new log chunks since the last call
|
|
1657
|
+
if next_page_token:
|
|
1658
|
+
# Incremental fetch - get only new chunks
|
|
1659
|
+
log_download_result = self._internal_api_client.get_job_logs_download_v2_api_v2_logs_job_logs_download_v2_job_id_get(
|
|
1660
|
+
job_id=job_run_id, next_page_token=next_page_token,
|
|
1661
|
+
).result
|
|
1662
|
+
else:
|
|
1663
|
+
# First fetch - get all available chunks
|
|
1664
|
+
log_download_result = self._internal_api_client.get_job_logs_download_v2_api_v2_logs_job_logs_download_v2_job_id_get(
|
|
1665
|
+
job_id=job_run_id,
|
|
1666
|
+
).result
|
|
1667
|
+
|
|
1668
|
+
# Download and concatenate log chunks
|
|
1669
|
+
log_chunk_urls = [chunk.chunk_url for chunk in log_download_result.log_chunks]
|
|
1670
|
+
bearer_token = log_download_result.bearer_token
|
|
1671
|
+
|
|
1672
|
+
logs = self._read_log_lines(
|
|
1673
|
+
log_chunk_urls,
|
|
1674
|
+
head=False,
|
|
1675
|
+
bearer_token=bearer_token,
|
|
1676
|
+
max_lines=None,
|
|
1677
|
+
parse_json=False,
|
|
1678
|
+
)
|
|
1679
|
+
|
|
1680
|
+
# Return logs and the token for the next page
|
|
1681
|
+
new_next_page_token = (
|
|
1682
|
+
log_download_result.next_page_token
|
|
1683
|
+
if len(log_download_result.log_chunks) > 0
|
|
1684
|
+
else next_page_token
|
|
1685
|
+
)
|
|
1686
|
+
|
|
1687
|
+
return logs, new_next_page_token
|
|
1688
|
+
|
|
1587
1689
|
@handle_api_exceptions
|
|
1588
1690
|
def controller_logs_for_service_version(
|
|
1589
1691
|
self,
|
|
@@ -2079,3 +2181,24 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
|
2079
2181
|
self._internal_api_client.set_resource_quota_status_api_v2_resource_quotas_resource_quota_id_status_patch(
|
|
2080
2182
|
resource_quota_id, ResourceQuotaStatus(is_enabled=is_enabled)
|
|
2081
2183
|
).result
|
|
2184
|
+
|
|
2185
|
+
@handle_api_exceptions
|
|
2186
|
+
def upsert_resource_tags(
|
|
2187
|
+
self,
|
|
2188
|
+
resource_type: ResourceTagResourceType,
|
|
2189
|
+
resource_id: str,
|
|
2190
|
+
tags: Dict[str, str],
|
|
2191
|
+
) -> None:
|
|
2192
|
+
req = UpsertResourceTagsRequest(
|
|
2193
|
+
resource_type=resource_type, resource_id=resource_id, tags=tags
|
|
2194
|
+
)
|
|
2195
|
+
self._internal_api_client.upsert_resource_tags_api_v2_tags_resource_put(req)
|
|
2196
|
+
|
|
2197
|
+
@handle_api_exceptions
|
|
2198
|
+
def delete_resource_tags(
|
|
2199
|
+
self, resource_type: ResourceTagResourceType, resource_id: str, keys: List[str],
|
|
2200
|
+
) -> None:
|
|
2201
|
+
req = DeleteResourceTagsRequest(
|
|
2202
|
+
resource_type=resource_type, resource_id=resource_id, keys=keys
|
|
2203
|
+
)
|
|
2204
|
+
self._internal_api_client.delete_resource_tags_api_v2_tags_resource_delete(req)
|
|
@@ -7,6 +7,7 @@ from anyscale.client.openapi_client.models import (
|
|
|
7
7
|
AdminCreatedUser,
|
|
8
8
|
AdminCreateUser,
|
|
9
9
|
AnyscaleServiceAccount,
|
|
10
|
+
ApplyProductionServiceMultiVersionV2Model,
|
|
10
11
|
Cloud,
|
|
11
12
|
ClusteroperationResponse,
|
|
12
13
|
CollaboratorType,
|
|
@@ -16,10 +17,12 @@ from anyscale.client.openapi_client.models import (
|
|
|
16
17
|
CreateInternalProductionJob,
|
|
17
18
|
CreateResourceQuota,
|
|
18
19
|
CreateUserProjectCollaborator,
|
|
20
|
+
DecoratedCloudResource,
|
|
19
21
|
DecoratedComputeTemplate,
|
|
20
22
|
DecoratedjobqueueListResponse,
|
|
21
23
|
DecoratedlistserviceapimodelListResponse,
|
|
22
24
|
DecoratedProductionServiceV2APIModel,
|
|
25
|
+
DecoratedProductionServiceV2VersionAPIModel,
|
|
23
26
|
InternalProductionJob,
|
|
24
27
|
JobQueueSortDirective,
|
|
25
28
|
OrganizationCollaborator,
|
|
@@ -28,6 +31,7 @@ from anyscale.client.openapi_client.models import (
|
|
|
28
31
|
ProjectBase,
|
|
29
32
|
ProjectListResponse,
|
|
30
33
|
ResourceQuota,
|
|
34
|
+
ResourceTagResourceType,
|
|
31
35
|
ServerSessionToken,
|
|
32
36
|
SessionState,
|
|
33
37
|
WorkspaceDataplaneProxiedArtifacts,
|
|
@@ -57,7 +61,7 @@ from anyscale.utils.workspace_notification import WorkspaceNotification
|
|
|
57
61
|
# Maybe just make it part of the release process to update it, or fetch the
|
|
58
62
|
# default builds and get the latest one. The best thing to do is probably
|
|
59
63
|
# to populate this in the backend.
|
|
60
|
-
DEFAULT_RAY_VERSION = "2.
|
|
64
|
+
DEFAULT_RAY_VERSION = "2.51.0" # RAY_RELEASE_UPDATE: update to latest version
|
|
61
65
|
DEFAULT_PYTHON_VERSION = "py311"
|
|
62
66
|
RUNTIME_ENV_PACKAGE_FORMAT = "pkg_{content_hash}.zip"
|
|
63
67
|
|
|
@@ -166,6 +170,13 @@ class AnyscaleClientInterface(ABC):
|
|
|
166
170
|
"""
|
|
167
171
|
raise NotImplementedError
|
|
168
172
|
|
|
173
|
+
@abstractmethod
|
|
174
|
+
def get_cloud_resource_by_name(
|
|
175
|
+
self, cloud_id: str, cloud_resource_name: str
|
|
176
|
+
) -> Optional[DecoratedCloudResource]:
|
|
177
|
+
"""Get a cloud resource by name."""
|
|
178
|
+
raise NotImplementedError
|
|
179
|
+
|
|
169
180
|
@abstractmethod
|
|
170
181
|
def get_default_cloud(self) -> Optional[Cloud]:
|
|
171
182
|
"""Get the user's default cloud."""
|
|
@@ -234,7 +245,9 @@ class AnyscaleClientInterface(ABC):
|
|
|
234
245
|
raise NotImplementedError
|
|
235
246
|
|
|
236
247
|
@abstractmethod
|
|
237
|
-
def get_default_compute_config(
|
|
248
|
+
def get_default_compute_config(
|
|
249
|
+
self, *, cloud_id: str, cloud_resource_id: Optional[str] = None
|
|
250
|
+
) -> ClusterCompute:
|
|
238
251
|
"""Get the default compute config for the provided cloud ID."""
|
|
239
252
|
raise NotImplementedError
|
|
240
253
|
|
|
@@ -345,6 +358,7 @@ class AnyscaleClientInterface(ABC):
|
|
|
345
358
|
*,
|
|
346
359
|
name: Optional[str],
|
|
347
360
|
state_filter: Optional[List[str]],
|
|
361
|
+
tag_filter: Optional[List[str]],
|
|
348
362
|
creator_id: Optional[str],
|
|
349
363
|
cloud: Optional[str],
|
|
350
364
|
project: Optional[str],
|
|
@@ -381,6 +395,13 @@ class AnyscaleClientInterface(ABC):
|
|
|
381
395
|
"""List projects."""
|
|
382
396
|
raise NotImplementedError
|
|
383
397
|
|
|
398
|
+
@abstractmethod
|
|
399
|
+
def get_service_versions(
|
|
400
|
+
self, service_id: str, read_all_versions: bool = False
|
|
401
|
+
) -> List[DecoratedProductionServiceV2VersionAPIModel]:
|
|
402
|
+
"""Get the versions of a service."""
|
|
403
|
+
raise NotImplementedError
|
|
404
|
+
|
|
384
405
|
@abstractmethod
|
|
385
406
|
def create_project(self, project: WriteProject) -> ProjectBase:
|
|
386
407
|
"""Create a project."""
|
|
@@ -453,6 +474,7 @@ class AnyscaleClientInterface(ABC):
|
|
|
453
474
|
cluster_status: Optional[SessionState] = None,
|
|
454
475
|
project: Optional[str] = None,
|
|
455
476
|
cloud: Optional[str] = None,
|
|
477
|
+
tags_filter: Optional[Dict[str, List[str]]] = None,
|
|
456
478
|
count: Optional[int] = None,
|
|
457
479
|
paging_token: Optional[str] = None,
|
|
458
480
|
sorting_directives: Optional[List[JobQueueSortDirective]] = None,
|
|
@@ -470,6 +492,16 @@ class AnyscaleClientInterface(ABC):
|
|
|
470
492
|
"""
|
|
471
493
|
raise NotImplementedError
|
|
472
494
|
|
|
495
|
+
@abstractmethod
|
|
496
|
+
def rollout_service_multi_version(
|
|
497
|
+
self, model: ApplyProductionServiceMultiVersionV2Model
|
|
498
|
+
) -> DecoratedProductionServiceV2APIModel:
|
|
499
|
+
"""Deploy or update the service to use the provided multi-version configs.
|
|
500
|
+
|
|
501
|
+
Returns the service ID.
|
|
502
|
+
"""
|
|
503
|
+
raise NotImplementedError
|
|
504
|
+
|
|
473
505
|
@abstractmethod
|
|
474
506
|
def rollback_service(
|
|
475
507
|
self, service_id: str, *, max_surge_percent: Optional[int] = None
|
|
@@ -821,3 +853,20 @@ class AnyscaleClientInterface(ABC):
|
|
|
821
853
|
) -> None:
|
|
822
854
|
"""Set the status of a resource quota."""
|
|
823
855
|
raise NotImplementedError
|
|
856
|
+
|
|
857
|
+
@abstractmethod
|
|
858
|
+
def upsert_resource_tags(
|
|
859
|
+
self,
|
|
860
|
+
resource_type: ResourceTagResourceType,
|
|
861
|
+
resource_id: str,
|
|
862
|
+
tags: Dict[str, str],
|
|
863
|
+
) -> None:
|
|
864
|
+
"""Upsert tags (add/update) for a resource."""
|
|
865
|
+
raise NotImplementedError
|
|
866
|
+
|
|
867
|
+
@abstractmethod
|
|
868
|
+
def delete_resource_tags(
|
|
869
|
+
self, resource_type: ResourceTagResourceType, resource_id: str, keys: List[str],
|
|
870
|
+
) -> None:
|
|
871
|
+
"""Delete tags for the provided keys from a resource."""
|
|
872
|
+
raise NotImplementedError
|
|
@@ -2,7 +2,7 @@ from collections import defaultdict
|
|
|
2
2
|
from datetime import date, datetime
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
-
from typing import DefaultDict, Dict, Generator, List, Optional, Tuple
|
|
5
|
+
from typing import DefaultDict, Dict, Generator, List, Optional, Tuple, Union
|
|
6
6
|
from unittest.mock import Mock
|
|
7
7
|
import uuid
|
|
8
8
|
|
|
@@ -16,6 +16,7 @@ from anyscale.client.openapi_client.models import (
|
|
|
16
16
|
AdminCreatedUser,
|
|
17
17
|
AdminCreateUser,
|
|
18
18
|
AnyscaleServiceAccount,
|
|
19
|
+
ApplyProductionServiceMultiVersionV2Model,
|
|
19
20
|
Cloud,
|
|
20
21
|
CloudProviders,
|
|
21
22
|
ClusterOperation,
|
|
@@ -28,9 +29,11 @@ from anyscale.client.openapi_client.models import (
|
|
|
28
29
|
CreateInternalProductionJob,
|
|
29
30
|
CreateResourceQuota,
|
|
30
31
|
CreateUserProjectCollaborator,
|
|
32
|
+
DecoratedCloudResource,
|
|
31
33
|
DecoratedComputeTemplate,
|
|
32
34
|
DecoratedlistserviceapimodelListResponse,
|
|
33
35
|
DecoratedProductionServiceV2APIModel,
|
|
36
|
+
DecoratedProductionServiceV2VersionAPIModel,
|
|
34
37
|
DeletedPlatformFineTunedModel,
|
|
35
38
|
ExperimentalWorkspace,
|
|
36
39
|
FineTunedModel,
|
|
@@ -50,6 +53,7 @@ from anyscale.client.openapi_client.models import (
|
|
|
50
53
|
ProjectBase,
|
|
51
54
|
ProjectListResponse,
|
|
52
55
|
ResourceQuota,
|
|
56
|
+
ResourceTagResourceType,
|
|
53
57
|
ServerSessionToken,
|
|
54
58
|
WorkspaceDataplaneProxiedArtifacts,
|
|
55
59
|
WriteProject,
|
|
@@ -153,6 +157,9 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
153
157
|
self._workspace_cluster: Optional[Cluster] = None
|
|
154
158
|
self._workspace_dependency_tracking_enabled: bool = False
|
|
155
159
|
self._services: Dict[str, DecoratedProductionServiceV2APIModel] = {}
|
|
160
|
+
self._versions: Dict[
|
|
161
|
+
str, Dict[str, ProductionServiceV2VersionModel]
|
|
162
|
+
] = defaultdict(dict)
|
|
156
163
|
self._archived_services: Dict[str, DecoratedProductionServiceV2APIModel] = {}
|
|
157
164
|
self._deleted_services: Dict[str, DecoratedProductionServiceV2APIModel] = {}
|
|
158
165
|
self._jobs: Dict[str, ProductionJob] = {}
|
|
@@ -409,6 +416,11 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
409
416
|
return c
|
|
410
417
|
return None
|
|
411
418
|
|
|
419
|
+
def get_cloud_resource_by_name(
|
|
420
|
+
self, cloud_id: str, cloud_resource_name: str # noqa: ARG002
|
|
421
|
+
) -> Optional[DecoratedCloudResource]:
|
|
422
|
+
return None
|
|
423
|
+
|
|
412
424
|
def get_default_cloud(self) -> Optional[Cloud]:
|
|
413
425
|
return self._clouds.get(self.DEFAULT_CLOUD_ID, None)
|
|
414
426
|
|
|
@@ -536,7 +548,9 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
536
548
|
):
|
|
537
549
|
self._default_compute_configs[cloud_id] = compute_config
|
|
538
550
|
|
|
539
|
-
def get_default_compute_config(
|
|
551
|
+
def get_default_compute_config(
|
|
552
|
+
self, *, cloud_id: str, cloud_resource_id: Optional[str] = None # noqa: ARG002
|
|
553
|
+
) -> ClusterCompute:
|
|
540
554
|
return self._default_compute_configs[cloud_id]
|
|
541
555
|
|
|
542
556
|
def list_cluster_env_builds(
|
|
@@ -658,6 +672,9 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
658
672
|
|
|
659
673
|
def update_service(self, model: DecoratedProductionServiceV2APIModel):
|
|
660
674
|
self._services[model.id] = model
|
|
675
|
+
if model.versions is not None:
|
|
676
|
+
for version in model.versions:
|
|
677
|
+
self._versions[model.id][version.id] = version
|
|
661
678
|
|
|
662
679
|
def get_service(
|
|
663
680
|
self,
|
|
@@ -897,7 +914,11 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
897
914
|
return project_id
|
|
898
915
|
|
|
899
916
|
@property
|
|
900
|
-
def rolled_out_model(
|
|
917
|
+
def rolled_out_model(
|
|
918
|
+
self,
|
|
919
|
+
) -> Optional[
|
|
920
|
+
Union[ApplyProductionServiceV2Model, ApplyProductionServiceMultiVersionV2Model]
|
|
921
|
+
]:
|
|
901
922
|
return self._rolled_out_model
|
|
902
923
|
|
|
903
924
|
def rollout_service(
|
|
@@ -917,6 +938,18 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
917
938
|
else:
|
|
918
939
|
service_id = f"service-id-{uuid.uuid4()!s}"
|
|
919
940
|
|
|
941
|
+
primary_version = ProductionServiceV2VersionModel(
|
|
942
|
+
id=str(uuid.uuid4()),
|
|
943
|
+
created_at=datetime.now(),
|
|
944
|
+
version=model.version,
|
|
945
|
+
current_state=ServiceVersionState.RUNNING,
|
|
946
|
+
weight=100,
|
|
947
|
+
build_id=model.build_id,
|
|
948
|
+
compute_config_id=model.compute_config_id,
|
|
949
|
+
ray_serve_config=model.ray_serve_config,
|
|
950
|
+
ray_gcs_external_storage_config=model.ray_gcs_external_storage_config,
|
|
951
|
+
local_vars_configuration=OPENAPI_NO_VALIDATION,
|
|
952
|
+
)
|
|
920
953
|
service = DecoratedProductionServiceV2APIModel(
|
|
921
954
|
id=service_id,
|
|
922
955
|
name=model.name,
|
|
@@ -925,18 +958,56 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
925
958
|
current_state=ServiceEventCurrentState.STARTING,
|
|
926
959
|
base_url=f"http://{model.name}.fake.url",
|
|
927
960
|
auth_token="fake-auth-token",
|
|
928
|
-
primary_version=
|
|
961
|
+
primary_version=primary_version,
|
|
962
|
+
versions=[primary_version],
|
|
963
|
+
local_vars_configuration=OPENAPI_NO_VALIDATION,
|
|
964
|
+
)
|
|
965
|
+
self.update_service(service)
|
|
966
|
+
return service
|
|
967
|
+
|
|
968
|
+
def rollout_service_multi_version(
|
|
969
|
+
self, model: ApplyProductionServiceMultiVersionV2Model
|
|
970
|
+
) -> DecoratedProductionServiceV2APIModel:
|
|
971
|
+
self._rolled_out_model = model
|
|
972
|
+
version = model.service_versions[0]
|
|
973
|
+
project_model = self.get_project(version.project_id)
|
|
974
|
+
project = project_model.name if project_model else None
|
|
975
|
+
compute_config = self.get_compute_config(version.compute_config_id)
|
|
976
|
+
cloud_id = compute_config.config.cloud_id if compute_config else None
|
|
977
|
+
cloud_model = self.get_cloud(cloud_id=cloud_id)
|
|
978
|
+
cloud = cloud_model.name if cloud_model else None
|
|
979
|
+
existing_service = self.get_service(version.name, project=project, cloud=cloud)
|
|
980
|
+
if existing_service is not None:
|
|
981
|
+
service_id = existing_service.id
|
|
982
|
+
else:
|
|
983
|
+
service_id = f"service-id-{uuid.uuid4()!s}"
|
|
984
|
+
|
|
985
|
+
service_versions = []
|
|
986
|
+
for version in model.service_versions:
|
|
987
|
+
service_version = ProductionServiceV2VersionModel(
|
|
929
988
|
id=str(uuid.uuid4()),
|
|
930
989
|
created_at=datetime.now(),
|
|
931
|
-
version=
|
|
990
|
+
version=version.version,
|
|
932
991
|
current_state=ServiceVersionState.RUNNING,
|
|
933
|
-
weight=
|
|
934
|
-
build_id=
|
|
935
|
-
compute_config_id=
|
|
936
|
-
ray_serve_config=
|
|
937
|
-
ray_gcs_external_storage_config=
|
|
992
|
+
weight=version.traffic_percent,
|
|
993
|
+
build_id=version.build_id,
|
|
994
|
+
compute_config_id=version.compute_config_id,
|
|
995
|
+
ray_serve_config=version.ray_serve_config,
|
|
996
|
+
ray_gcs_external_storage_config=version.ray_gcs_external_storage_config,
|
|
938
997
|
local_vars_configuration=OPENAPI_NO_VALIDATION,
|
|
939
|
-
)
|
|
998
|
+
)
|
|
999
|
+
service_versions.append(service_version)
|
|
1000
|
+
|
|
1001
|
+
service = DecoratedProductionServiceV2APIModel(
|
|
1002
|
+
id=service_id,
|
|
1003
|
+
name=version.name,
|
|
1004
|
+
project_id=version.project_id,
|
|
1005
|
+
cloud_id=self.get_cloud_id(compute_config_id=version.compute_config_id),
|
|
1006
|
+
current_state=ServiceEventCurrentState.STARTING,
|
|
1007
|
+
base_url=f"http://{version.name}.fake.url",
|
|
1008
|
+
auth_token="fake-auth-token",
|
|
1009
|
+
primary_version="",
|
|
1010
|
+
versions=service_versions,
|
|
940
1011
|
local_vars_configuration=OPENAPI_NO_VALIDATION,
|
|
941
1012
|
)
|
|
942
1013
|
self.update_service(service)
|
|
@@ -1551,6 +1622,7 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
1551
1622
|
*,
|
|
1552
1623
|
name: Optional[str] = None,
|
|
1553
1624
|
state_filter: Optional[List[str]] = None,
|
|
1625
|
+
tag_filter: Optional[List[str]] = None, # noqa: ARG002
|
|
1554
1626
|
creator_id: Optional[str] = None, # noqa: ARG002
|
|
1555
1627
|
cloud: Optional[str] = None,
|
|
1556
1628
|
project: Optional[str] = None,
|
|
@@ -1603,3 +1675,23 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
|
1603
1675
|
local_vars_configuration=OPENAPI_NO_VALIDATION,
|
|
1604
1676
|
)
|
|
1605
1677
|
return response
|
|
1678
|
+
|
|
1679
|
+
def get_service_versions(
|
|
1680
|
+
self, service_id: str, read_all_versions: bool = False # noqa: ARG002
|
|
1681
|
+
) -> List[DecoratedProductionServiceV2VersionAPIModel]:
|
|
1682
|
+
return list(self._versions[service_id].values())
|
|
1683
|
+
|
|
1684
|
+
def upsert_resource_tags(
|
|
1685
|
+
self,
|
|
1686
|
+
resource_type: ResourceTagResourceType,
|
|
1687
|
+
resource_id: str,
|
|
1688
|
+
tags: Dict[str, str],
|
|
1689
|
+
) -> None:
|
|
1690
|
+
_ = resource_type, resource_id, tags
|
|
1691
|
+
return None
|
|
1692
|
+
|
|
1693
|
+
def delete_resource_tags(
|
|
1694
|
+
self, resource_type: ResourceTagResourceType, resource_id: str, keys: List[str],
|
|
1695
|
+
) -> None:
|
|
1696
|
+
_ = resource_type, resource_id, keys
|
|
1697
|
+
return None
|