databricks-sdk 0.29.0__py3-none-any.whl → 0.30.0__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 databricks-sdk might be problematic. Click here for more details.
- databricks/sdk/__init__.py +67 -19
- databricks/sdk/config.py +61 -75
- databricks/sdk/core.py +16 -9
- databricks/sdk/credentials_provider.py +15 -15
- databricks/sdk/data_plane.py +65 -0
- databricks/sdk/mixins/files.py +12 -4
- databricks/sdk/service/apps.py +977 -0
- databricks/sdk/service/billing.py +602 -218
- databricks/sdk/service/catalog.py +131 -34
- databricks/sdk/service/compute.py +494 -81
- databricks/sdk/service/dashboards.py +608 -5
- databricks/sdk/service/iam.py +99 -88
- databricks/sdk/service/jobs.py +34 -15
- databricks/sdk/service/marketplace.py +2 -122
- databricks/sdk/service/oauth2.py +127 -70
- databricks/sdk/service/pipelines.py +72 -52
- databricks/sdk/service/serving.py +303 -750
- databricks/sdk/service/settings.py +423 -4
- databricks/sdk/service/sharing.py +235 -25
- databricks/sdk/service/sql.py +2417 -566
- databricks/sdk/useragent.py +144 -0
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/METADATA +36 -16
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/RECORD +28 -25
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/WHEEL +1 -1
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.30.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,977 @@
|
|
|
1
|
+
# Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import random
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from datetime import timedelta
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import Callable, Dict, Iterator, List, Optional
|
|
12
|
+
|
|
13
|
+
from ..errors import OperationFailed
|
|
14
|
+
from ._internal import Wait, _enum, _from_dict, _repeated_dict
|
|
15
|
+
|
|
16
|
+
_LOG = logging.getLogger('databricks.sdk')
|
|
17
|
+
|
|
18
|
+
# all definitions in this file are in alphabetical order
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class App:
|
|
23
|
+
name: str
|
|
24
|
+
"""The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
|
|
25
|
+
It must be unique within the workspace."""
|
|
26
|
+
|
|
27
|
+
active_deployment: Optional[AppDeployment] = None
|
|
28
|
+
"""The active deployment of the app."""
|
|
29
|
+
|
|
30
|
+
create_time: Optional[str] = None
|
|
31
|
+
"""The creation time of the app. Formatted timestamp in ISO 6801."""
|
|
32
|
+
|
|
33
|
+
creator: Optional[str] = None
|
|
34
|
+
"""The email of the user that created the app."""
|
|
35
|
+
|
|
36
|
+
description: Optional[str] = None
|
|
37
|
+
"""The description of the app."""
|
|
38
|
+
|
|
39
|
+
pending_deployment: Optional[AppDeployment] = None
|
|
40
|
+
"""The pending deployment of the app."""
|
|
41
|
+
|
|
42
|
+
service_principal_id: Optional[int] = None
|
|
43
|
+
|
|
44
|
+
service_principal_name: Optional[str] = None
|
|
45
|
+
|
|
46
|
+
status: Optional[AppStatus] = None
|
|
47
|
+
|
|
48
|
+
update_time: Optional[str] = None
|
|
49
|
+
"""The update time of the app. Formatted timestamp in ISO 6801."""
|
|
50
|
+
|
|
51
|
+
updater: Optional[str] = None
|
|
52
|
+
"""The email of the user that last updated the app."""
|
|
53
|
+
|
|
54
|
+
url: Optional[str] = None
|
|
55
|
+
"""The URL of the app once it is deployed."""
|
|
56
|
+
|
|
57
|
+
def as_dict(self) -> dict:
|
|
58
|
+
"""Serializes the App into a dictionary suitable for use as a JSON request body."""
|
|
59
|
+
body = {}
|
|
60
|
+
if self.active_deployment: body['active_deployment'] = self.active_deployment.as_dict()
|
|
61
|
+
if self.create_time is not None: body['create_time'] = self.create_time
|
|
62
|
+
if self.creator is not None: body['creator'] = self.creator
|
|
63
|
+
if self.description is not None: body['description'] = self.description
|
|
64
|
+
if self.name is not None: body['name'] = self.name
|
|
65
|
+
if self.pending_deployment: body['pending_deployment'] = self.pending_deployment.as_dict()
|
|
66
|
+
if self.service_principal_id is not None: body['service_principal_id'] = self.service_principal_id
|
|
67
|
+
if self.service_principal_name is not None:
|
|
68
|
+
body['service_principal_name'] = self.service_principal_name
|
|
69
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
70
|
+
if self.update_time is not None: body['update_time'] = self.update_time
|
|
71
|
+
if self.updater is not None: body['updater'] = self.updater
|
|
72
|
+
if self.url is not None: body['url'] = self.url
|
|
73
|
+
return body
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_dict(cls, d: Dict[str, any]) -> App:
|
|
77
|
+
"""Deserializes the App from a dictionary."""
|
|
78
|
+
return cls(active_deployment=_from_dict(d, 'active_deployment', AppDeployment),
|
|
79
|
+
create_time=d.get('create_time', None),
|
|
80
|
+
creator=d.get('creator', None),
|
|
81
|
+
description=d.get('description', None),
|
|
82
|
+
name=d.get('name', None),
|
|
83
|
+
pending_deployment=_from_dict(d, 'pending_deployment', AppDeployment),
|
|
84
|
+
service_principal_id=d.get('service_principal_id', None),
|
|
85
|
+
service_principal_name=d.get('service_principal_name', None),
|
|
86
|
+
status=_from_dict(d, 'status', AppStatus),
|
|
87
|
+
update_time=d.get('update_time', None),
|
|
88
|
+
updater=d.get('updater', None),
|
|
89
|
+
url=d.get('url', None))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class AppAccessControlRequest:
|
|
94
|
+
group_name: Optional[str] = None
|
|
95
|
+
"""name of the group"""
|
|
96
|
+
|
|
97
|
+
permission_level: Optional[AppPermissionLevel] = None
|
|
98
|
+
"""Permission level"""
|
|
99
|
+
|
|
100
|
+
service_principal_name: Optional[str] = None
|
|
101
|
+
"""application ID of a service principal"""
|
|
102
|
+
|
|
103
|
+
user_name: Optional[str] = None
|
|
104
|
+
"""name of the user"""
|
|
105
|
+
|
|
106
|
+
def as_dict(self) -> dict:
|
|
107
|
+
"""Serializes the AppAccessControlRequest into a dictionary suitable for use as a JSON request body."""
|
|
108
|
+
body = {}
|
|
109
|
+
if self.group_name is not None: body['group_name'] = self.group_name
|
|
110
|
+
if self.permission_level is not None: body['permission_level'] = self.permission_level.value
|
|
111
|
+
if self.service_principal_name is not None:
|
|
112
|
+
body['service_principal_name'] = self.service_principal_name
|
|
113
|
+
if self.user_name is not None: body['user_name'] = self.user_name
|
|
114
|
+
return body
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def from_dict(cls, d: Dict[str, any]) -> AppAccessControlRequest:
|
|
118
|
+
"""Deserializes the AppAccessControlRequest from a dictionary."""
|
|
119
|
+
return cls(group_name=d.get('group_name', None),
|
|
120
|
+
permission_level=_enum(d, 'permission_level', AppPermissionLevel),
|
|
121
|
+
service_principal_name=d.get('service_principal_name', None),
|
|
122
|
+
user_name=d.get('user_name', None))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class AppAccessControlResponse:
|
|
127
|
+
all_permissions: Optional[List[AppPermission]] = None
|
|
128
|
+
"""All permissions."""
|
|
129
|
+
|
|
130
|
+
display_name: Optional[str] = None
|
|
131
|
+
"""Display name of the user or service principal."""
|
|
132
|
+
|
|
133
|
+
group_name: Optional[str] = None
|
|
134
|
+
"""name of the group"""
|
|
135
|
+
|
|
136
|
+
service_principal_name: Optional[str] = None
|
|
137
|
+
"""Name of the service principal."""
|
|
138
|
+
|
|
139
|
+
user_name: Optional[str] = None
|
|
140
|
+
"""name of the user"""
|
|
141
|
+
|
|
142
|
+
def as_dict(self) -> dict:
|
|
143
|
+
"""Serializes the AppAccessControlResponse into a dictionary suitable for use as a JSON request body."""
|
|
144
|
+
body = {}
|
|
145
|
+
if self.all_permissions: body['all_permissions'] = [v.as_dict() for v in self.all_permissions]
|
|
146
|
+
if self.display_name is not None: body['display_name'] = self.display_name
|
|
147
|
+
if self.group_name is not None: body['group_name'] = self.group_name
|
|
148
|
+
if self.service_principal_name is not None:
|
|
149
|
+
body['service_principal_name'] = self.service_principal_name
|
|
150
|
+
if self.user_name is not None: body['user_name'] = self.user_name
|
|
151
|
+
return body
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def from_dict(cls, d: Dict[str, any]) -> AppAccessControlResponse:
|
|
155
|
+
"""Deserializes the AppAccessControlResponse from a dictionary."""
|
|
156
|
+
return cls(all_permissions=_repeated_dict(d, 'all_permissions', AppPermission),
|
|
157
|
+
display_name=d.get('display_name', None),
|
|
158
|
+
group_name=d.get('group_name', None),
|
|
159
|
+
service_principal_name=d.get('service_principal_name', None),
|
|
160
|
+
user_name=d.get('user_name', None))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@dataclass
|
|
164
|
+
class AppDeployment:
|
|
165
|
+
source_code_path: str
|
|
166
|
+
"""The workspace file system path of the source code used to create the app deployment. This is
|
|
167
|
+
different from `deployment_artifacts.source_code_path`, which is the path used by the deployed
|
|
168
|
+
app. The former refers to the original source code location of the app in the workspace during
|
|
169
|
+
deployment creation, whereas the latter provides a system generated stable snapshotted source
|
|
170
|
+
code path used by the deployment."""
|
|
171
|
+
|
|
172
|
+
create_time: Optional[str] = None
|
|
173
|
+
"""The creation time of the deployment. Formatted timestamp in ISO 6801."""
|
|
174
|
+
|
|
175
|
+
creator: Optional[str] = None
|
|
176
|
+
"""The email of the user creates the deployment."""
|
|
177
|
+
|
|
178
|
+
deployment_artifacts: Optional[AppDeploymentArtifacts] = None
|
|
179
|
+
"""The deployment artifacts for an app."""
|
|
180
|
+
|
|
181
|
+
deployment_id: Optional[str] = None
|
|
182
|
+
"""The unique id of the deployment."""
|
|
183
|
+
|
|
184
|
+
mode: Optional[AppDeploymentMode] = None
|
|
185
|
+
"""The mode of which the deployment will manage the source code."""
|
|
186
|
+
|
|
187
|
+
status: Optional[AppDeploymentStatus] = None
|
|
188
|
+
"""Status and status message of the deployment"""
|
|
189
|
+
|
|
190
|
+
update_time: Optional[str] = None
|
|
191
|
+
"""The update time of the deployment. Formatted timestamp in ISO 6801."""
|
|
192
|
+
|
|
193
|
+
def as_dict(self) -> dict:
|
|
194
|
+
"""Serializes the AppDeployment into a dictionary suitable for use as a JSON request body."""
|
|
195
|
+
body = {}
|
|
196
|
+
if self.create_time is not None: body['create_time'] = self.create_time
|
|
197
|
+
if self.creator is not None: body['creator'] = self.creator
|
|
198
|
+
if self.deployment_artifacts: body['deployment_artifacts'] = self.deployment_artifacts.as_dict()
|
|
199
|
+
if self.deployment_id is not None: body['deployment_id'] = self.deployment_id
|
|
200
|
+
if self.mode is not None: body['mode'] = self.mode.value
|
|
201
|
+
if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
|
|
202
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
203
|
+
if self.update_time is not None: body['update_time'] = self.update_time
|
|
204
|
+
return body
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def from_dict(cls, d: Dict[str, any]) -> AppDeployment:
|
|
208
|
+
"""Deserializes the AppDeployment from a dictionary."""
|
|
209
|
+
return cls(create_time=d.get('create_time', None),
|
|
210
|
+
creator=d.get('creator', None),
|
|
211
|
+
deployment_artifacts=_from_dict(d, 'deployment_artifacts', AppDeploymentArtifacts),
|
|
212
|
+
deployment_id=d.get('deployment_id', None),
|
|
213
|
+
mode=_enum(d, 'mode', AppDeploymentMode),
|
|
214
|
+
source_code_path=d.get('source_code_path', None),
|
|
215
|
+
status=_from_dict(d, 'status', AppDeploymentStatus),
|
|
216
|
+
update_time=d.get('update_time', None))
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@dataclass
|
|
220
|
+
class AppDeploymentArtifacts:
|
|
221
|
+
source_code_path: Optional[str] = None
|
|
222
|
+
"""The snapshotted workspace file system path of the source code loaded by the deployed app."""
|
|
223
|
+
|
|
224
|
+
def as_dict(self) -> dict:
|
|
225
|
+
"""Serializes the AppDeploymentArtifacts into a dictionary suitable for use as a JSON request body."""
|
|
226
|
+
body = {}
|
|
227
|
+
if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
|
|
228
|
+
return body
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def from_dict(cls, d: Dict[str, any]) -> AppDeploymentArtifacts:
|
|
232
|
+
"""Deserializes the AppDeploymentArtifacts from a dictionary."""
|
|
233
|
+
return cls(source_code_path=d.get('source_code_path', None))
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class AppDeploymentMode(Enum):
|
|
237
|
+
|
|
238
|
+
AUTO_SYNC = 'AUTO_SYNC'
|
|
239
|
+
SNAPSHOT = 'SNAPSHOT'
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class AppDeploymentState(Enum):
|
|
243
|
+
|
|
244
|
+
FAILED = 'FAILED'
|
|
245
|
+
IN_PROGRESS = 'IN_PROGRESS'
|
|
246
|
+
STOPPED = 'STOPPED'
|
|
247
|
+
SUCCEEDED = 'SUCCEEDED'
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@dataclass
|
|
251
|
+
class AppDeploymentStatus:
|
|
252
|
+
message: Optional[str] = None
|
|
253
|
+
"""Message corresponding with the deployment state."""
|
|
254
|
+
|
|
255
|
+
state: Optional[AppDeploymentState] = None
|
|
256
|
+
"""State of the deployment."""
|
|
257
|
+
|
|
258
|
+
def as_dict(self) -> dict:
|
|
259
|
+
"""Serializes the AppDeploymentStatus into a dictionary suitable for use as a JSON request body."""
|
|
260
|
+
body = {}
|
|
261
|
+
if self.message is not None: body['message'] = self.message
|
|
262
|
+
if self.state is not None: body['state'] = self.state.value
|
|
263
|
+
return body
|
|
264
|
+
|
|
265
|
+
@classmethod
|
|
266
|
+
def from_dict(cls, d: Dict[str, any]) -> AppDeploymentStatus:
|
|
267
|
+
"""Deserializes the AppDeploymentStatus from a dictionary."""
|
|
268
|
+
return cls(message=d.get('message', None), state=_enum(d, 'state', AppDeploymentState))
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@dataclass
|
|
272
|
+
class AppPermission:
|
|
273
|
+
inherited: Optional[bool] = None
|
|
274
|
+
|
|
275
|
+
inherited_from_object: Optional[List[str]] = None
|
|
276
|
+
|
|
277
|
+
permission_level: Optional[AppPermissionLevel] = None
|
|
278
|
+
"""Permission level"""
|
|
279
|
+
|
|
280
|
+
def as_dict(self) -> dict:
|
|
281
|
+
"""Serializes the AppPermission into a dictionary suitable for use as a JSON request body."""
|
|
282
|
+
body = {}
|
|
283
|
+
if self.inherited is not None: body['inherited'] = self.inherited
|
|
284
|
+
if self.inherited_from_object: body['inherited_from_object'] = [v for v in self.inherited_from_object]
|
|
285
|
+
if self.permission_level is not None: body['permission_level'] = self.permission_level.value
|
|
286
|
+
return body
|
|
287
|
+
|
|
288
|
+
@classmethod
|
|
289
|
+
def from_dict(cls, d: Dict[str, any]) -> AppPermission:
|
|
290
|
+
"""Deserializes the AppPermission from a dictionary."""
|
|
291
|
+
return cls(inherited=d.get('inherited', None),
|
|
292
|
+
inherited_from_object=d.get('inherited_from_object', None),
|
|
293
|
+
permission_level=_enum(d, 'permission_level', AppPermissionLevel))
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class AppPermissionLevel(Enum):
|
|
297
|
+
"""Permission level"""
|
|
298
|
+
|
|
299
|
+
CAN_MANAGE = 'CAN_MANAGE'
|
|
300
|
+
CAN_USE = 'CAN_USE'
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@dataclass
|
|
304
|
+
class AppPermissions:
|
|
305
|
+
access_control_list: Optional[List[AppAccessControlResponse]] = None
|
|
306
|
+
|
|
307
|
+
object_id: Optional[str] = None
|
|
308
|
+
|
|
309
|
+
object_type: Optional[str] = None
|
|
310
|
+
|
|
311
|
+
def as_dict(self) -> dict:
|
|
312
|
+
"""Serializes the AppPermissions into a dictionary suitable for use as a JSON request body."""
|
|
313
|
+
body = {}
|
|
314
|
+
if self.access_control_list:
|
|
315
|
+
body['access_control_list'] = [v.as_dict() for v in self.access_control_list]
|
|
316
|
+
if self.object_id is not None: body['object_id'] = self.object_id
|
|
317
|
+
if self.object_type is not None: body['object_type'] = self.object_type
|
|
318
|
+
return body
|
|
319
|
+
|
|
320
|
+
@classmethod
|
|
321
|
+
def from_dict(cls, d: Dict[str, any]) -> AppPermissions:
|
|
322
|
+
"""Deserializes the AppPermissions from a dictionary."""
|
|
323
|
+
return cls(access_control_list=_repeated_dict(d, 'access_control_list', AppAccessControlResponse),
|
|
324
|
+
object_id=d.get('object_id', None),
|
|
325
|
+
object_type=d.get('object_type', None))
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@dataclass
|
|
329
|
+
class AppPermissionsDescription:
|
|
330
|
+
description: Optional[str] = None
|
|
331
|
+
|
|
332
|
+
permission_level: Optional[AppPermissionLevel] = None
|
|
333
|
+
"""Permission level"""
|
|
334
|
+
|
|
335
|
+
def as_dict(self) -> dict:
|
|
336
|
+
"""Serializes the AppPermissionsDescription into a dictionary suitable for use as a JSON request body."""
|
|
337
|
+
body = {}
|
|
338
|
+
if self.description is not None: body['description'] = self.description
|
|
339
|
+
if self.permission_level is not None: body['permission_level'] = self.permission_level.value
|
|
340
|
+
return body
|
|
341
|
+
|
|
342
|
+
@classmethod
|
|
343
|
+
def from_dict(cls, d: Dict[str, any]) -> AppPermissionsDescription:
|
|
344
|
+
"""Deserializes the AppPermissionsDescription from a dictionary."""
|
|
345
|
+
return cls(description=d.get('description', None),
|
|
346
|
+
permission_level=_enum(d, 'permission_level', AppPermissionLevel))
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@dataclass
|
|
350
|
+
class AppPermissionsRequest:
|
|
351
|
+
access_control_list: Optional[List[AppAccessControlRequest]] = None
|
|
352
|
+
|
|
353
|
+
app_name: Optional[str] = None
|
|
354
|
+
"""The app for which to get or manage permissions."""
|
|
355
|
+
|
|
356
|
+
def as_dict(self) -> dict:
|
|
357
|
+
"""Serializes the AppPermissionsRequest into a dictionary suitable for use as a JSON request body."""
|
|
358
|
+
body = {}
|
|
359
|
+
if self.access_control_list:
|
|
360
|
+
body['access_control_list'] = [v.as_dict() for v in self.access_control_list]
|
|
361
|
+
if self.app_name is not None: body['app_name'] = self.app_name
|
|
362
|
+
return body
|
|
363
|
+
|
|
364
|
+
@classmethod
|
|
365
|
+
def from_dict(cls, d: Dict[str, any]) -> AppPermissionsRequest:
|
|
366
|
+
"""Deserializes the AppPermissionsRequest from a dictionary."""
|
|
367
|
+
return cls(access_control_list=_repeated_dict(d, 'access_control_list', AppAccessControlRequest),
|
|
368
|
+
app_name=d.get('app_name', None))
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class AppState(Enum):
|
|
372
|
+
|
|
373
|
+
CREATING = 'CREATING'
|
|
374
|
+
DELETED = 'DELETED'
|
|
375
|
+
DELETING = 'DELETING'
|
|
376
|
+
ERROR = 'ERROR'
|
|
377
|
+
IDLE = 'IDLE'
|
|
378
|
+
RUNNING = 'RUNNING'
|
|
379
|
+
STARTING = 'STARTING'
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
@dataclass
|
|
383
|
+
class AppStatus:
|
|
384
|
+
message: Optional[str] = None
|
|
385
|
+
"""Message corresponding with the app state."""
|
|
386
|
+
|
|
387
|
+
state: Optional[AppState] = None
|
|
388
|
+
"""State of the app."""
|
|
389
|
+
|
|
390
|
+
def as_dict(self) -> dict:
|
|
391
|
+
"""Serializes the AppStatus into a dictionary suitable for use as a JSON request body."""
|
|
392
|
+
body = {}
|
|
393
|
+
if self.message is not None: body['message'] = self.message
|
|
394
|
+
if self.state is not None: body['state'] = self.state.value
|
|
395
|
+
return body
|
|
396
|
+
|
|
397
|
+
@classmethod
|
|
398
|
+
def from_dict(cls, d: Dict[str, any]) -> AppStatus:
|
|
399
|
+
"""Deserializes the AppStatus from a dictionary."""
|
|
400
|
+
return cls(message=d.get('message', None), state=_enum(d, 'state', AppState))
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
@dataclass
|
|
404
|
+
class CreateAppDeploymentRequest:
|
|
405
|
+
source_code_path: str
|
|
406
|
+
"""The workspace file system path of the source code used to create the app deployment. This is
|
|
407
|
+
different from `deployment_artifacts.source_code_path`, which is the path used by the deployed
|
|
408
|
+
app. The former refers to the original source code location of the app in the workspace during
|
|
409
|
+
deployment creation, whereas the latter provides a system generated stable snapshotted source
|
|
410
|
+
code path used by the deployment."""
|
|
411
|
+
|
|
412
|
+
app_name: Optional[str] = None
|
|
413
|
+
"""The name of the app."""
|
|
414
|
+
|
|
415
|
+
mode: Optional[AppDeploymentMode] = None
|
|
416
|
+
"""The mode of which the deployment will manage the source code."""
|
|
417
|
+
|
|
418
|
+
def as_dict(self) -> dict:
|
|
419
|
+
"""Serializes the CreateAppDeploymentRequest into a dictionary suitable for use as a JSON request body."""
|
|
420
|
+
body = {}
|
|
421
|
+
if self.app_name is not None: body['app_name'] = self.app_name
|
|
422
|
+
if self.mode is not None: body['mode'] = self.mode.value
|
|
423
|
+
if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
|
|
424
|
+
return body
|
|
425
|
+
|
|
426
|
+
@classmethod
|
|
427
|
+
def from_dict(cls, d: Dict[str, any]) -> CreateAppDeploymentRequest:
|
|
428
|
+
"""Deserializes the CreateAppDeploymentRequest from a dictionary."""
|
|
429
|
+
return cls(app_name=d.get('app_name', None),
|
|
430
|
+
mode=_enum(d, 'mode', AppDeploymentMode),
|
|
431
|
+
source_code_path=d.get('source_code_path', None))
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@dataclass
|
|
435
|
+
class CreateAppRequest:
|
|
436
|
+
name: str
|
|
437
|
+
"""The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
|
|
438
|
+
It must be unique within the workspace."""
|
|
439
|
+
|
|
440
|
+
description: Optional[str] = None
|
|
441
|
+
"""The description of the app."""
|
|
442
|
+
|
|
443
|
+
def as_dict(self) -> dict:
|
|
444
|
+
"""Serializes the CreateAppRequest into a dictionary suitable for use as a JSON request body."""
|
|
445
|
+
body = {}
|
|
446
|
+
if self.description is not None: body['description'] = self.description
|
|
447
|
+
if self.name is not None: body['name'] = self.name
|
|
448
|
+
return body
|
|
449
|
+
|
|
450
|
+
@classmethod
|
|
451
|
+
def from_dict(cls, d: Dict[str, any]) -> CreateAppRequest:
|
|
452
|
+
"""Deserializes the CreateAppRequest from a dictionary."""
|
|
453
|
+
return cls(description=d.get('description', None), name=d.get('name', None))
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@dataclass
|
|
457
|
+
class DeleteResponse:
|
|
458
|
+
|
|
459
|
+
def as_dict(self) -> dict:
|
|
460
|
+
"""Serializes the DeleteResponse into a dictionary suitable for use as a JSON request body."""
|
|
461
|
+
body = {}
|
|
462
|
+
return body
|
|
463
|
+
|
|
464
|
+
@classmethod
|
|
465
|
+
def from_dict(cls, d: Dict[str, any]) -> DeleteResponse:
|
|
466
|
+
"""Deserializes the DeleteResponse from a dictionary."""
|
|
467
|
+
return cls()
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@dataclass
|
|
471
|
+
class GetAppPermissionLevelsResponse:
|
|
472
|
+
permission_levels: Optional[List[AppPermissionsDescription]] = None
|
|
473
|
+
"""Specific permission levels"""
|
|
474
|
+
|
|
475
|
+
def as_dict(self) -> dict:
|
|
476
|
+
"""Serializes the GetAppPermissionLevelsResponse into a dictionary suitable for use as a JSON request body."""
|
|
477
|
+
body = {}
|
|
478
|
+
if self.permission_levels: body['permission_levels'] = [v.as_dict() for v in self.permission_levels]
|
|
479
|
+
return body
|
|
480
|
+
|
|
481
|
+
@classmethod
|
|
482
|
+
def from_dict(cls, d: Dict[str, any]) -> GetAppPermissionLevelsResponse:
|
|
483
|
+
"""Deserializes the GetAppPermissionLevelsResponse from a dictionary."""
|
|
484
|
+
return cls(permission_levels=_repeated_dict(d, 'permission_levels', AppPermissionsDescription))
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
@dataclass
|
|
488
|
+
class ListAppDeploymentsResponse:
|
|
489
|
+
app_deployments: Optional[List[AppDeployment]] = None
|
|
490
|
+
"""Deployment history of the app."""
|
|
491
|
+
|
|
492
|
+
next_page_token: Optional[str] = None
|
|
493
|
+
"""Pagination token to request the next page of apps."""
|
|
494
|
+
|
|
495
|
+
def as_dict(self) -> dict:
|
|
496
|
+
"""Serializes the ListAppDeploymentsResponse into a dictionary suitable for use as a JSON request body."""
|
|
497
|
+
body = {}
|
|
498
|
+
if self.app_deployments: body['app_deployments'] = [v.as_dict() for v in self.app_deployments]
|
|
499
|
+
if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
|
|
500
|
+
return body
|
|
501
|
+
|
|
502
|
+
@classmethod
|
|
503
|
+
def from_dict(cls, d: Dict[str, any]) -> ListAppDeploymentsResponse:
|
|
504
|
+
"""Deserializes the ListAppDeploymentsResponse from a dictionary."""
|
|
505
|
+
return cls(app_deployments=_repeated_dict(d, 'app_deployments', AppDeployment),
|
|
506
|
+
next_page_token=d.get('next_page_token', None))
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
@dataclass
|
|
510
|
+
class ListAppsResponse:
|
|
511
|
+
apps: Optional[List[App]] = None
|
|
512
|
+
|
|
513
|
+
next_page_token: Optional[str] = None
|
|
514
|
+
"""Pagination token to request the next page of apps."""
|
|
515
|
+
|
|
516
|
+
def as_dict(self) -> dict:
|
|
517
|
+
"""Serializes the ListAppsResponse into a dictionary suitable for use as a JSON request body."""
|
|
518
|
+
body = {}
|
|
519
|
+
if self.apps: body['apps'] = [v.as_dict() for v in self.apps]
|
|
520
|
+
if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
|
|
521
|
+
return body
|
|
522
|
+
|
|
523
|
+
@classmethod
|
|
524
|
+
def from_dict(cls, d: Dict[str, any]) -> ListAppsResponse:
|
|
525
|
+
"""Deserializes the ListAppsResponse from a dictionary."""
|
|
526
|
+
return cls(apps=_repeated_dict(d, 'apps', App), next_page_token=d.get('next_page_token', None))
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@dataclass
|
|
530
|
+
class StartAppRequest:
|
|
531
|
+
name: Optional[str] = None
|
|
532
|
+
"""The name of the app."""
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
@dataclass
|
|
536
|
+
class StopAppRequest:
|
|
537
|
+
name: Optional[str] = None
|
|
538
|
+
"""The name of the app."""
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
@dataclass
|
|
542
|
+
class StopAppResponse:
|
|
543
|
+
|
|
544
|
+
def as_dict(self) -> dict:
|
|
545
|
+
"""Serializes the StopAppResponse into a dictionary suitable for use as a JSON request body."""
|
|
546
|
+
body = {}
|
|
547
|
+
return body
|
|
548
|
+
|
|
549
|
+
@classmethod
|
|
550
|
+
def from_dict(cls, d: Dict[str, any]) -> StopAppResponse:
|
|
551
|
+
"""Deserializes the StopAppResponse from a dictionary."""
|
|
552
|
+
return cls()
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
@dataclass
|
|
556
|
+
class UpdateAppRequest:
|
|
557
|
+
name: str
|
|
558
|
+
"""The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
|
|
559
|
+
It must be unique within the workspace."""
|
|
560
|
+
|
|
561
|
+
description: Optional[str] = None
|
|
562
|
+
"""The description of the app."""
|
|
563
|
+
|
|
564
|
+
def as_dict(self) -> dict:
|
|
565
|
+
"""Serializes the UpdateAppRequest into a dictionary suitable for use as a JSON request body."""
|
|
566
|
+
body = {}
|
|
567
|
+
if self.description is not None: body['description'] = self.description
|
|
568
|
+
if self.name is not None: body['name'] = self.name
|
|
569
|
+
return body
|
|
570
|
+
|
|
571
|
+
@classmethod
|
|
572
|
+
def from_dict(cls, d: Dict[str, any]) -> UpdateAppRequest:
|
|
573
|
+
"""Deserializes the UpdateAppRequest from a dictionary."""
|
|
574
|
+
return cls(description=d.get('description', None), name=d.get('name', None))
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
class AppsAPI:
|
|
578
|
+
"""Apps run directly on a customer’s Databricks instance, integrate with their data, use and extend
|
|
579
|
+
Databricks services, and enable users to interact through single sign-on."""
|
|
580
|
+
|
|
581
|
+
def __init__(self, api_client):
|
|
582
|
+
self._api = api_client
|
|
583
|
+
|
|
584
|
+
def wait_get_app_idle(self,
|
|
585
|
+
name: str,
|
|
586
|
+
timeout=timedelta(minutes=20),
|
|
587
|
+
callback: Optional[Callable[[App], None]] = None) -> App:
|
|
588
|
+
deadline = time.time() + timeout.total_seconds()
|
|
589
|
+
target_states = (AppState.IDLE, )
|
|
590
|
+
failure_states = (AppState.ERROR, )
|
|
591
|
+
status_message = 'polling...'
|
|
592
|
+
attempt = 1
|
|
593
|
+
while time.time() < deadline:
|
|
594
|
+
poll = self.get(name=name)
|
|
595
|
+
status = poll.status.state
|
|
596
|
+
status_message = f'current status: {status}'
|
|
597
|
+
if poll.status:
|
|
598
|
+
status_message = poll.status.message
|
|
599
|
+
if status in target_states:
|
|
600
|
+
return poll
|
|
601
|
+
if callback:
|
|
602
|
+
callback(poll)
|
|
603
|
+
if status in failure_states:
|
|
604
|
+
msg = f'failed to reach IDLE, got {status}: {status_message}'
|
|
605
|
+
raise OperationFailed(msg)
|
|
606
|
+
prefix = f"name={name}"
|
|
607
|
+
sleep = attempt
|
|
608
|
+
if sleep > 10:
|
|
609
|
+
# sleep 10s max per attempt
|
|
610
|
+
sleep = 10
|
|
611
|
+
_LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
|
|
612
|
+
time.sleep(sleep + random.random())
|
|
613
|
+
attempt += 1
|
|
614
|
+
raise TimeoutError(f'timed out after {timeout}: {status_message}')
|
|
615
|
+
|
|
616
|
+
def wait_get_deployment_app_succeeded(
|
|
617
|
+
self,
|
|
618
|
+
app_name: str,
|
|
619
|
+
deployment_id: str,
|
|
620
|
+
timeout=timedelta(minutes=20),
|
|
621
|
+
callback: Optional[Callable[[AppDeployment], None]] = None) -> AppDeployment:
|
|
622
|
+
deadline = time.time() + timeout.total_seconds()
|
|
623
|
+
target_states = (AppDeploymentState.SUCCEEDED, )
|
|
624
|
+
failure_states = (AppDeploymentState.FAILED, )
|
|
625
|
+
status_message = 'polling...'
|
|
626
|
+
attempt = 1
|
|
627
|
+
while time.time() < deadline:
|
|
628
|
+
poll = self.get_deployment(app_name=app_name, deployment_id=deployment_id)
|
|
629
|
+
status = poll.status.state
|
|
630
|
+
status_message = f'current status: {status}'
|
|
631
|
+
if poll.status:
|
|
632
|
+
status_message = poll.status.message
|
|
633
|
+
if status in target_states:
|
|
634
|
+
return poll
|
|
635
|
+
if callback:
|
|
636
|
+
callback(poll)
|
|
637
|
+
if status in failure_states:
|
|
638
|
+
msg = f'failed to reach SUCCEEDED, got {status}: {status_message}'
|
|
639
|
+
raise OperationFailed(msg)
|
|
640
|
+
prefix = f"app_name={app_name}, deployment_id={deployment_id}"
|
|
641
|
+
sleep = attempt
|
|
642
|
+
if sleep > 10:
|
|
643
|
+
# sleep 10s max per attempt
|
|
644
|
+
sleep = 10
|
|
645
|
+
_LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
|
|
646
|
+
time.sleep(sleep + random.random())
|
|
647
|
+
attempt += 1
|
|
648
|
+
raise TimeoutError(f'timed out after {timeout}: {status_message}')
|
|
649
|
+
|
|
650
|
+
def create(self, name: str, *, description: Optional[str] = None) -> Wait[App]:
|
|
651
|
+
"""Create an app.
|
|
652
|
+
|
|
653
|
+
Creates a new app.
|
|
654
|
+
|
|
655
|
+
:param name: str
|
|
656
|
+
The name of the app. The name must contain only lowercase alphanumeric characters and hyphens. It
|
|
657
|
+
must be unique within the workspace.
|
|
658
|
+
:param description: str (optional)
|
|
659
|
+
The description of the app.
|
|
660
|
+
|
|
661
|
+
:returns:
|
|
662
|
+
Long-running operation waiter for :class:`App`.
|
|
663
|
+
See :method:wait_get_app_idle for more details.
|
|
664
|
+
"""
|
|
665
|
+
body = {}
|
|
666
|
+
if description is not None: body['description'] = description
|
|
667
|
+
if name is not None: body['name'] = name
|
|
668
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
669
|
+
|
|
670
|
+
op_response = self._api.do('POST', '/api/2.0/preview/apps', body=body, headers=headers)
|
|
671
|
+
return Wait(self.wait_get_app_idle, response=App.from_dict(op_response), name=op_response['name'])
|
|
672
|
+
|
|
673
|
+
def create_and_wait(self,
|
|
674
|
+
name: str,
|
|
675
|
+
*,
|
|
676
|
+
description: Optional[str] = None,
|
|
677
|
+
timeout=timedelta(minutes=20)) -> App:
|
|
678
|
+
return self.create(description=description, name=name).result(timeout=timeout)
|
|
679
|
+
|
|
680
|
+
def delete(self, name: str):
|
|
681
|
+
"""Delete an app.
|
|
682
|
+
|
|
683
|
+
Deletes an app.
|
|
684
|
+
|
|
685
|
+
:param name: str
|
|
686
|
+
The name of the app.
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
"""
|
|
690
|
+
|
|
691
|
+
headers = {'Accept': 'application/json', }
|
|
692
|
+
|
|
693
|
+
self._api.do('DELETE', f'/api/2.0/preview/apps/{name}', headers=headers)
|
|
694
|
+
|
|
695
|
+
def deploy(self,
|
|
696
|
+
app_name: str,
|
|
697
|
+
source_code_path: str,
|
|
698
|
+
*,
|
|
699
|
+
mode: Optional[AppDeploymentMode] = None) -> Wait[AppDeployment]:
|
|
700
|
+
"""Create an app deployment.
|
|
701
|
+
|
|
702
|
+
Creates an app deployment for the app with the supplied name.
|
|
703
|
+
|
|
704
|
+
:param app_name: str
|
|
705
|
+
The name of the app.
|
|
706
|
+
:param source_code_path: str
|
|
707
|
+
The workspace file system path of the source code used to create the app deployment. This is
|
|
708
|
+
different from `deployment_artifacts.source_code_path`, which is the path used by the deployed app.
|
|
709
|
+
The former refers to the original source code location of the app in the workspace during deployment
|
|
710
|
+
creation, whereas the latter provides a system generated stable snapshotted source code path used by
|
|
711
|
+
the deployment.
|
|
712
|
+
:param mode: :class:`AppDeploymentMode` (optional)
|
|
713
|
+
The mode of which the deployment will manage the source code.
|
|
714
|
+
|
|
715
|
+
:returns:
|
|
716
|
+
Long-running operation waiter for :class:`AppDeployment`.
|
|
717
|
+
See :method:wait_get_deployment_app_succeeded for more details.
|
|
718
|
+
"""
|
|
719
|
+
body = {}
|
|
720
|
+
if mode is not None: body['mode'] = mode.value
|
|
721
|
+
if source_code_path is not None: body['source_code_path'] = source_code_path
|
|
722
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
723
|
+
|
|
724
|
+
op_response = self._api.do('POST',
|
|
725
|
+
f'/api/2.0/preview/apps/{app_name}/deployments',
|
|
726
|
+
body=body,
|
|
727
|
+
headers=headers)
|
|
728
|
+
return Wait(self.wait_get_deployment_app_succeeded,
|
|
729
|
+
response=AppDeployment.from_dict(op_response),
|
|
730
|
+
app_name=app_name,
|
|
731
|
+
deployment_id=op_response['deployment_id'])
|
|
732
|
+
|
|
733
|
+
def deploy_and_wait(
|
|
734
|
+
self,
|
|
735
|
+
app_name: str,
|
|
736
|
+
source_code_path: str,
|
|
737
|
+
*,
|
|
738
|
+
mode: Optional[AppDeploymentMode] = None,
|
|
739
|
+
timeout=timedelta(minutes=20)) -> AppDeployment:
|
|
740
|
+
return self.deploy(app_name=app_name, mode=mode,
|
|
741
|
+
source_code_path=source_code_path).result(timeout=timeout)
|
|
742
|
+
|
|
743
|
+
def get(self, name: str) -> App:
|
|
744
|
+
"""Get an app.
|
|
745
|
+
|
|
746
|
+
Retrieves information for the app with the supplied name.
|
|
747
|
+
|
|
748
|
+
:param name: str
|
|
749
|
+
The name of the app.
|
|
750
|
+
|
|
751
|
+
:returns: :class:`App`
|
|
752
|
+
"""
|
|
753
|
+
|
|
754
|
+
headers = {'Accept': 'application/json', }
|
|
755
|
+
|
|
756
|
+
res = self._api.do('GET', f'/api/2.0/preview/apps/{name}', headers=headers)
|
|
757
|
+
return App.from_dict(res)
|
|
758
|
+
|
|
759
|
+
def get_deployment(self, app_name: str, deployment_id: str) -> AppDeployment:
|
|
760
|
+
"""Get an app deployment.
|
|
761
|
+
|
|
762
|
+
Retrieves information for the app deployment with the supplied name and deployment id.
|
|
763
|
+
|
|
764
|
+
:param app_name: str
|
|
765
|
+
The name of the app.
|
|
766
|
+
:param deployment_id: str
|
|
767
|
+
The unique id of the deployment.
|
|
768
|
+
|
|
769
|
+
:returns: :class:`AppDeployment`
|
|
770
|
+
"""
|
|
771
|
+
|
|
772
|
+
headers = {'Accept': 'application/json', }
|
|
773
|
+
|
|
774
|
+
res = self._api.do('GET',
|
|
775
|
+
f'/api/2.0/preview/apps/{app_name}/deployments/{deployment_id}',
|
|
776
|
+
headers=headers)
|
|
777
|
+
return AppDeployment.from_dict(res)
|
|
778
|
+
|
|
779
|
+
def get_permission_levels(self, app_name: str) -> GetAppPermissionLevelsResponse:
|
|
780
|
+
"""Get app permission levels.
|
|
781
|
+
|
|
782
|
+
Gets the permission levels that a user can have on an object.
|
|
783
|
+
|
|
784
|
+
:param app_name: str
|
|
785
|
+
The app for which to get or manage permissions.
|
|
786
|
+
|
|
787
|
+
:returns: :class:`GetAppPermissionLevelsResponse`
|
|
788
|
+
"""
|
|
789
|
+
|
|
790
|
+
headers = {'Accept': 'application/json', }
|
|
791
|
+
|
|
792
|
+
res = self._api.do('GET', f'/api/2.0/permissions/apps/{app_name}/permissionLevels', headers=headers)
|
|
793
|
+
return GetAppPermissionLevelsResponse.from_dict(res)
|
|
794
|
+
|
|
795
|
+
def get_permissions(self, app_name: str) -> AppPermissions:
|
|
796
|
+
"""Get app permissions.
|
|
797
|
+
|
|
798
|
+
Gets the permissions of an app. Apps can inherit permissions from their root object.
|
|
799
|
+
|
|
800
|
+
:param app_name: str
|
|
801
|
+
The app for which to get or manage permissions.
|
|
802
|
+
|
|
803
|
+
:returns: :class:`AppPermissions`
|
|
804
|
+
"""
|
|
805
|
+
|
|
806
|
+
headers = {'Accept': 'application/json', }
|
|
807
|
+
|
|
808
|
+
res = self._api.do('GET', f'/api/2.0/permissions/apps/{app_name}', headers=headers)
|
|
809
|
+
return AppPermissions.from_dict(res)
|
|
810
|
+
|
|
811
|
+
def list(self, *, page_size: Optional[int] = None, page_token: Optional[str] = None) -> Iterator[App]:
|
|
812
|
+
"""List apps.
|
|
813
|
+
|
|
814
|
+
Lists all apps in the workspace.
|
|
815
|
+
|
|
816
|
+
:param page_size: int (optional)
|
|
817
|
+
Upper bound for items returned.
|
|
818
|
+
:param page_token: str (optional)
|
|
819
|
+
Pagination token to go to the next page of apps. Requests first page if absent.
|
|
820
|
+
|
|
821
|
+
:returns: Iterator over :class:`App`
|
|
822
|
+
"""
|
|
823
|
+
|
|
824
|
+
query = {}
|
|
825
|
+
if page_size is not None: query['page_size'] = page_size
|
|
826
|
+
if page_token is not None: query['page_token'] = page_token
|
|
827
|
+
headers = {'Accept': 'application/json', }
|
|
828
|
+
|
|
829
|
+
while True:
|
|
830
|
+
json = self._api.do('GET', '/api/2.0/preview/apps', query=query, headers=headers)
|
|
831
|
+
if 'apps' in json:
|
|
832
|
+
for v in json['apps']:
|
|
833
|
+
yield App.from_dict(v)
|
|
834
|
+
if 'next_page_token' not in json or not json['next_page_token']:
|
|
835
|
+
return
|
|
836
|
+
query['page_token'] = json['next_page_token']
|
|
837
|
+
|
|
838
|
+
def list_deployments(self,
|
|
839
|
+
app_name: str,
|
|
840
|
+
*,
|
|
841
|
+
page_size: Optional[int] = None,
|
|
842
|
+
page_token: Optional[str] = None) -> Iterator[AppDeployment]:
|
|
843
|
+
"""List app deployments.
|
|
844
|
+
|
|
845
|
+
Lists all app deployments for the app with the supplied name.
|
|
846
|
+
|
|
847
|
+
:param app_name: str
|
|
848
|
+
The name of the app.
|
|
849
|
+
:param page_size: int (optional)
|
|
850
|
+
Upper bound for items returned.
|
|
851
|
+
:param page_token: str (optional)
|
|
852
|
+
Pagination token to go to the next page of apps. Requests first page if absent.
|
|
853
|
+
|
|
854
|
+
:returns: Iterator over :class:`AppDeployment`
|
|
855
|
+
"""
|
|
856
|
+
|
|
857
|
+
query = {}
|
|
858
|
+
if page_size is not None: query['page_size'] = page_size
|
|
859
|
+
if page_token is not None: query['page_token'] = page_token
|
|
860
|
+
headers = {'Accept': 'application/json', }
|
|
861
|
+
|
|
862
|
+
while True:
|
|
863
|
+
json = self._api.do('GET',
|
|
864
|
+
f'/api/2.0/preview/apps/{app_name}/deployments',
|
|
865
|
+
query=query,
|
|
866
|
+
headers=headers)
|
|
867
|
+
if 'app_deployments' in json:
|
|
868
|
+
for v in json['app_deployments']:
|
|
869
|
+
yield AppDeployment.from_dict(v)
|
|
870
|
+
if 'next_page_token' not in json or not json['next_page_token']:
|
|
871
|
+
return
|
|
872
|
+
query['page_token'] = json['next_page_token']
|
|
873
|
+
|
|
874
|
+
def set_permissions(
|
|
875
|
+
self,
|
|
876
|
+
app_name: str,
|
|
877
|
+
*,
|
|
878
|
+
access_control_list: Optional[List[AppAccessControlRequest]] = None) -> AppPermissions:
|
|
879
|
+
"""Set app permissions.
|
|
880
|
+
|
|
881
|
+
Sets permissions on an app. Apps can inherit permissions from their root object.
|
|
882
|
+
|
|
883
|
+
:param app_name: str
|
|
884
|
+
The app for which to get or manage permissions.
|
|
885
|
+
:param access_control_list: List[:class:`AppAccessControlRequest`] (optional)
|
|
886
|
+
|
|
887
|
+
:returns: :class:`AppPermissions`
|
|
888
|
+
"""
|
|
889
|
+
body = {}
|
|
890
|
+
if access_control_list is not None:
|
|
891
|
+
body['access_control_list'] = [v.as_dict() for v in access_control_list]
|
|
892
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
893
|
+
|
|
894
|
+
res = self._api.do('PUT', f'/api/2.0/permissions/apps/{app_name}', body=body, headers=headers)
|
|
895
|
+
return AppPermissions.from_dict(res)
|
|
896
|
+
|
|
897
|
+
def start(self, name: str) -> Wait[AppDeployment]:
|
|
898
|
+
"""Start an app.
|
|
899
|
+
|
|
900
|
+
Start the last active deployment of the app in the workspace.
|
|
901
|
+
|
|
902
|
+
:param name: str
|
|
903
|
+
The name of the app.
|
|
904
|
+
|
|
905
|
+
:returns:
|
|
906
|
+
Long-running operation waiter for :class:`AppDeployment`.
|
|
907
|
+
See :method:wait_get_deployment_app_succeeded for more details.
|
|
908
|
+
"""
|
|
909
|
+
|
|
910
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
911
|
+
|
|
912
|
+
op_response = self._api.do('POST', f'/api/2.0/preview/apps/{name}/start', headers=headers)
|
|
913
|
+
return Wait(self.wait_get_deployment_app_succeeded,
|
|
914
|
+
response=AppDeployment.from_dict(op_response),
|
|
915
|
+
app_name=name,
|
|
916
|
+
deployment_id=op_response['deployment_id'])
|
|
917
|
+
|
|
918
|
+
def start_and_wait(self, name: str, timeout=timedelta(minutes=20)) -> AppDeployment:
|
|
919
|
+
return self.start(name=name).result(timeout=timeout)
|
|
920
|
+
|
|
921
|
+
def stop(self, name: str):
|
|
922
|
+
"""Stop an app.
|
|
923
|
+
|
|
924
|
+
Stops the active deployment of the app in the workspace.
|
|
925
|
+
|
|
926
|
+
:param name: str
|
|
927
|
+
The name of the app.
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
"""
|
|
931
|
+
|
|
932
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
933
|
+
|
|
934
|
+
self._api.do('POST', f'/api/2.0/preview/apps/{name}/stop', headers=headers)
|
|
935
|
+
|
|
936
|
+
def update(self, name: str, *, description: Optional[str] = None) -> App:
|
|
937
|
+
"""Update an app.
|
|
938
|
+
|
|
939
|
+
Updates the app with the supplied name.
|
|
940
|
+
|
|
941
|
+
:param name: str
|
|
942
|
+
The name of the app. The name must contain only lowercase alphanumeric characters and hyphens. It
|
|
943
|
+
must be unique within the workspace.
|
|
944
|
+
:param description: str (optional)
|
|
945
|
+
The description of the app.
|
|
946
|
+
|
|
947
|
+
:returns: :class:`App`
|
|
948
|
+
"""
|
|
949
|
+
body = {}
|
|
950
|
+
if description is not None: body['description'] = description
|
|
951
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
952
|
+
|
|
953
|
+
res = self._api.do('PATCH', f'/api/2.0/preview/apps/{name}', body=body, headers=headers)
|
|
954
|
+
return App.from_dict(res)
|
|
955
|
+
|
|
956
|
+
def update_permissions(
|
|
957
|
+
self,
|
|
958
|
+
app_name: str,
|
|
959
|
+
*,
|
|
960
|
+
access_control_list: Optional[List[AppAccessControlRequest]] = None) -> AppPermissions:
|
|
961
|
+
"""Update app permissions.
|
|
962
|
+
|
|
963
|
+
Updates the permissions on an app. Apps can inherit permissions from their root object.
|
|
964
|
+
|
|
965
|
+
:param app_name: str
|
|
966
|
+
The app for which to get or manage permissions.
|
|
967
|
+
:param access_control_list: List[:class:`AppAccessControlRequest`] (optional)
|
|
968
|
+
|
|
969
|
+
:returns: :class:`AppPermissions`
|
|
970
|
+
"""
|
|
971
|
+
body = {}
|
|
972
|
+
if access_control_list is not None:
|
|
973
|
+
body['access_control_list'] = [v.as_dict() for v in access_control_list]
|
|
974
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
975
|
+
|
|
976
|
+
res = self._api.do('PATCH', f'/api/2.0/permissions/apps/{app_name}', body=body, headers=headers)
|
|
977
|
+
return AppPermissions.from_dict(res)
|