databricks-sdk 0.0.7__py3-none-any.whl → 0.1.1__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 +121 -104
- databricks/sdk/core.py +76 -16
- databricks/sdk/dbutils.py +18 -17
- databricks/sdk/mixins/compute.py +6 -6
- databricks/sdk/mixins/dbfs.py +6 -6
- databricks/sdk/oauth.py +28 -14
- databricks/sdk/service/{unitycatalog.py → catalog.py} +375 -1146
- databricks/sdk/service/{clusters.py → compute.py} +2176 -61
- databricks/sdk/service/{dbfs.py → files.py} +6 -6
- databricks/sdk/service/{scim.py → iam.py} +567 -27
- databricks/sdk/service/jobs.py +44 -34
- databricks/sdk/service/{mlflow.py → ml.py} +976 -1071
- databricks/sdk/service/oauth2.py +3 -3
- databricks/sdk/service/pipelines.py +46 -30
- databricks/sdk/service/{deployment.py → provisioning.py} +47 -29
- databricks/sdk/service/settings.py +849 -0
- databricks/sdk/service/sharing.py +1176 -0
- databricks/sdk/service/sql.py +15 -15
- databricks/sdk/service/workspace.py +917 -22
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.0.7.dist-info → databricks_sdk-0.1.1.dist-info}/METADATA +3 -1
- databricks_sdk-0.1.1.dist-info/RECORD +37 -0
- databricks/sdk/service/clusterpolicies.py +0 -399
- databricks/sdk/service/commands.py +0 -478
- databricks/sdk/service/gitcredentials.py +0 -202
- databricks/sdk/service/globalinitscripts.py +0 -262
- databricks/sdk/service/instancepools.py +0 -757
- databricks/sdk/service/ipaccesslists.py +0 -340
- databricks/sdk/service/libraries.py +0 -282
- databricks/sdk/service/permissions.py +0 -470
- databricks/sdk/service/repos.py +0 -250
- databricks/sdk/service/secrets.py +0 -472
- databricks/sdk/service/tokenmanagement.py +0 -182
- databricks/sdk/service/tokens.py +0 -137
- databricks/sdk/service/workspaceconf.py +0 -50
- databricks_sdk-0.0.7.dist-info/RECORD +0 -48
- /databricks/sdk/service/{endpoints.py → serving.py} +0 -0
- {databricks_sdk-0.0.7.dist-info → databricks_sdk-0.1.1.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.0.7.dist-info → databricks_sdk-0.1.1.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.0.7.dist-info → databricks_sdk-0.1.1.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.0.7.dist-info → databricks_sdk-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -5,13 +5,158 @@ from dataclasses import dataclass
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from typing import Dict, Iterator, List
|
|
7
7
|
|
|
8
|
-
from ._internal import _enum, _repeated
|
|
8
|
+
from ._internal import _enum, _from_dict, _repeated
|
|
9
9
|
|
|
10
10
|
_LOG = logging.getLogger('databricks.sdk')
|
|
11
11
|
|
|
12
12
|
# all definitions in this file are in alphabetical order
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
@dataclass
|
|
16
|
+
class AclItem:
|
|
17
|
+
principal: str
|
|
18
|
+
permission: 'AclPermission'
|
|
19
|
+
|
|
20
|
+
def as_dict(self) -> dict:
|
|
21
|
+
body = {}
|
|
22
|
+
if self.permission: body['permission'] = self.permission.value
|
|
23
|
+
if self.principal: body['principal'] = self.principal
|
|
24
|
+
return body
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def from_dict(cls, d: Dict[str, any]) -> 'AclItem':
|
|
28
|
+
return cls(permission=_enum(d, 'permission', AclPermission), principal=d.get('principal', None))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AclPermission(Enum):
|
|
32
|
+
|
|
33
|
+
MANAGE = 'MANAGE'
|
|
34
|
+
READ = 'READ'
|
|
35
|
+
WRITE = 'WRITE'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class AzureKeyVaultSecretScopeMetadata:
|
|
40
|
+
resource_id: str
|
|
41
|
+
dns_name: str
|
|
42
|
+
|
|
43
|
+
def as_dict(self) -> dict:
|
|
44
|
+
body = {}
|
|
45
|
+
if self.dns_name: body['dns_name'] = self.dns_name
|
|
46
|
+
if self.resource_id: body['resource_id'] = self.resource_id
|
|
47
|
+
return body
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_dict(cls, d: Dict[str, any]) -> 'AzureKeyVaultSecretScopeMetadata':
|
|
51
|
+
return cls(dns_name=d.get('dns_name', None), resource_id=d.get('resource_id', None))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class CreateCredentials:
|
|
56
|
+
git_provider: str
|
|
57
|
+
git_username: str = None
|
|
58
|
+
personal_access_token: str = None
|
|
59
|
+
|
|
60
|
+
def as_dict(self) -> dict:
|
|
61
|
+
body = {}
|
|
62
|
+
if self.git_provider: body['git_provider'] = self.git_provider
|
|
63
|
+
if self.git_username: body['git_username'] = self.git_username
|
|
64
|
+
if self.personal_access_token: body['personal_access_token'] = self.personal_access_token
|
|
65
|
+
return body
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def from_dict(cls, d: Dict[str, any]) -> 'CreateCredentials':
|
|
69
|
+
return cls(git_provider=d.get('git_provider', None),
|
|
70
|
+
git_username=d.get('git_username', None),
|
|
71
|
+
personal_access_token=d.get('personal_access_token', None))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class CreateCredentialsResponse:
|
|
76
|
+
credential_id: int = None
|
|
77
|
+
git_provider: str = None
|
|
78
|
+
git_username: str = None
|
|
79
|
+
|
|
80
|
+
def as_dict(self) -> dict:
|
|
81
|
+
body = {}
|
|
82
|
+
if self.credential_id: body['credential_id'] = self.credential_id
|
|
83
|
+
if self.git_provider: body['git_provider'] = self.git_provider
|
|
84
|
+
if self.git_username: body['git_username'] = self.git_username
|
|
85
|
+
return body
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def from_dict(cls, d: Dict[str, any]) -> 'CreateCredentialsResponse':
|
|
89
|
+
return cls(credential_id=d.get('credential_id', None),
|
|
90
|
+
git_provider=d.get('git_provider', None),
|
|
91
|
+
git_username=d.get('git_username', None))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class CreateRepo:
|
|
96
|
+
url: str
|
|
97
|
+
provider: str
|
|
98
|
+
path: str = None
|
|
99
|
+
sparse_checkout: 'SparseCheckout' = None
|
|
100
|
+
|
|
101
|
+
def as_dict(self) -> dict:
|
|
102
|
+
body = {}
|
|
103
|
+
if self.path: body['path'] = self.path
|
|
104
|
+
if self.provider: body['provider'] = self.provider
|
|
105
|
+
if self.sparse_checkout: body['sparse_checkout'] = self.sparse_checkout.as_dict()
|
|
106
|
+
if self.url: body['url'] = self.url
|
|
107
|
+
return body
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def from_dict(cls, d: Dict[str, any]) -> 'CreateRepo':
|
|
111
|
+
return cls(path=d.get('path', None),
|
|
112
|
+
provider=d.get('provider', None),
|
|
113
|
+
sparse_checkout=_from_dict(d, 'sparse_checkout', SparseCheckout),
|
|
114
|
+
url=d.get('url', None))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass
|
|
118
|
+
class CreateScope:
|
|
119
|
+
scope: str
|
|
120
|
+
initial_manage_principal: str = None
|
|
121
|
+
keyvault_metadata: 'AzureKeyVaultSecretScopeMetadata' = None
|
|
122
|
+
scope_backend_type: 'ScopeBackendType' = None
|
|
123
|
+
|
|
124
|
+
def as_dict(self) -> dict:
|
|
125
|
+
body = {}
|
|
126
|
+
if self.initial_manage_principal: body['initial_manage_principal'] = self.initial_manage_principal
|
|
127
|
+
if self.keyvault_metadata: body['keyvault_metadata'] = self.keyvault_metadata.as_dict()
|
|
128
|
+
if self.scope: body['scope'] = self.scope
|
|
129
|
+
if self.scope_backend_type: body['scope_backend_type'] = self.scope_backend_type.value
|
|
130
|
+
return body
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_dict(cls, d: Dict[str, any]) -> 'CreateScope':
|
|
134
|
+
return cls(initial_manage_principal=d.get('initial_manage_principal', None),
|
|
135
|
+
keyvault_metadata=_from_dict(d, 'keyvault_metadata', AzureKeyVaultSecretScopeMetadata),
|
|
136
|
+
scope=d.get('scope', None),
|
|
137
|
+
scope_backend_type=_enum(d, 'scope_backend_type', ScopeBackendType))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@dataclass
|
|
141
|
+
class CredentialInfo:
|
|
142
|
+
credential_id: int = None
|
|
143
|
+
git_provider: str = None
|
|
144
|
+
git_username: str = None
|
|
145
|
+
|
|
146
|
+
def as_dict(self) -> dict:
|
|
147
|
+
body = {}
|
|
148
|
+
if self.credential_id: body['credential_id'] = self.credential_id
|
|
149
|
+
if self.git_provider: body['git_provider'] = self.git_provider
|
|
150
|
+
if self.git_username: body['git_username'] = self.git_username
|
|
151
|
+
return body
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def from_dict(cls, d: Dict[str, any]) -> 'CredentialInfo':
|
|
155
|
+
return cls(credential_id=d.get('credential_id', None),
|
|
156
|
+
git_provider=d.get('git_provider', None),
|
|
157
|
+
git_username=d.get('git_username', None))
|
|
158
|
+
|
|
159
|
+
|
|
15
160
|
@dataclass
|
|
16
161
|
class Delete:
|
|
17
162
|
path: str
|
|
@@ -29,18 +174,74 @@ class Delete:
|
|
|
29
174
|
|
|
30
175
|
|
|
31
176
|
@dataclass
|
|
32
|
-
class
|
|
33
|
-
|
|
177
|
+
class DeleteAcl:
|
|
178
|
+
scope: str
|
|
179
|
+
principal: str
|
|
34
180
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
181
|
+
def as_dict(self) -> dict:
|
|
182
|
+
body = {}
|
|
183
|
+
if self.principal: body['principal'] = self.principal
|
|
184
|
+
if self.scope: body['scope'] = self.scope
|
|
185
|
+
return body
|
|
186
|
+
|
|
187
|
+
@classmethod
|
|
188
|
+
def from_dict(cls, d: Dict[str, any]) -> 'DeleteAcl':
|
|
189
|
+
return cls(principal=d.get('principal', None), scope=d.get('scope', None))
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@dataclass
|
|
193
|
+
class DeleteGitCredentialRequest:
|
|
194
|
+
"""Delete a credential"""
|
|
195
|
+
|
|
196
|
+
credential_id: int
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dataclass
|
|
200
|
+
class DeleteRepoRequest:
|
|
201
|
+
"""Delete a repo"""
|
|
202
|
+
|
|
203
|
+
repo_id: int
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@dataclass
|
|
207
|
+
class DeleteScope:
|
|
208
|
+
scope: str
|
|
209
|
+
|
|
210
|
+
def as_dict(self) -> dict:
|
|
211
|
+
body = {}
|
|
212
|
+
if self.scope: body['scope'] = self.scope
|
|
213
|
+
return body
|
|
214
|
+
|
|
215
|
+
@classmethod
|
|
216
|
+
def from_dict(cls, d: Dict[str, any]) -> 'DeleteScope':
|
|
217
|
+
return cls(scope=d.get('scope', None))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@dataclass
|
|
221
|
+
class DeleteSecret:
|
|
222
|
+
scope: str
|
|
223
|
+
key: str
|
|
224
|
+
|
|
225
|
+
def as_dict(self) -> dict:
|
|
226
|
+
body = {}
|
|
227
|
+
if self.key: body['key'] = self.key
|
|
228
|
+
if self.scope: body['scope'] = self.scope
|
|
229
|
+
return body
|
|
230
|
+
|
|
231
|
+
@classmethod
|
|
232
|
+
def from_dict(cls, d: Dict[str, any]) -> 'DeleteSecret':
|
|
233
|
+
return cls(key=d.get('key', None), scope=d.get('scope', None))
|
|
38
234
|
|
|
39
235
|
|
|
40
236
|
class ExportFormat(Enum):
|
|
41
|
-
"""This specifies the format of the file to be imported. By default, this is `SOURCE`.
|
|
42
|
-
|
|
237
|
+
"""This specifies the format of the file to be imported. By default, this is `SOURCE`.
|
|
238
|
+
|
|
239
|
+
If using `AUTO` the item is imported or exported as either a workspace file or a
|
|
240
|
+
notebook,depending on an analysis of the item’s extension and the header content provided in
|
|
241
|
+
the request. The value is case sensitive. In addition, if the item is imported as a notebook,
|
|
242
|
+
then the item’s extension is automatically removed."""
|
|
43
243
|
|
|
244
|
+
AUTO = 'AUTO'
|
|
44
245
|
DBC = 'DBC'
|
|
45
246
|
HTML = 'HTML'
|
|
46
247
|
JUPYTER = 'JUPYTER'
|
|
@@ -48,6 +249,15 @@ class ExportFormat(Enum):
|
|
|
48
249
|
SOURCE = 'SOURCE'
|
|
49
250
|
|
|
50
251
|
|
|
252
|
+
@dataclass
|
|
253
|
+
class ExportRequest:
|
|
254
|
+
"""Export a workspace object"""
|
|
255
|
+
|
|
256
|
+
path: str
|
|
257
|
+
direct_download: bool = None
|
|
258
|
+
format: 'ExportFormat' = None
|
|
259
|
+
|
|
260
|
+
|
|
51
261
|
@dataclass
|
|
52
262
|
class ExportResponse:
|
|
53
263
|
content: str = None
|
|
@@ -63,7 +273,43 @@ class ExportResponse:
|
|
|
63
273
|
|
|
64
274
|
|
|
65
275
|
@dataclass
|
|
66
|
-
class
|
|
276
|
+
class GetAclRequest:
|
|
277
|
+
"""Get secret ACL details"""
|
|
278
|
+
|
|
279
|
+
scope: str
|
|
280
|
+
principal: str
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@dataclass
|
|
284
|
+
class GetCredentialsResponse:
|
|
285
|
+
credentials: 'List[CredentialInfo]' = None
|
|
286
|
+
|
|
287
|
+
def as_dict(self) -> dict:
|
|
288
|
+
body = {}
|
|
289
|
+
if self.credentials: body['credentials'] = [v.as_dict() for v in self.credentials]
|
|
290
|
+
return body
|
|
291
|
+
|
|
292
|
+
@classmethod
|
|
293
|
+
def from_dict(cls, d: Dict[str, any]) -> 'GetCredentialsResponse':
|
|
294
|
+
return cls(credentials=_repeated(d, 'credentials', CredentialInfo))
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@dataclass
|
|
298
|
+
class GetGitCredentialRequest:
|
|
299
|
+
"""Get a credential entry"""
|
|
300
|
+
|
|
301
|
+
credential_id: int
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
@dataclass
|
|
305
|
+
class GetRepoRequest:
|
|
306
|
+
"""Get a repo"""
|
|
307
|
+
|
|
308
|
+
repo_id: int
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@dataclass
|
|
312
|
+
class GetStatusRequest:
|
|
67
313
|
"""Get status"""
|
|
68
314
|
|
|
69
315
|
path: str
|
|
@@ -105,11 +351,48 @@ class Language(Enum):
|
|
|
105
351
|
|
|
106
352
|
|
|
107
353
|
@dataclass
|
|
108
|
-
class
|
|
109
|
-
"""
|
|
354
|
+
class ListAclsRequest:
|
|
355
|
+
"""Lists ACLs"""
|
|
110
356
|
|
|
111
|
-
|
|
112
|
-
|
|
357
|
+
scope: str
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@dataclass
|
|
361
|
+
class ListAclsResponse:
|
|
362
|
+
items: 'List[AclItem]' = None
|
|
363
|
+
|
|
364
|
+
def as_dict(self) -> dict:
|
|
365
|
+
body = {}
|
|
366
|
+
if self.items: body['items'] = [v.as_dict() for v in self.items]
|
|
367
|
+
return body
|
|
368
|
+
|
|
369
|
+
@classmethod
|
|
370
|
+
def from_dict(cls, d: Dict[str, any]) -> 'ListAclsResponse':
|
|
371
|
+
return cls(items=_repeated(d, 'items', AclItem))
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
@dataclass
|
|
375
|
+
class ListReposRequest:
|
|
376
|
+
"""Get repos"""
|
|
377
|
+
|
|
378
|
+
next_page_token: str = None
|
|
379
|
+
path_prefix: str = None
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
@dataclass
|
|
383
|
+
class ListReposResponse:
|
|
384
|
+
next_page_token: str = None
|
|
385
|
+
repos: 'List[RepoInfo]' = None
|
|
386
|
+
|
|
387
|
+
def as_dict(self) -> dict:
|
|
388
|
+
body = {}
|
|
389
|
+
if self.next_page_token: body['next_page_token'] = self.next_page_token
|
|
390
|
+
if self.repos: body['repos'] = [v.as_dict() for v in self.repos]
|
|
391
|
+
return body
|
|
392
|
+
|
|
393
|
+
@classmethod
|
|
394
|
+
def from_dict(cls, d: Dict[str, any]) -> 'ListReposResponse':
|
|
395
|
+
return cls(next_page_token=d.get('next_page_token', None), repos=_repeated(d, 'repos', RepoInfo))
|
|
113
396
|
|
|
114
397
|
|
|
115
398
|
@dataclass
|
|
@@ -126,6 +409,49 @@ class ListResponse:
|
|
|
126
409
|
return cls(objects=_repeated(d, 'objects', ObjectInfo))
|
|
127
410
|
|
|
128
411
|
|
|
412
|
+
@dataclass
|
|
413
|
+
class ListScopesResponse:
|
|
414
|
+
scopes: 'List[SecretScope]' = None
|
|
415
|
+
|
|
416
|
+
def as_dict(self) -> dict:
|
|
417
|
+
body = {}
|
|
418
|
+
if self.scopes: body['scopes'] = [v.as_dict() for v in self.scopes]
|
|
419
|
+
return body
|
|
420
|
+
|
|
421
|
+
@classmethod
|
|
422
|
+
def from_dict(cls, d: Dict[str, any]) -> 'ListScopesResponse':
|
|
423
|
+
return cls(scopes=_repeated(d, 'scopes', SecretScope))
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
@dataclass
|
|
427
|
+
class ListSecretsRequest:
|
|
428
|
+
"""List secret keys"""
|
|
429
|
+
|
|
430
|
+
scope: str
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
@dataclass
|
|
434
|
+
class ListSecretsResponse:
|
|
435
|
+
secrets: 'List[SecretMetadata]' = None
|
|
436
|
+
|
|
437
|
+
def as_dict(self) -> dict:
|
|
438
|
+
body = {}
|
|
439
|
+
if self.secrets: body['secrets'] = [v.as_dict() for v in self.secrets]
|
|
440
|
+
return body
|
|
441
|
+
|
|
442
|
+
@classmethod
|
|
443
|
+
def from_dict(cls, d: Dict[str, any]) -> 'ListSecretsResponse':
|
|
444
|
+
return cls(secrets=_repeated(d, 'secrets', SecretMetadata))
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@dataclass
|
|
448
|
+
class ListWorkspaceRequest:
|
|
449
|
+
"""List contents"""
|
|
450
|
+
|
|
451
|
+
path: str
|
|
452
|
+
notebooks_modified_after: int = None
|
|
453
|
+
|
|
454
|
+
|
|
129
455
|
@dataclass
|
|
130
456
|
class Mkdirs:
|
|
131
457
|
path: str
|
|
@@ -182,6 +508,575 @@ class ObjectType(Enum):
|
|
|
182
508
|
REPO = 'REPO'
|
|
183
509
|
|
|
184
510
|
|
|
511
|
+
@dataclass
|
|
512
|
+
class PutAcl:
|
|
513
|
+
scope: str
|
|
514
|
+
principal: str
|
|
515
|
+
permission: 'AclPermission'
|
|
516
|
+
|
|
517
|
+
def as_dict(self) -> dict:
|
|
518
|
+
body = {}
|
|
519
|
+
if self.permission: body['permission'] = self.permission.value
|
|
520
|
+
if self.principal: body['principal'] = self.principal
|
|
521
|
+
if self.scope: body['scope'] = self.scope
|
|
522
|
+
return body
|
|
523
|
+
|
|
524
|
+
@classmethod
|
|
525
|
+
def from_dict(cls, d: Dict[str, any]) -> 'PutAcl':
|
|
526
|
+
return cls(permission=_enum(d, 'permission', AclPermission),
|
|
527
|
+
principal=d.get('principal', None),
|
|
528
|
+
scope=d.get('scope', None))
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
@dataclass
|
|
532
|
+
class PutSecret:
|
|
533
|
+
scope: str
|
|
534
|
+
key: str
|
|
535
|
+
bytes_value: str = None
|
|
536
|
+
string_value: str = None
|
|
537
|
+
|
|
538
|
+
def as_dict(self) -> dict:
|
|
539
|
+
body = {}
|
|
540
|
+
if self.bytes_value: body['bytes_value'] = self.bytes_value
|
|
541
|
+
if self.key: body['key'] = self.key
|
|
542
|
+
if self.scope: body['scope'] = self.scope
|
|
543
|
+
if self.string_value: body['string_value'] = self.string_value
|
|
544
|
+
return body
|
|
545
|
+
|
|
546
|
+
@classmethod
|
|
547
|
+
def from_dict(cls, d: Dict[str, any]) -> 'PutSecret':
|
|
548
|
+
return cls(bytes_value=d.get('bytes_value', None),
|
|
549
|
+
key=d.get('key', None),
|
|
550
|
+
scope=d.get('scope', None),
|
|
551
|
+
string_value=d.get('string_value', None))
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
@dataclass
|
|
555
|
+
class RepoInfo:
|
|
556
|
+
branch: str = None
|
|
557
|
+
head_commit_id: str = None
|
|
558
|
+
id: int = None
|
|
559
|
+
path: str = None
|
|
560
|
+
provider: str = None
|
|
561
|
+
sparse_checkout: 'SparseCheckout' = None
|
|
562
|
+
url: str = None
|
|
563
|
+
|
|
564
|
+
def as_dict(self) -> dict:
|
|
565
|
+
body = {}
|
|
566
|
+
if self.branch: body['branch'] = self.branch
|
|
567
|
+
if self.head_commit_id: body['head_commit_id'] = self.head_commit_id
|
|
568
|
+
if self.id: body['id'] = self.id
|
|
569
|
+
if self.path: body['path'] = self.path
|
|
570
|
+
if self.provider: body['provider'] = self.provider
|
|
571
|
+
if self.sparse_checkout: body['sparse_checkout'] = self.sparse_checkout.as_dict()
|
|
572
|
+
if self.url: body['url'] = self.url
|
|
573
|
+
return body
|
|
574
|
+
|
|
575
|
+
@classmethod
|
|
576
|
+
def from_dict(cls, d: Dict[str, any]) -> 'RepoInfo':
|
|
577
|
+
return cls(branch=d.get('branch', None),
|
|
578
|
+
head_commit_id=d.get('head_commit_id', None),
|
|
579
|
+
id=d.get('id', None),
|
|
580
|
+
path=d.get('path', None),
|
|
581
|
+
provider=d.get('provider', None),
|
|
582
|
+
sparse_checkout=_from_dict(d, 'sparse_checkout', SparseCheckout),
|
|
583
|
+
url=d.get('url', None))
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class ScopeBackendType(Enum):
|
|
587
|
+
|
|
588
|
+
AZURE_KEYVAULT = 'AZURE_KEYVAULT'
|
|
589
|
+
DATABRICKS = 'DATABRICKS'
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
@dataclass
|
|
593
|
+
class SecretMetadata:
|
|
594
|
+
key: str = None
|
|
595
|
+
last_updated_timestamp: int = None
|
|
596
|
+
|
|
597
|
+
def as_dict(self) -> dict:
|
|
598
|
+
body = {}
|
|
599
|
+
if self.key: body['key'] = self.key
|
|
600
|
+
if self.last_updated_timestamp: body['last_updated_timestamp'] = self.last_updated_timestamp
|
|
601
|
+
return body
|
|
602
|
+
|
|
603
|
+
@classmethod
|
|
604
|
+
def from_dict(cls, d: Dict[str, any]) -> 'SecretMetadata':
|
|
605
|
+
return cls(key=d.get('key', None), last_updated_timestamp=d.get('last_updated_timestamp', None))
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
@dataclass
|
|
609
|
+
class SecretScope:
|
|
610
|
+
backend_type: 'ScopeBackendType' = None
|
|
611
|
+
keyvault_metadata: 'AzureKeyVaultSecretScopeMetadata' = None
|
|
612
|
+
name: str = None
|
|
613
|
+
|
|
614
|
+
def as_dict(self) -> dict:
|
|
615
|
+
body = {}
|
|
616
|
+
if self.backend_type: body['backend_type'] = self.backend_type.value
|
|
617
|
+
if self.keyvault_metadata: body['keyvault_metadata'] = self.keyvault_metadata.as_dict()
|
|
618
|
+
if self.name: body['name'] = self.name
|
|
619
|
+
return body
|
|
620
|
+
|
|
621
|
+
@classmethod
|
|
622
|
+
def from_dict(cls, d: Dict[str, any]) -> 'SecretScope':
|
|
623
|
+
return cls(backend_type=_enum(d, 'backend_type', ScopeBackendType),
|
|
624
|
+
keyvault_metadata=_from_dict(d, 'keyvault_metadata', AzureKeyVaultSecretScopeMetadata),
|
|
625
|
+
name=d.get('name', None))
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
@dataclass
|
|
629
|
+
class SparseCheckout:
|
|
630
|
+
patterns: 'List[str]' = None
|
|
631
|
+
|
|
632
|
+
def as_dict(self) -> dict:
|
|
633
|
+
body = {}
|
|
634
|
+
if self.patterns: body['patterns'] = [v for v in self.patterns]
|
|
635
|
+
return body
|
|
636
|
+
|
|
637
|
+
@classmethod
|
|
638
|
+
def from_dict(cls, d: Dict[str, any]) -> 'SparseCheckout':
|
|
639
|
+
return cls(patterns=d.get('patterns', None))
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
@dataclass
|
|
643
|
+
class SparseCheckoutUpdate:
|
|
644
|
+
patterns: 'List[str]' = None
|
|
645
|
+
|
|
646
|
+
def as_dict(self) -> dict:
|
|
647
|
+
body = {}
|
|
648
|
+
if self.patterns: body['patterns'] = [v for v in self.patterns]
|
|
649
|
+
return body
|
|
650
|
+
|
|
651
|
+
@classmethod
|
|
652
|
+
def from_dict(cls, d: Dict[str, any]) -> 'SparseCheckoutUpdate':
|
|
653
|
+
return cls(patterns=d.get('patterns', None))
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
@dataclass
|
|
657
|
+
class UpdateCredentials:
|
|
658
|
+
credential_id: int
|
|
659
|
+
git_provider: str = None
|
|
660
|
+
git_username: str = None
|
|
661
|
+
personal_access_token: str = None
|
|
662
|
+
|
|
663
|
+
def as_dict(self) -> dict:
|
|
664
|
+
body = {}
|
|
665
|
+
if self.credential_id: body['credential_id'] = self.credential_id
|
|
666
|
+
if self.git_provider: body['git_provider'] = self.git_provider
|
|
667
|
+
if self.git_username: body['git_username'] = self.git_username
|
|
668
|
+
if self.personal_access_token: body['personal_access_token'] = self.personal_access_token
|
|
669
|
+
return body
|
|
670
|
+
|
|
671
|
+
@classmethod
|
|
672
|
+
def from_dict(cls, d: Dict[str, any]) -> 'UpdateCredentials':
|
|
673
|
+
return cls(credential_id=d.get('credential_id', None),
|
|
674
|
+
git_provider=d.get('git_provider', None),
|
|
675
|
+
git_username=d.get('git_username', None),
|
|
676
|
+
personal_access_token=d.get('personal_access_token', None))
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
@dataclass
|
|
680
|
+
class UpdateRepo:
|
|
681
|
+
repo_id: int
|
|
682
|
+
branch: str = None
|
|
683
|
+
sparse_checkout: 'SparseCheckoutUpdate' = None
|
|
684
|
+
tag: str = None
|
|
685
|
+
|
|
686
|
+
def as_dict(self) -> dict:
|
|
687
|
+
body = {}
|
|
688
|
+
if self.branch: body['branch'] = self.branch
|
|
689
|
+
if self.repo_id: body['repo_id'] = self.repo_id
|
|
690
|
+
if self.sparse_checkout: body['sparse_checkout'] = self.sparse_checkout.as_dict()
|
|
691
|
+
if self.tag: body['tag'] = self.tag
|
|
692
|
+
return body
|
|
693
|
+
|
|
694
|
+
@classmethod
|
|
695
|
+
def from_dict(cls, d: Dict[str, any]) -> 'UpdateRepo':
|
|
696
|
+
return cls(branch=d.get('branch', None),
|
|
697
|
+
repo_id=d.get('repo_id', None),
|
|
698
|
+
sparse_checkout=_from_dict(d, 'sparse_checkout', SparseCheckoutUpdate),
|
|
699
|
+
tag=d.get('tag', None))
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
class GitCredentialsAPI:
|
|
703
|
+
"""Registers personal access token for Databricks to do operations on behalf of the user.
|
|
704
|
+
|
|
705
|
+
See [more info].
|
|
706
|
+
|
|
707
|
+
[more info]: https://docs.databricks.com/repos/get-access-tokens-from-git-provider.html"""
|
|
708
|
+
|
|
709
|
+
def __init__(self, api_client):
|
|
710
|
+
self._api = api_client
|
|
711
|
+
|
|
712
|
+
def create(self,
|
|
713
|
+
git_provider: str,
|
|
714
|
+
*,
|
|
715
|
+
git_username: str = None,
|
|
716
|
+
personal_access_token: str = None,
|
|
717
|
+
**kwargs) -> CreateCredentialsResponse:
|
|
718
|
+
"""Create a credential entry.
|
|
719
|
+
|
|
720
|
+
Creates a Git credential entry for the user. Only one Git credential per user is supported, so any
|
|
721
|
+
attempts to create credentials if an entry already exists will fail. Use the PATCH endpoint to update
|
|
722
|
+
existing credentials, or the DELETE endpoint to delete existing credentials."""
|
|
723
|
+
request = kwargs.get('request', None)
|
|
724
|
+
if not request: # request is not given through keyed args
|
|
725
|
+
request = CreateCredentials(git_provider=git_provider,
|
|
726
|
+
git_username=git_username,
|
|
727
|
+
personal_access_token=personal_access_token)
|
|
728
|
+
body = request.as_dict()
|
|
729
|
+
|
|
730
|
+
json = self._api.do('POST', '/api/2.0/git-credentials', body=body)
|
|
731
|
+
return CreateCredentialsResponse.from_dict(json)
|
|
732
|
+
|
|
733
|
+
def delete(self, credential_id: int, **kwargs):
|
|
734
|
+
"""Delete a credential.
|
|
735
|
+
|
|
736
|
+
Deletes the specified Git credential."""
|
|
737
|
+
request = kwargs.get('request', None)
|
|
738
|
+
if not request: # request is not given through keyed args
|
|
739
|
+
request = DeleteGitCredentialRequest(credential_id=credential_id)
|
|
740
|
+
|
|
741
|
+
self._api.do('DELETE', f'/api/2.0/git-credentials/{request.credential_id}')
|
|
742
|
+
|
|
743
|
+
def get(self, credential_id: int, **kwargs) -> CredentialInfo:
|
|
744
|
+
"""Get a credential entry.
|
|
745
|
+
|
|
746
|
+
Gets the Git credential with the specified credential ID."""
|
|
747
|
+
request = kwargs.get('request', None)
|
|
748
|
+
if not request: # request is not given through keyed args
|
|
749
|
+
request = GetGitCredentialRequest(credential_id=credential_id)
|
|
750
|
+
|
|
751
|
+
json = self._api.do('GET', f'/api/2.0/git-credentials/{request.credential_id}')
|
|
752
|
+
return CredentialInfo.from_dict(json)
|
|
753
|
+
|
|
754
|
+
def list(self) -> Iterator[CredentialInfo]:
|
|
755
|
+
"""Get Git credentials.
|
|
756
|
+
|
|
757
|
+
Lists the calling user's Git credentials. One credential per user is supported."""
|
|
758
|
+
|
|
759
|
+
json = self._api.do('GET', '/api/2.0/git-credentials')
|
|
760
|
+
return [CredentialInfo.from_dict(v) for v in json.get('credentials', [])]
|
|
761
|
+
|
|
762
|
+
def update(self,
|
|
763
|
+
credential_id: int,
|
|
764
|
+
*,
|
|
765
|
+
git_provider: str = None,
|
|
766
|
+
git_username: str = None,
|
|
767
|
+
personal_access_token: str = None,
|
|
768
|
+
**kwargs):
|
|
769
|
+
"""Update a credential.
|
|
770
|
+
|
|
771
|
+
Updates the specified Git credential."""
|
|
772
|
+
request = kwargs.get('request', None)
|
|
773
|
+
if not request: # request is not given through keyed args
|
|
774
|
+
request = UpdateCredentials(credential_id=credential_id,
|
|
775
|
+
git_provider=git_provider,
|
|
776
|
+
git_username=git_username,
|
|
777
|
+
personal_access_token=personal_access_token)
|
|
778
|
+
body = request.as_dict()
|
|
779
|
+
self._api.do('PATCH', f'/api/2.0/git-credentials/{request.credential_id}', body=body)
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
class ReposAPI:
|
|
783
|
+
"""The Repos API allows users to manage their git repos. Users can use the API to access all repos that they
|
|
784
|
+
have manage permissions on.
|
|
785
|
+
|
|
786
|
+
Databricks Repos is a visual Git client in Databricks. It supports common Git operations such a cloning a
|
|
787
|
+
repository, committing and pushing, pulling, branch management, and visual comparison of diffs when
|
|
788
|
+
committing.
|
|
789
|
+
|
|
790
|
+
Within Repos you can develop code in notebooks or other files and follow data science and engineering code
|
|
791
|
+
development best practices using Git for version control, collaboration, and CI/CD."""
|
|
792
|
+
|
|
793
|
+
def __init__(self, api_client):
|
|
794
|
+
self._api = api_client
|
|
795
|
+
|
|
796
|
+
def create(self,
|
|
797
|
+
url: str,
|
|
798
|
+
provider: str,
|
|
799
|
+
*,
|
|
800
|
+
path: str = None,
|
|
801
|
+
sparse_checkout: SparseCheckout = None,
|
|
802
|
+
**kwargs) -> RepoInfo:
|
|
803
|
+
"""Create a repo.
|
|
804
|
+
|
|
805
|
+
Creates a repo in the workspace and links it to the remote Git repo specified. Note that repos created
|
|
806
|
+
programmatically must be linked to a remote Git repo, unlike repos created in the browser."""
|
|
807
|
+
request = kwargs.get('request', None)
|
|
808
|
+
if not request: # request is not given through keyed args
|
|
809
|
+
request = CreateRepo(path=path, provider=provider, sparse_checkout=sparse_checkout, url=url)
|
|
810
|
+
body = request.as_dict()
|
|
811
|
+
|
|
812
|
+
json = self._api.do('POST', '/api/2.0/repos', body=body)
|
|
813
|
+
return RepoInfo.from_dict(json)
|
|
814
|
+
|
|
815
|
+
def delete(self, repo_id: int, **kwargs):
|
|
816
|
+
"""Delete a repo.
|
|
817
|
+
|
|
818
|
+
Deletes the specified repo."""
|
|
819
|
+
request = kwargs.get('request', None)
|
|
820
|
+
if not request: # request is not given through keyed args
|
|
821
|
+
request = DeleteRepoRequest(repo_id=repo_id)
|
|
822
|
+
|
|
823
|
+
self._api.do('DELETE', f'/api/2.0/repos/{request.repo_id}')
|
|
824
|
+
|
|
825
|
+
def get(self, repo_id: int, **kwargs) -> RepoInfo:
|
|
826
|
+
"""Get a repo.
|
|
827
|
+
|
|
828
|
+
Returns the repo with the given repo ID."""
|
|
829
|
+
request = kwargs.get('request', None)
|
|
830
|
+
if not request: # request is not given through keyed args
|
|
831
|
+
request = GetRepoRequest(repo_id=repo_id)
|
|
832
|
+
|
|
833
|
+
json = self._api.do('GET', f'/api/2.0/repos/{request.repo_id}')
|
|
834
|
+
return RepoInfo.from_dict(json)
|
|
835
|
+
|
|
836
|
+
def list(self, *, next_page_token: str = None, path_prefix: str = None, **kwargs) -> Iterator[RepoInfo]:
|
|
837
|
+
"""Get repos.
|
|
838
|
+
|
|
839
|
+
Returns repos that the calling user has Manage permissions on. Results are paginated with each page
|
|
840
|
+
containing twenty repos."""
|
|
841
|
+
request = kwargs.get('request', None)
|
|
842
|
+
if not request: # request is not given through keyed args
|
|
843
|
+
request = ListReposRequest(next_page_token=next_page_token, path_prefix=path_prefix)
|
|
844
|
+
|
|
845
|
+
query = {}
|
|
846
|
+
if next_page_token: query['next_page_token'] = request.next_page_token
|
|
847
|
+
if path_prefix: query['path_prefix'] = request.path_prefix
|
|
848
|
+
|
|
849
|
+
while True:
|
|
850
|
+
json = self._api.do('GET', '/api/2.0/repos', query=query)
|
|
851
|
+
if 'repos' not in json or not json['repos']:
|
|
852
|
+
return
|
|
853
|
+
for v in json['repos']:
|
|
854
|
+
yield RepoInfo.from_dict(v)
|
|
855
|
+
if 'next_page_token' not in json or not json['next_page_token']:
|
|
856
|
+
return
|
|
857
|
+
query['next_page_token'] = json['next_page_token']
|
|
858
|
+
|
|
859
|
+
def update(self,
|
|
860
|
+
repo_id: int,
|
|
861
|
+
*,
|
|
862
|
+
branch: str = None,
|
|
863
|
+
sparse_checkout: SparseCheckoutUpdate = None,
|
|
864
|
+
tag: str = None,
|
|
865
|
+
**kwargs):
|
|
866
|
+
"""Update a repo.
|
|
867
|
+
|
|
868
|
+
Updates the repo to a different branch or tag, or updates the repo to the latest commit on the same
|
|
869
|
+
branch."""
|
|
870
|
+
request = kwargs.get('request', None)
|
|
871
|
+
if not request: # request is not given through keyed args
|
|
872
|
+
request = UpdateRepo(branch=branch, repo_id=repo_id, sparse_checkout=sparse_checkout, tag=tag)
|
|
873
|
+
body = request.as_dict()
|
|
874
|
+
self._api.do('PATCH', f'/api/2.0/repos/{request.repo_id}', body=body)
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
class SecretsAPI:
|
|
878
|
+
"""The Secrets API allows you to manage secrets, secret scopes, and access permissions.
|
|
879
|
+
|
|
880
|
+
Sometimes accessing data requires that you authenticate to external data sources through JDBC. Instead of
|
|
881
|
+
directly entering your credentials into a notebook, use Databricks secrets to store your credentials and
|
|
882
|
+
reference them in notebooks and jobs.
|
|
883
|
+
|
|
884
|
+
Administrators, secret creators, and users granted permission can read Databricks secrets. While
|
|
885
|
+
Databricks makes an effort to redact secret values that might be displayed in notebooks, it is not
|
|
886
|
+
possible to prevent such users from reading secrets."""
|
|
887
|
+
|
|
888
|
+
def __init__(self, api_client):
|
|
889
|
+
self._api = api_client
|
|
890
|
+
|
|
891
|
+
def create_scope(self,
|
|
892
|
+
scope: str,
|
|
893
|
+
*,
|
|
894
|
+
initial_manage_principal: str = None,
|
|
895
|
+
keyvault_metadata: AzureKeyVaultSecretScopeMetadata = None,
|
|
896
|
+
scope_backend_type: ScopeBackendType = None,
|
|
897
|
+
**kwargs):
|
|
898
|
+
"""Create a new secret scope.
|
|
899
|
+
|
|
900
|
+
The scope name must consist of alphanumeric characters, dashes, underscores, and periods, and may not
|
|
901
|
+
exceed 128 characters. The maximum number of scopes in a workspace is 100."""
|
|
902
|
+
request = kwargs.get('request', None)
|
|
903
|
+
if not request: # request is not given through keyed args
|
|
904
|
+
request = CreateScope(initial_manage_principal=initial_manage_principal,
|
|
905
|
+
keyvault_metadata=keyvault_metadata,
|
|
906
|
+
scope=scope,
|
|
907
|
+
scope_backend_type=scope_backend_type)
|
|
908
|
+
body = request.as_dict()
|
|
909
|
+
self._api.do('POST', '/api/2.0/secrets/scopes/create', body=body)
|
|
910
|
+
|
|
911
|
+
def delete_acl(self, scope: str, principal: str, **kwargs):
|
|
912
|
+
"""Delete an ACL.
|
|
913
|
+
|
|
914
|
+
Deletes the given ACL on the given scope.
|
|
915
|
+
|
|
916
|
+
Users must have the `MANAGE` permission to invoke this API. Throws `RESOURCE_DOES_NOT_EXIST` if no
|
|
917
|
+
such secret scope, principal, or ACL exists. Throws `PERMISSION_DENIED` if the user does not have
|
|
918
|
+
permission to make this API call."""
|
|
919
|
+
request = kwargs.get('request', None)
|
|
920
|
+
if not request: # request is not given through keyed args
|
|
921
|
+
request = DeleteAcl(principal=principal, scope=scope)
|
|
922
|
+
body = request.as_dict()
|
|
923
|
+
self._api.do('POST', '/api/2.0/secrets/acls/delete', body=body)
|
|
924
|
+
|
|
925
|
+
def delete_scope(self, scope: str, **kwargs):
|
|
926
|
+
"""Delete a secret scope.
|
|
927
|
+
|
|
928
|
+
Deletes a secret scope.
|
|
929
|
+
|
|
930
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if the scope does not exist. Throws `PERMISSION_DENIED` if the user
|
|
931
|
+
does not have permission to make this API call."""
|
|
932
|
+
request = kwargs.get('request', None)
|
|
933
|
+
if not request: # request is not given through keyed args
|
|
934
|
+
request = DeleteScope(scope=scope)
|
|
935
|
+
body = request.as_dict()
|
|
936
|
+
self._api.do('POST', '/api/2.0/secrets/scopes/delete', body=body)
|
|
937
|
+
|
|
938
|
+
def delete_secret(self, scope: str, key: str, **kwargs):
|
|
939
|
+
"""Delete a secret.
|
|
940
|
+
|
|
941
|
+
Deletes the secret stored in this secret scope. You must have `WRITE` or `MANAGE` permission on the
|
|
942
|
+
secret scope.
|
|
943
|
+
|
|
944
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if no such secret scope or secret exists. Throws `PERMISSION_DENIED`
|
|
945
|
+
if the user does not have permission to make this API call."""
|
|
946
|
+
request = kwargs.get('request', None)
|
|
947
|
+
if not request: # request is not given through keyed args
|
|
948
|
+
request = DeleteSecret(key=key, scope=scope)
|
|
949
|
+
body = request.as_dict()
|
|
950
|
+
self._api.do('POST', '/api/2.0/secrets/delete', body=body)
|
|
951
|
+
|
|
952
|
+
def get_acl(self, scope: str, principal: str, **kwargs) -> AclItem:
|
|
953
|
+
"""Get secret ACL details.
|
|
954
|
+
|
|
955
|
+
Gets the details about the given ACL, such as the group and permission. Users must have the `MANAGE`
|
|
956
|
+
permission to invoke this API.
|
|
957
|
+
|
|
958
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if no such secret scope exists. Throws `PERMISSION_DENIED` if the
|
|
959
|
+
user does not have permission to make this API call."""
|
|
960
|
+
request = kwargs.get('request', None)
|
|
961
|
+
if not request: # request is not given through keyed args
|
|
962
|
+
request = GetAclRequest(principal=principal, scope=scope)
|
|
963
|
+
|
|
964
|
+
query = {}
|
|
965
|
+
if principal: query['principal'] = request.principal
|
|
966
|
+
if scope: query['scope'] = request.scope
|
|
967
|
+
|
|
968
|
+
json = self._api.do('GET', '/api/2.0/secrets/acls/get', query=query)
|
|
969
|
+
return AclItem.from_dict(json)
|
|
970
|
+
|
|
971
|
+
def list_acls(self, scope: str, **kwargs) -> Iterator[AclItem]:
|
|
972
|
+
"""Lists ACLs.
|
|
973
|
+
|
|
974
|
+
List the ACLs for a given secret scope. Users must have the `MANAGE` permission to invoke this API.
|
|
975
|
+
|
|
976
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if no such secret scope exists. Throws `PERMISSION_DENIED` if the
|
|
977
|
+
user does not have permission to make this API call."""
|
|
978
|
+
request = kwargs.get('request', None)
|
|
979
|
+
if not request: # request is not given through keyed args
|
|
980
|
+
request = ListAclsRequest(scope=scope)
|
|
981
|
+
|
|
982
|
+
query = {}
|
|
983
|
+
if scope: query['scope'] = request.scope
|
|
984
|
+
|
|
985
|
+
json = self._api.do('GET', '/api/2.0/secrets/acls/list', query=query)
|
|
986
|
+
return [AclItem.from_dict(v) for v in json.get('items', [])]
|
|
987
|
+
|
|
988
|
+
def list_scopes(self) -> Iterator[SecretScope]:
|
|
989
|
+
"""List all scopes.
|
|
990
|
+
|
|
991
|
+
Lists all secret scopes available in the workspace.
|
|
992
|
+
|
|
993
|
+
Throws `PERMISSION_DENIED` if the user does not have permission to make this API call."""
|
|
994
|
+
|
|
995
|
+
json = self._api.do('GET', '/api/2.0/secrets/scopes/list')
|
|
996
|
+
return [SecretScope.from_dict(v) for v in json.get('scopes', [])]
|
|
997
|
+
|
|
998
|
+
def list_secrets(self, scope: str, **kwargs) -> Iterator[SecretMetadata]:
|
|
999
|
+
"""List secret keys.
|
|
1000
|
+
|
|
1001
|
+
Lists the secret keys that are stored at this scope. This is a metadata-only operation; secret data
|
|
1002
|
+
cannot be retrieved using this API. Users need the READ permission to make this call.
|
|
1003
|
+
|
|
1004
|
+
The lastUpdatedTimestamp returned is in milliseconds since epoch. Throws `RESOURCE_DOES_NOT_EXIST` if
|
|
1005
|
+
no such secret scope exists. Throws `PERMISSION_DENIED` if the user does not have permission to make
|
|
1006
|
+
this API call."""
|
|
1007
|
+
request = kwargs.get('request', None)
|
|
1008
|
+
if not request: # request is not given through keyed args
|
|
1009
|
+
request = ListSecretsRequest(scope=scope)
|
|
1010
|
+
|
|
1011
|
+
query = {}
|
|
1012
|
+
if scope: query['scope'] = request.scope
|
|
1013
|
+
|
|
1014
|
+
json = self._api.do('GET', '/api/2.0/secrets/list', query=query)
|
|
1015
|
+
return [SecretMetadata.from_dict(v) for v in json.get('secrets', [])]
|
|
1016
|
+
|
|
1017
|
+
def put_acl(self, scope: str, principal: str, permission: AclPermission, **kwargs):
|
|
1018
|
+
"""Create/update an ACL.
|
|
1019
|
+
|
|
1020
|
+
Creates or overwrites the Access Control List (ACL) associated with the given principal (user or
|
|
1021
|
+
group) on the specified scope point.
|
|
1022
|
+
|
|
1023
|
+
In general, a user or group will use the most powerful permission available to them, and permissions
|
|
1024
|
+
are ordered as follows:
|
|
1025
|
+
|
|
1026
|
+
* `MANAGE` - Allowed to change ACLs, and read and write to this secret scope. * `WRITE` - Allowed to
|
|
1027
|
+
read and write to this secret scope. * `READ` - Allowed to read this secret scope and list what
|
|
1028
|
+
secrets are available.
|
|
1029
|
+
|
|
1030
|
+
Note that in general, secret values can only be read from within a command on a cluster (for example,
|
|
1031
|
+
through a notebook). There is no API to read the actual secret value material outside of a cluster.
|
|
1032
|
+
However, the user's permission will be applied based on who is executing the command, and they must
|
|
1033
|
+
have at least READ permission.
|
|
1034
|
+
|
|
1035
|
+
Users must have the `MANAGE` permission to invoke this API.
|
|
1036
|
+
|
|
1037
|
+
The principal is a user or group name corresponding to an existing Databricks principal to be granted
|
|
1038
|
+
or revoked access.
|
|
1039
|
+
|
|
1040
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if no such secret scope exists. Throws `RESOURCE_ALREADY_EXISTS` if a
|
|
1041
|
+
permission for the principal already exists. Throws `INVALID_PARAMETER_VALUE` if the permission is
|
|
1042
|
+
invalid. Throws `PERMISSION_DENIED` if the user does not have permission to make this API call."""
|
|
1043
|
+
request = kwargs.get('request', None)
|
|
1044
|
+
if not request: # request is not given through keyed args
|
|
1045
|
+
request = PutAcl(permission=permission, principal=principal, scope=scope)
|
|
1046
|
+
body = request.as_dict()
|
|
1047
|
+
self._api.do('POST', '/api/2.0/secrets/acls/put', body=body)
|
|
1048
|
+
|
|
1049
|
+
def put_secret(self,
|
|
1050
|
+
scope: str,
|
|
1051
|
+
key: str,
|
|
1052
|
+
*,
|
|
1053
|
+
bytes_value: str = None,
|
|
1054
|
+
string_value: str = None,
|
|
1055
|
+
**kwargs):
|
|
1056
|
+
"""Add a secret.
|
|
1057
|
+
|
|
1058
|
+
Inserts a secret under the provided scope with the given name. If a secret already exists with the
|
|
1059
|
+
same name, this command overwrites the existing secret's value. The server encrypts the secret using
|
|
1060
|
+
the secret scope's encryption settings before storing it.
|
|
1061
|
+
|
|
1062
|
+
You must have `WRITE` or `MANAGE` permission on the secret scope. The secret key must consist of
|
|
1063
|
+
alphanumeric characters, dashes, underscores, and periods, and cannot exceed 128 characters. The
|
|
1064
|
+
maximum allowed secret value size is 128 KB. The maximum number of secrets in a given scope is 1000.
|
|
1065
|
+
|
|
1066
|
+
The input fields "string_value" or "bytes_value" specify the type of the secret, which will determine
|
|
1067
|
+
the value returned when the secret value is requested. Exactly one must be specified.
|
|
1068
|
+
|
|
1069
|
+
Throws `RESOURCE_DOES_NOT_EXIST` if no such secret scope exists. Throws `RESOURCE_LIMIT_EXCEEDED` if
|
|
1070
|
+
maximum number of secrets in scope is exceeded. Throws `INVALID_PARAMETER_VALUE` if the key name or
|
|
1071
|
+
value length is invalid. Throws `PERMISSION_DENIED` if the user does not have permission to make this
|
|
1072
|
+
API call."""
|
|
1073
|
+
request = kwargs.get('request', None)
|
|
1074
|
+
if not request: # request is not given through keyed args
|
|
1075
|
+
request = PutSecret(bytes_value=bytes_value, key=key, scope=scope, string_value=string_value)
|
|
1076
|
+
body = request.as_dict()
|
|
1077
|
+
self._api.do('POST', '/api/2.0/secrets/put', body=body)
|
|
1078
|
+
|
|
1079
|
+
|
|
185
1080
|
class WorkspaceAPI:
|
|
186
1081
|
"""The Workspace API allows you to list, import, export, and delete notebooks and folders.
|
|
187
1082
|
|
|
@@ -212,9 +1107,9 @@ class WorkspaceAPI:
|
|
|
212
1107
|
direct_download: bool = None,
|
|
213
1108
|
format: ExportFormat = None,
|
|
214
1109
|
**kwargs) -> ExportResponse:
|
|
215
|
-
"""Export a
|
|
1110
|
+
"""Export a workspace object.
|
|
216
1111
|
|
|
217
|
-
Exports
|
|
1112
|
+
Exports an object or the contents of an entire directory.
|
|
218
1113
|
|
|
219
1114
|
If `path` does not exist, this call returns an error `RESOURCE_DOES_NOT_EXIST`.
|
|
220
1115
|
|
|
@@ -222,7 +1117,7 @@ class WorkspaceAPI:
|
|
|
222
1117
|
call returns `MAX_NOTEBOOK_SIZE_EXCEEDED`. Currently, this API does not support exporting a library."""
|
|
223
1118
|
request = kwargs.get('request', None)
|
|
224
1119
|
if not request: # request is not given through keyed args
|
|
225
|
-
request =
|
|
1120
|
+
request = ExportRequest(direct_download=direct_download, format=format, path=path)
|
|
226
1121
|
|
|
227
1122
|
query = {}
|
|
228
1123
|
if direct_download: query['direct_download'] = request.direct_download
|
|
@@ -239,7 +1134,7 @@ class WorkspaceAPI:
|
|
|
239
1134
|
`RESOURCE_DOES_NOT_EXIST`."""
|
|
240
1135
|
request = kwargs.get('request', None)
|
|
241
1136
|
if not request: # request is not given through keyed args
|
|
242
|
-
request =
|
|
1137
|
+
request = GetStatusRequest(path=path)
|
|
243
1138
|
|
|
244
1139
|
query = {}
|
|
245
1140
|
if path: query['path'] = request.path
|
|
@@ -255,11 +1150,11 @@ class WorkspaceAPI:
|
|
|
255
1150
|
language: Language = None,
|
|
256
1151
|
overwrite: bool = None,
|
|
257
1152
|
**kwargs):
|
|
258
|
-
"""Import a
|
|
1153
|
+
"""Import a workspace object.
|
|
259
1154
|
|
|
260
|
-
Imports a notebook or the contents of an entire directory.
|
|
261
|
-
set to `false`, this call returns an error
|
|
262
|
-
import a directory."""
|
|
1155
|
+
Imports a workspace object (for example, a notebook or file) or the contents of an entire directory.
|
|
1156
|
+
If `path` already exists and `overwrite` is set to `false`, this call returns an error
|
|
1157
|
+
`RESOURCE_ALREADY_EXISTS`. One can only use `DBC` format to import a directory."""
|
|
263
1158
|
request = kwargs.get('request', None)
|
|
264
1159
|
if not request: # request is not given through keyed args
|
|
265
1160
|
request = Import(content=content,
|
|
@@ -277,7 +1172,7 @@ class WorkspaceAPI:
|
|
|
277
1172
|
exist, this call returns an error `RESOURCE_DOES_NOT_EXIST`."""
|
|
278
1173
|
request = kwargs.get('request', None)
|
|
279
1174
|
if not request: # request is not given through keyed args
|
|
280
|
-
request =
|
|
1175
|
+
request = ListWorkspaceRequest(notebooks_modified_after=notebooks_modified_after, path=path)
|
|
281
1176
|
|
|
282
1177
|
query = {}
|
|
283
1178
|
if notebooks_modified_after: query['notebooks_modified_after'] = request.notebooks_modified_after
|