anyscale 0.25.0__py3-none-any.whl → 0.25.2__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/__init__.py +10 -0
- anyscale/_private/anyscale_client/anyscale_client.py +35 -9
- anyscale/_private/anyscale_client/common.py +32 -3
- anyscale/_private/anyscale_client/fake_anyscale_client.py +69 -6
- anyscale/_private/docgen/__main__.py +9 -2
- anyscale/_private/docgen/api.md +13 -0
- anyscale/_private/docgen/models.md +3 -3
- anyscale/client/README.md +4 -0
- anyscale/client/openapi_client/__init__.py +2 -0
- anyscale/client/openapi_client/api/default_api.py +233 -0
- anyscale/client/openapi_client/models/__init__.py +2 -0
- anyscale/client/openapi_client/models/baseimagesenum.py +43 -1
- anyscale/client/openapi_client/models/decorated_interactive_session.py +1 -57
- anyscale/client/openapi_client/models/decorated_job.py +1 -57
- anyscale/client/openapi_client/models/decorated_job_submission.py +1 -29
- anyscale/client/openapi_client/models/decorated_production_job.py +1 -29
- anyscale/client/openapi_client/models/decorated_session.py +1 -57
- anyscale/client/openapi_client/models/decorated_unified_job.py +1 -30
- anyscale/client/openapi_client/models/ha_jobs_sort_field.py +1 -2
- anyscale/client/openapi_client/models/internal_production_job.py +1 -29
- anyscale/client/openapi_client/models/jobs_sort_field.py +1 -2
- anyscale/client/openapi_client/models/serve_deployment_fast_api_docs_status.py +123 -0
- anyscale/client/openapi_client/models/serve_deployment_state.py +2 -1
- anyscale/client/openapi_client/models/servedeploymentfastapidocsstatus_response.py +121 -0
- anyscale/client/openapi_client/models/sessions_sort_field.py +1 -2
- anyscale/client/openapi_client/models/supportedbaseimagesenum.py +43 -1
- anyscale/client/openapi_client/models/unified_job_sort_field.py +1 -2
- anyscale/commands/cloud_commands.py +25 -8
- anyscale/commands/service_account_commands.py +65 -8
- anyscale/controllers/cloud_controller.py +29 -21
- anyscale/controllers/cluster_controller.py +1 -9
- anyscale/controllers/job_controller.py +0 -3
- anyscale/resource_quota/_private/resource_quota_sdk.py +15 -6
- anyscale/sdk/anyscale_client/api/default_api.py +119 -0
- anyscale/sdk/anyscale_client/models/baseimagesenum.py +43 -1
- anyscale/sdk/anyscale_client/models/jobs_sort_field.py +1 -2
- anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +43 -1
- anyscale/service_account/__init__.py +88 -0
- anyscale/service_account/_private/service_account_sdk.py +101 -0
- anyscale/service_account/commands.py +147 -0
- anyscale/service_account/models.py +66 -0
- anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
- anyscale/shared_anyscale_utils/utils/id_gen.py +1 -0
- anyscale/util.py +8 -0
- anyscale/version.py +1 -1
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/METADATA +1 -1
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/RECORD +52 -47
- anyscale/controllers/service_account_controller.py +0 -168
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/LICENSE +0 -0
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/NOTICE +0 -0
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/WHEEL +0 -0
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/entry_points.txt +0 -0
- {anyscale-0.25.0.dist-info → anyscale-0.25.2.dist-info}/top_level.txt +0 -0
anyscale/__init__.py
CHANGED
@@ -31,6 +31,7 @@ from anyscale import (
|
|
31
31
|
resource_quota,
|
32
32
|
schedule,
|
33
33
|
service,
|
34
|
+
service_account,
|
34
35
|
user,
|
35
36
|
)
|
36
37
|
from anyscale._private.anyscale_client import AnyscaleClient, AnyscaleClientInterface
|
@@ -52,6 +53,7 @@ from anyscale.resource_quota import ResourceQuotaSDK
|
|
52
53
|
from anyscale.schedule import ScheduleSDK
|
53
54
|
from anyscale.sdk.anyscale_client.sdk import AnyscaleSDK
|
54
55
|
from anyscale.service import ServiceSDK
|
56
|
+
from anyscale.service_account import ServiceAccountSDK
|
55
57
|
from anyscale.user import UserSDK
|
56
58
|
from anyscale.workspace import WorkspaceSDK
|
57
59
|
|
@@ -128,6 +130,7 @@ class Anyscale:
|
|
128
130
|
)
|
129
131
|
self._project_sdk = ProjectSDK(client=self._anyscale_client)
|
130
132
|
self._resource_quota_sdk = ResourceQuotaSDK(client=self._anyscale_client)
|
133
|
+
self._service_account_sdk = ServiceAccountSDK(client=self._anyscale_client)
|
131
134
|
self._user_sdk = UserSDK(client=self._anyscale_client)
|
132
135
|
self._workspace_sdk = WorkspaceSDK(client=self._anyscale_client)
|
133
136
|
|
@@ -162,6 +165,9 @@ class Anyscale:
|
|
162
165
|
obj._project_sdk = ProjectSDK( # noqa: SLF001
|
163
166
|
client=client, logger=logger, timer=timer
|
164
167
|
)
|
168
|
+
obj._service_account_sdk = ServiceAccountSDK( # noqa: SLF001
|
169
|
+
client=client, logger=logger, timer=timer
|
170
|
+
)
|
165
171
|
obj._user_sdk = UserSDK( # noqa: SLF001
|
166
172
|
client=client, logger=logger, timer=timer
|
167
173
|
)
|
@@ -217,6 +223,10 @@ class Anyscale:
|
|
217
223
|
def resource_quota(self) -> ResourceQuotaSDK: # noqa: F811
|
218
224
|
return self._resource_quota_sdk
|
219
225
|
|
226
|
+
@property
|
227
|
+
def service_account(self) -> ServiceAccountSDK: # noqa: F811
|
228
|
+
return self._service_account_sdk
|
229
|
+
|
220
230
|
@property
|
221
231
|
def user(self) -> UserSDK: # noqa: F811
|
222
232
|
return self._user_sdk
|
@@ -36,6 +36,8 @@ from anyscale.client.openapi_client.api.default_api import DefaultApi as Interna
|
|
36
36
|
from anyscale.client.openapi_client.models import (
|
37
37
|
AdminCreatedUser,
|
38
38
|
AdminCreateUser,
|
39
|
+
AnyscaleServiceAccount,
|
40
|
+
ApiKeyParameters,
|
39
41
|
ArchiveStatus,
|
40
42
|
Cloud,
|
41
43
|
CloudDataBucketAccessMode,
|
@@ -69,6 +71,7 @@ from anyscale.client.openapi_client.models import (
|
|
69
71
|
OrganizationInvitation,
|
70
72
|
ResourceQuota,
|
71
73
|
ResourceQuotaStatus,
|
74
|
+
ServerSessionToken,
|
72
75
|
SessionSshKey,
|
73
76
|
StartSessionOptions,
|
74
77
|
StopSessionOptions,
|
@@ -1860,6 +1863,20 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1860
1863
|
|
1861
1864
|
return filepath
|
1862
1865
|
|
1866
|
+
@handle_api_exceptions
|
1867
|
+
def create_api_key(
|
1868
|
+
self, duration: float, user_id: Optional[str]
|
1869
|
+
) -> ServerSessionToken:
|
1870
|
+
return self._internal_api_client.create_api_key_api_v2_users_create_api_key_post(
|
1871
|
+
ApiKeyParameters(user_id=user_id, duration=duration)
|
1872
|
+
).result
|
1873
|
+
|
1874
|
+
@handle_api_exceptions
|
1875
|
+
def rotate_api_key(self, user_id: str) -> None:
|
1876
|
+
self._internal_api_client.rotate_api_key_for_user_api_v2_organization_collaborators_rotate_api_key_for_user_user_id_post(
|
1877
|
+
user_id
|
1878
|
+
)
|
1879
|
+
|
1863
1880
|
@handle_api_exceptions
|
1864
1881
|
def admin_batch_create_users(
|
1865
1882
|
self, admin_create_users: List[AdminCreateUser]
|
@@ -1915,20 +1932,29 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1915
1932
|
).result
|
1916
1933
|
|
1917
1934
|
@handle_api_exceptions
|
1918
|
-
def
|
1935
|
+
def get_organization_collaborators(
|
1936
|
+
self,
|
1937
|
+
email: Optional[str] = None,
|
1938
|
+
name: Optional[str] = None,
|
1939
|
+
is_service_account: Optional[bool] = None,
|
1940
|
+
) -> List[OrganizationCollaborator]:
|
1919
1941
|
results = self._internal_api_client.list_organization_collaborators_api_v2_organization_collaborators_get(
|
1920
|
-
email=email
|
1942
|
+
email=email, name=name, is_service_account=is_service_account
|
1921
1943
|
).results
|
1922
1944
|
|
1923
|
-
|
1924
|
-
raise ValueError(f"User with email '{email}' not found.")
|
1945
|
+
return results
|
1925
1946
|
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1947
|
+
@handle_api_exceptions
|
1948
|
+
def delete_organization_collaborator(self, identity_id: str) -> None:
|
1949
|
+
self._internal_api_client.remove_organization_collaborator_api_v2_organization_collaborators_identity_id_delete(
|
1950
|
+
identity_id
|
1951
|
+
)
|
1930
1952
|
|
1931
|
-
|
1953
|
+
@handle_api_exceptions
|
1954
|
+
def create_service_account(self, name: str) -> AnyscaleServiceAccount:
|
1955
|
+
return self._internal_api_client.create_service_account_api_v2_users_service_accounts_post(
|
1956
|
+
name
|
1957
|
+
).result
|
1932
1958
|
|
1933
1959
|
@handle_api_exceptions
|
1934
1960
|
def create_resource_quota(
|
@@ -6,6 +6,7 @@ from anyscale._private.models.image_uri import ImageURI
|
|
6
6
|
from anyscale.client.openapi_client.models import (
|
7
7
|
AdminCreatedUser,
|
8
8
|
AdminCreateUser,
|
9
|
+
AnyscaleServiceAccount,
|
9
10
|
Cloud,
|
10
11
|
ComputeTemplateConfig,
|
11
12
|
CreateCloudCollaborator,
|
@@ -21,6 +22,7 @@ from anyscale.client.openapi_client.models import (
|
|
21
22
|
OrganizationInvitation,
|
22
23
|
Project,
|
23
24
|
ResourceQuota,
|
25
|
+
ServerSessionToken,
|
24
26
|
WorkspaceDataplaneProxiedArtifacts,
|
25
27
|
)
|
26
28
|
from anyscale.client.openapi_client.models.create_schedule import CreateSchedule
|
@@ -47,7 +49,7 @@ from anyscale.utils.workspace_notification import WorkspaceNotification
|
|
47
49
|
# Maybe just make it part of the release process to update it, or fetch the
|
48
50
|
# default builds and get the latest one. The best thing to do is probably
|
49
51
|
# to populate this in the backend.
|
50
|
-
DEFAULT_RAY_VERSION = "2.
|
52
|
+
DEFAULT_RAY_VERSION = "2.41.0" # RAY_RELEASE_UPDATE: update to latest version.
|
51
53
|
DEFAULT_PYTHON_VERSION = "py311"
|
52
54
|
RUNTIME_ENV_PACKAGE_FORMAT = "pkg_{content_hash}.zip"
|
53
55
|
|
@@ -614,6 +616,18 @@ class AnyscaleClientInterface(ABC):
|
|
614
616
|
"""Download the aggregated instance usage csv."""
|
615
617
|
raise NotImplementedError
|
616
618
|
|
619
|
+
@abstractmethod
|
620
|
+
def create_api_key(
|
621
|
+
self, duration: float, user_id: Optional[str]
|
622
|
+
) -> ServerSessionToken:
|
623
|
+
"""Create a new API key."""
|
624
|
+
raise NotImplementedError
|
625
|
+
|
626
|
+
@abstractmethod
|
627
|
+
def rotate_api_key(self, user_id: str) -> None:
|
628
|
+
"""Rotate the API key for user."""
|
629
|
+
raise NotImplementedError
|
630
|
+
|
617
631
|
@abstractmethod
|
618
632
|
def admin_batch_create_users(
|
619
633
|
self, admin_create_users: List[AdminCreateUser]
|
@@ -639,8 +653,23 @@ class AnyscaleClientInterface(ABC):
|
|
639
653
|
raise NotImplementedError
|
640
654
|
|
641
655
|
@abstractmethod
|
642
|
-
def
|
643
|
-
|
656
|
+
def get_organization_collaborators(
|
657
|
+
self,
|
658
|
+
email: Optional[str] = None,
|
659
|
+
name: Optional[str] = None,
|
660
|
+
is_service_account: Optional[bool] = None,
|
661
|
+
) -> List[OrganizationCollaborator]:
|
662
|
+
"""Get organization collaborators."""
|
663
|
+
raise NotImplementedError
|
664
|
+
|
665
|
+
@abstractmethod
|
666
|
+
def delete_organization_collaborator(self, identity_id: str) -> None:
|
667
|
+
"""Delete organization collaborator."""
|
668
|
+
raise NotImplementedError
|
669
|
+
|
670
|
+
@abstractmethod
|
671
|
+
def create_service_account(self, name: str) -> AnyscaleServiceAccount:
|
672
|
+
"""Create a service account."""
|
644
673
|
raise NotImplementedError
|
645
674
|
|
646
675
|
@abstractmethod
|
@@ -16,6 +16,7 @@ from anyscale.cli_logger import BlockLogger
|
|
16
16
|
from anyscale.client.openapi_client.models import (
|
17
17
|
AdminCreatedUser,
|
18
18
|
AdminCreateUser,
|
19
|
+
AnyscaleServiceAccount,
|
19
20
|
Cloud,
|
20
21
|
CloudProviders,
|
21
22
|
ComputeTemplateConfig,
|
@@ -41,6 +42,7 @@ from anyscale.client.openapi_client.models import (
|
|
41
42
|
ProductionJobStateTransition,
|
42
43
|
Project,
|
43
44
|
ResourceQuota,
|
45
|
+
ServerSessionToken,
|
44
46
|
WorkspaceDataplaneProxiedArtifacts,
|
45
47
|
)
|
46
48
|
from anyscale.client.openapi_client.models.create_schedule import CreateSchedule
|
@@ -165,6 +167,8 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
165
167
|
self._workspaces_env_vars: Dict[str, Dict[str, str]] = {}
|
166
168
|
self._clusters_headnode_ip: Dict[str, str] = {}
|
167
169
|
self._clusters_ssh_key: Dict[str, SessionSshKey] = {}
|
170
|
+
self._api_keys: Dict[str, List[str]] = defaultdict(list)
|
171
|
+
self._organization_collaborators: List[OrganizationCollaborator] = []
|
168
172
|
self._organization_invitations: Dict[str, OrganizationInvitation] = {}
|
169
173
|
self._resource_quotas: Dict[str, ResourceQuota] = {}
|
170
174
|
|
@@ -1139,6 +1143,20 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
1139
1143
|
|
1140
1144
|
return filepath
|
1141
1145
|
|
1146
|
+
def create_api_key(
|
1147
|
+
self, duration: float, user_id: Optional[str] # noqa: ARG002
|
1148
|
+
) -> ServerSessionToken:
|
1149
|
+
api_key = f"{uuid.uuid4()!s}"
|
1150
|
+
api_keys = self._api_keys.get(user_id or "usr_1", [])
|
1151
|
+
self._api_keys[user_id or "usr_1"] = api_keys + [api_key]
|
1152
|
+
|
1153
|
+
return ServerSessionToken(server_session_id=api_key)
|
1154
|
+
|
1155
|
+
def rotate_api_key(self, user_id: str) -> None:
|
1156
|
+
if user_id not in self._api_keys:
|
1157
|
+
raise ValueError(f"User '{user_id}' not found.")
|
1158
|
+
self._api_keys[user_id] = [f"{uuid.uuid4()!s}"]
|
1159
|
+
|
1142
1160
|
def admin_batch_create_users(
|
1143
1161
|
self, admin_create_users: List[AdminCreateUser]
|
1144
1162
|
) -> List[AdminCreatedUser]:
|
@@ -1195,14 +1213,59 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
1195
1213
|
|
1196
1214
|
return self._organization_invitations.pop(email)
|
1197
1215
|
|
1198
|
-
def
|
1199
|
-
|
1200
|
-
|
1216
|
+
def get_organization_collaborators(
|
1217
|
+
self,
|
1218
|
+
email: Optional[str] = None,
|
1219
|
+
name: Optional[str] = None,
|
1220
|
+
is_service_account: Optional[bool] = None, # noqa: ARG002
|
1221
|
+
) -> List[OrganizationCollaborator]:
|
1222
|
+
# Since organization collaborator doesn't include whether it's a service account or not, we'll just return all
|
1223
|
+
results = []
|
1224
|
+
for organization_collaborator in self._organization_collaborators:
|
1225
|
+
if email and organization_collaborator.email != email:
|
1226
|
+
continue
|
1227
|
+
if name and organization_collaborator.name != name:
|
1228
|
+
continue
|
1229
|
+
|
1230
|
+
results.append(organization_collaborator)
|
1231
|
+
|
1232
|
+
return results
|
1233
|
+
|
1234
|
+
def delete_organization_collaborator(self, identity_id: str) -> None:
|
1235
|
+
for organization_collaborator in self._organization_collaborators:
|
1236
|
+
if organization_collaborator.id == identity_id:
|
1237
|
+
self._organization_collaborators.remove(organization_collaborator)
|
1238
|
+
return
|
1239
|
+
|
1240
|
+
raise ValueError(
|
1241
|
+
f"Organization collaborator with id '{identity_id}' not found."
|
1242
|
+
)
|
1243
|
+
|
1244
|
+
def create_service_account(self, name) -> AnyscaleServiceAccount:
|
1245
|
+
for organization_collaborator in self._organization_collaborators:
|
1246
|
+
if organization_collaborator.name == name:
|
1247
|
+
raise ValueError(f"Service account with name '{name}' already exists.")
|
1248
|
+
|
1249
|
+
identity_id = f"id_{uuid.uuid4()!s}"
|
1250
|
+
user_id = f"usr_{uuid.uuid4()!s}"
|
1251
|
+
organization_collaborator = OrganizationCollaborator(
|
1201
1252
|
permission_level=OrganizationPermissionLevel.COLLABORATOR,
|
1202
|
-
|
1253
|
+
id=identity_id,
|
1254
|
+
name=name,
|
1255
|
+
email=f"{name}@service-account.com",
|
1256
|
+
user_id=user_id,
|
1203
1257
|
created_at=datetime.utcnow(),
|
1204
|
-
|
1205
|
-
|
1258
|
+
)
|
1259
|
+
|
1260
|
+
self._organization_collaborators.append((organization_collaborator))
|
1261
|
+
|
1262
|
+
return AnyscaleServiceAccount(
|
1263
|
+
user_id=organization_collaborator.user_id,
|
1264
|
+
name=organization_collaborator.name,
|
1265
|
+
organization_id="org_1",
|
1266
|
+
email=organization_collaborator.email,
|
1267
|
+
permission_level=organization_collaborator.permission_level,
|
1268
|
+
created_at=organization_collaborator.created_at,
|
1206
1269
|
)
|
1207
1270
|
|
1208
1271
|
def create_resource_quota(
|
@@ -76,6 +76,7 @@ from anyscale.service.models import (
|
|
76
76
|
ServiceVersionStatus,
|
77
77
|
TracingConfig,
|
78
78
|
)
|
79
|
+
from anyscale.service_account.models import OrganizationPermissionLevel, ServiceAccount
|
79
80
|
from anyscale.user.models import AdminCreatedUser, AdminCreateUser
|
80
81
|
from anyscale.workspace.models import WorkspaceConfig
|
81
82
|
|
@@ -356,8 +357,14 @@ ALL_MODULES = [
|
|
356
357
|
service_account_commands.rotate_api_keys,
|
357
358
|
],
|
358
359
|
sdk_prefix="anyscale.service_account",
|
359
|
-
sdk_commands=[
|
360
|
-
|
360
|
+
sdk_commands=[
|
361
|
+
anyscale.service_account.create,
|
362
|
+
anyscale.service_account.create_api_key,
|
363
|
+
anyscale.service_account.list,
|
364
|
+
anyscale.service_account.delete,
|
365
|
+
anyscale.service_account.rotate_api_keys,
|
366
|
+
],
|
367
|
+
models=[ServiceAccount, OrganizationPermissionLevel],
|
361
368
|
),
|
362
369
|
Module(
|
363
370
|
title="Image",
|
anyscale/_private/docgen/api.md
CHANGED
@@ -949,6 +949,18 @@ Returns [ProductionjobResponse](./models.md#productionjobresponse)
|
|
949
949
|
|
950
950
|
## Services
|
951
951
|
|
952
|
+
### archive_service
|
953
|
+
|
954
|
+
Archives a Service. It is a no-op if already archived.
|
955
|
+
|
956
|
+
Parameters
|
957
|
+
|
958
|
+
Name | Type | Description | Notes
|
959
|
+
------------- | ------------- | ------------- | -------------
|
960
|
+
`service_id` | str| | Defaults to null
|
961
|
+
|
962
|
+
Returns void (empty response body)
|
963
|
+
|
952
964
|
### get_service
|
953
965
|
|
954
966
|
Get a Service
|
@@ -972,6 +984,7 @@ Name | Type | Description | Notes
|
|
972
984
|
`project_id` | optional str| project_id to filter by | Defaults to null
|
973
985
|
`name` | optional str| name to filter by | Defaults to null
|
974
986
|
`state_filter` | [List[ServiceEventCurrentState]](./models.md#serviceeventcurrentstate)| A list of Service states to filter by | Defaults to []
|
987
|
+
`archive_status` | [ArchiveStatus](./models.md#archivestatus)| The archive status to filter by. Defaults to unarchived. | Defaults to null
|
975
988
|
`creator_id` | optional str| creator_id to filter by | Defaults to null
|
976
989
|
`cloud_id` | optional str| cloud_id to filter by | Defaults to null
|
977
990
|
`sort_field` | [ServiceSortField](./models.md#servicesortfield)| If absent, the default sorting order is 1. status (active first).2. Last updated at (desc). 3. Name (asc). | Defaults to null
|