databricks-sdk 0.65.0__py3-none-any.whl → 0.66.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 +89 -28
- databricks/sdk/credentials_provider.py +6 -5
- databricks/sdk/mixins/sharing.py +44 -0
- databricks/sdk/service/catalog.py +12 -6
- databricks/sdk/service/compute.py +11 -0
- databricks/sdk/service/dashboards.py +88 -16
- databricks/sdk/service/database.py +24 -38
- databricks/sdk/service/iam.py +2557 -492
- databricks/sdk/service/iamv2.py +643 -0
- databricks/sdk/service/jobs.py +22 -59
- databricks/sdk/service/ml.py +392 -0
- databricks/sdk/service/oauth2.py +3 -3
- databricks/sdk/service/pipelines.py +105 -0
- databricks/sdk/service/settingsv2.py +13 -65
- databricks/sdk/service/sharing.py +13 -1
- databricks/sdk/service/sql.py +15 -3
- databricks/sdk/service/tags.py +25 -6
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/METADATA +1 -1
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/RECORD +24 -22
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/licenses/LICENSE +0 -0
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/licenses/NOTICE +0 -0
- {databricks_sdk-0.65.0.dist-info → databricks_sdk-0.66.0.dist-info}/top_level.txt +0 -0
databricks/sdk/service/iam.py
CHANGED
|
@@ -124,6 +124,244 @@ class AccessControlResponse:
|
|
|
124
124
|
)
|
|
125
125
|
|
|
126
126
|
|
|
127
|
+
@dataclass
|
|
128
|
+
class AccountGroup:
|
|
129
|
+
account_id: Optional[str] = None
|
|
130
|
+
"""Databricks account ID"""
|
|
131
|
+
|
|
132
|
+
display_name: Optional[str] = None
|
|
133
|
+
"""String that represents a human-readable group name"""
|
|
134
|
+
|
|
135
|
+
external_id: Optional[str] = None
|
|
136
|
+
"""external_id should be unique for identifying groups"""
|
|
137
|
+
|
|
138
|
+
id: Optional[str] = None
|
|
139
|
+
"""Databricks group ID"""
|
|
140
|
+
|
|
141
|
+
members: Optional[List[ComplexValue]] = None
|
|
142
|
+
|
|
143
|
+
meta: Optional[ResourceMeta] = None
|
|
144
|
+
"""Container for the group identifier. Workspace local versus account."""
|
|
145
|
+
|
|
146
|
+
roles: Optional[List[ComplexValue]] = None
|
|
147
|
+
"""Indicates if the group has the admin role."""
|
|
148
|
+
|
|
149
|
+
def as_dict(self) -> dict:
|
|
150
|
+
"""Serializes the AccountGroup into a dictionary suitable for use as a JSON request body."""
|
|
151
|
+
body = {}
|
|
152
|
+
if self.account_id is not None:
|
|
153
|
+
body["account_id"] = self.account_id
|
|
154
|
+
if self.display_name is not None:
|
|
155
|
+
body["displayName"] = self.display_name
|
|
156
|
+
if self.external_id is not None:
|
|
157
|
+
body["externalId"] = self.external_id
|
|
158
|
+
if self.id is not None:
|
|
159
|
+
body["id"] = self.id
|
|
160
|
+
if self.members:
|
|
161
|
+
body["members"] = [v.as_dict() for v in self.members]
|
|
162
|
+
if self.meta:
|
|
163
|
+
body["meta"] = self.meta.as_dict()
|
|
164
|
+
if self.roles:
|
|
165
|
+
body["roles"] = [v.as_dict() for v in self.roles]
|
|
166
|
+
return body
|
|
167
|
+
|
|
168
|
+
def as_shallow_dict(self) -> dict:
|
|
169
|
+
"""Serializes the AccountGroup into a shallow dictionary of its immediate attributes."""
|
|
170
|
+
body = {}
|
|
171
|
+
if self.account_id is not None:
|
|
172
|
+
body["account_id"] = self.account_id
|
|
173
|
+
if self.display_name is not None:
|
|
174
|
+
body["displayName"] = self.display_name
|
|
175
|
+
if self.external_id is not None:
|
|
176
|
+
body["externalId"] = self.external_id
|
|
177
|
+
if self.id is not None:
|
|
178
|
+
body["id"] = self.id
|
|
179
|
+
if self.members:
|
|
180
|
+
body["members"] = self.members
|
|
181
|
+
if self.meta:
|
|
182
|
+
body["meta"] = self.meta
|
|
183
|
+
if self.roles:
|
|
184
|
+
body["roles"] = self.roles
|
|
185
|
+
return body
|
|
186
|
+
|
|
187
|
+
@classmethod
|
|
188
|
+
def from_dict(cls, d: Dict[str, Any]) -> AccountGroup:
|
|
189
|
+
"""Deserializes the AccountGroup from a dictionary."""
|
|
190
|
+
return cls(
|
|
191
|
+
account_id=d.get("account_id", None),
|
|
192
|
+
display_name=d.get("displayName", None),
|
|
193
|
+
external_id=d.get("externalId", None),
|
|
194
|
+
id=d.get("id", None),
|
|
195
|
+
members=_repeated_dict(d, "members", ComplexValue),
|
|
196
|
+
meta=_from_dict(d, "meta", ResourceMeta),
|
|
197
|
+
roles=_repeated_dict(d, "roles", ComplexValue),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@dataclass
|
|
202
|
+
class AccountServicePrincipal:
|
|
203
|
+
account_id: Optional[str] = None
|
|
204
|
+
"""Databricks account ID"""
|
|
205
|
+
|
|
206
|
+
active: Optional[bool] = None
|
|
207
|
+
"""If this user is active"""
|
|
208
|
+
|
|
209
|
+
application_id: Optional[str] = None
|
|
210
|
+
"""UUID relating to the service principal"""
|
|
211
|
+
|
|
212
|
+
display_name: Optional[str] = None
|
|
213
|
+
"""String that represents a concatenation of given and family names."""
|
|
214
|
+
|
|
215
|
+
external_id: Optional[str] = None
|
|
216
|
+
|
|
217
|
+
id: Optional[str] = None
|
|
218
|
+
"""Databricks service principal ID."""
|
|
219
|
+
|
|
220
|
+
roles: Optional[List[ComplexValue]] = None
|
|
221
|
+
"""Indicates if the group has the admin role."""
|
|
222
|
+
|
|
223
|
+
def as_dict(self) -> dict:
|
|
224
|
+
"""Serializes the AccountServicePrincipal into a dictionary suitable for use as a JSON request body."""
|
|
225
|
+
body = {}
|
|
226
|
+
if self.account_id is not None:
|
|
227
|
+
body["account_id"] = self.account_id
|
|
228
|
+
if self.active is not None:
|
|
229
|
+
body["active"] = self.active
|
|
230
|
+
if self.application_id is not None:
|
|
231
|
+
body["applicationId"] = self.application_id
|
|
232
|
+
if self.display_name is not None:
|
|
233
|
+
body["displayName"] = self.display_name
|
|
234
|
+
if self.external_id is not None:
|
|
235
|
+
body["externalId"] = self.external_id
|
|
236
|
+
if self.id is not None:
|
|
237
|
+
body["id"] = self.id
|
|
238
|
+
if self.roles:
|
|
239
|
+
body["roles"] = [v.as_dict() for v in self.roles]
|
|
240
|
+
return body
|
|
241
|
+
|
|
242
|
+
def as_shallow_dict(self) -> dict:
|
|
243
|
+
"""Serializes the AccountServicePrincipal into a shallow dictionary of its immediate attributes."""
|
|
244
|
+
body = {}
|
|
245
|
+
if self.account_id is not None:
|
|
246
|
+
body["account_id"] = self.account_id
|
|
247
|
+
if self.active is not None:
|
|
248
|
+
body["active"] = self.active
|
|
249
|
+
if self.application_id is not None:
|
|
250
|
+
body["applicationId"] = self.application_id
|
|
251
|
+
if self.display_name is not None:
|
|
252
|
+
body["displayName"] = self.display_name
|
|
253
|
+
if self.external_id is not None:
|
|
254
|
+
body["externalId"] = self.external_id
|
|
255
|
+
if self.id is not None:
|
|
256
|
+
body["id"] = self.id
|
|
257
|
+
if self.roles:
|
|
258
|
+
body["roles"] = self.roles
|
|
259
|
+
return body
|
|
260
|
+
|
|
261
|
+
@classmethod
|
|
262
|
+
def from_dict(cls, d: Dict[str, Any]) -> AccountServicePrincipal:
|
|
263
|
+
"""Deserializes the AccountServicePrincipal from a dictionary."""
|
|
264
|
+
return cls(
|
|
265
|
+
account_id=d.get("account_id", None),
|
|
266
|
+
active=d.get("active", None),
|
|
267
|
+
application_id=d.get("applicationId", None),
|
|
268
|
+
display_name=d.get("displayName", None),
|
|
269
|
+
external_id=d.get("externalId", None),
|
|
270
|
+
id=d.get("id", None),
|
|
271
|
+
roles=_repeated_dict(d, "roles", ComplexValue),
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@dataclass
|
|
276
|
+
class AccountUser:
|
|
277
|
+
account_id: Optional[str] = None
|
|
278
|
+
"""Databricks account ID"""
|
|
279
|
+
|
|
280
|
+
active: Optional[bool] = None
|
|
281
|
+
"""If this user is active"""
|
|
282
|
+
|
|
283
|
+
display_name: Optional[str] = None
|
|
284
|
+
"""String that represents a concatenation of given and family names. For example `John Smith`."""
|
|
285
|
+
|
|
286
|
+
emails: Optional[List[ComplexValue]] = None
|
|
287
|
+
"""All the emails associated with the Databricks user."""
|
|
288
|
+
|
|
289
|
+
external_id: Optional[str] = None
|
|
290
|
+
"""External ID is not currently supported. It is reserved for future use."""
|
|
291
|
+
|
|
292
|
+
id: Optional[str] = None
|
|
293
|
+
"""Databricks user ID."""
|
|
294
|
+
|
|
295
|
+
name: Optional[Name] = None
|
|
296
|
+
|
|
297
|
+
roles: Optional[List[ComplexValue]] = None
|
|
298
|
+
"""Indicates if the group has the admin role."""
|
|
299
|
+
|
|
300
|
+
user_name: Optional[str] = None
|
|
301
|
+
"""Email address of the Databricks user."""
|
|
302
|
+
|
|
303
|
+
def as_dict(self) -> dict:
|
|
304
|
+
"""Serializes the AccountUser into a dictionary suitable for use as a JSON request body."""
|
|
305
|
+
body = {}
|
|
306
|
+
if self.account_id is not None:
|
|
307
|
+
body["account_id"] = self.account_id
|
|
308
|
+
if self.active is not None:
|
|
309
|
+
body["active"] = self.active
|
|
310
|
+
if self.display_name is not None:
|
|
311
|
+
body["displayName"] = self.display_name
|
|
312
|
+
if self.emails:
|
|
313
|
+
body["emails"] = [v.as_dict() for v in self.emails]
|
|
314
|
+
if self.external_id is not None:
|
|
315
|
+
body["externalId"] = self.external_id
|
|
316
|
+
if self.id is not None:
|
|
317
|
+
body["id"] = self.id
|
|
318
|
+
if self.name:
|
|
319
|
+
body["name"] = self.name.as_dict()
|
|
320
|
+
if self.roles:
|
|
321
|
+
body["roles"] = [v.as_dict() for v in self.roles]
|
|
322
|
+
if self.user_name is not None:
|
|
323
|
+
body["userName"] = self.user_name
|
|
324
|
+
return body
|
|
325
|
+
|
|
326
|
+
def as_shallow_dict(self) -> dict:
|
|
327
|
+
"""Serializes the AccountUser into a shallow dictionary of its immediate attributes."""
|
|
328
|
+
body = {}
|
|
329
|
+
if self.account_id is not None:
|
|
330
|
+
body["account_id"] = self.account_id
|
|
331
|
+
if self.active is not None:
|
|
332
|
+
body["active"] = self.active
|
|
333
|
+
if self.display_name is not None:
|
|
334
|
+
body["displayName"] = self.display_name
|
|
335
|
+
if self.emails:
|
|
336
|
+
body["emails"] = self.emails
|
|
337
|
+
if self.external_id is not None:
|
|
338
|
+
body["externalId"] = self.external_id
|
|
339
|
+
if self.id is not None:
|
|
340
|
+
body["id"] = self.id
|
|
341
|
+
if self.name:
|
|
342
|
+
body["name"] = self.name
|
|
343
|
+
if self.roles:
|
|
344
|
+
body["roles"] = self.roles
|
|
345
|
+
if self.user_name is not None:
|
|
346
|
+
body["userName"] = self.user_name
|
|
347
|
+
return body
|
|
348
|
+
|
|
349
|
+
@classmethod
|
|
350
|
+
def from_dict(cls, d: Dict[str, Any]) -> AccountUser:
|
|
351
|
+
"""Deserializes the AccountUser from a dictionary."""
|
|
352
|
+
return cls(
|
|
353
|
+
account_id=d.get("account_id", None),
|
|
354
|
+
active=d.get("active", None),
|
|
355
|
+
display_name=d.get("displayName", None),
|
|
356
|
+
emails=_repeated_dict(d, "emails", ComplexValue),
|
|
357
|
+
external_id=d.get("externalId", None),
|
|
358
|
+
id=d.get("id", None),
|
|
359
|
+
name=_from_dict(d, "name", Name),
|
|
360
|
+
roles=_repeated_dict(d, "roles", ComplexValue),
|
|
361
|
+
user_name=d.get("userName", None),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
127
365
|
@dataclass
|
|
128
366
|
class Actor:
|
|
129
367
|
"""represents an identity trying to access a resource - user or a service principal group can be a
|
|
@@ -425,6 +663,7 @@ class Group:
|
|
|
425
663
|
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements"""
|
|
426
664
|
|
|
427
665
|
external_id: Optional[str] = None
|
|
666
|
+
"""external_id should be unique for identifying groups"""
|
|
428
667
|
|
|
429
668
|
groups: Optional[List[ComplexValue]] = None
|
|
430
669
|
|
|
@@ -510,16 +749,13 @@ class GroupSchema(Enum):
|
|
|
510
749
|
|
|
511
750
|
|
|
512
751
|
@dataclass
|
|
513
|
-
class
|
|
752
|
+
class ListAccountGroupsResponse:
|
|
514
753
|
items_per_page: Optional[int] = None
|
|
515
754
|
"""Total results returned in the response."""
|
|
516
755
|
|
|
517
|
-
resources: Optional[List[
|
|
756
|
+
resources: Optional[List[AccountGroup]] = None
|
|
518
757
|
"""User objects returned in the response."""
|
|
519
758
|
|
|
520
|
-
schemas: Optional[List[ListResponseSchema]] = None
|
|
521
|
-
"""The schema of the service principal."""
|
|
522
|
-
|
|
523
759
|
start_index: Optional[int] = None
|
|
524
760
|
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
525
761
|
|
|
@@ -527,14 +763,12 @@ class ListGroupsResponse:
|
|
|
527
763
|
"""Total results that match the request filters."""
|
|
528
764
|
|
|
529
765
|
def as_dict(self) -> dict:
|
|
530
|
-
"""Serializes the
|
|
766
|
+
"""Serializes the ListAccountGroupsResponse into a dictionary suitable for use as a JSON request body."""
|
|
531
767
|
body = {}
|
|
532
768
|
if self.items_per_page is not None:
|
|
533
769
|
body["itemsPerPage"] = self.items_per_page
|
|
534
770
|
if self.resources:
|
|
535
771
|
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
536
|
-
if self.schemas:
|
|
537
|
-
body["schemas"] = [v.value for v in self.schemas]
|
|
538
772
|
if self.start_index is not None:
|
|
539
773
|
body["startIndex"] = self.start_index
|
|
540
774
|
if self.total_results is not None:
|
|
@@ -542,14 +776,12 @@ class ListGroupsResponse:
|
|
|
542
776
|
return body
|
|
543
777
|
|
|
544
778
|
def as_shallow_dict(self) -> dict:
|
|
545
|
-
"""Serializes the
|
|
779
|
+
"""Serializes the ListAccountGroupsResponse into a shallow dictionary of its immediate attributes."""
|
|
546
780
|
body = {}
|
|
547
781
|
if self.items_per_page is not None:
|
|
548
782
|
body["itemsPerPage"] = self.items_per_page
|
|
549
783
|
if self.resources:
|
|
550
784
|
body["Resources"] = self.resources
|
|
551
|
-
if self.schemas:
|
|
552
|
-
body["schemas"] = self.schemas
|
|
553
785
|
if self.start_index is not None:
|
|
554
786
|
body["startIndex"] = self.start_index
|
|
555
787
|
if self.total_results is not None:
|
|
@@ -557,33 +789,24 @@ class ListGroupsResponse:
|
|
|
557
789
|
return body
|
|
558
790
|
|
|
559
791
|
@classmethod
|
|
560
|
-
def from_dict(cls, d: Dict[str, Any]) ->
|
|
561
|
-
"""Deserializes the
|
|
792
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListAccountGroupsResponse:
|
|
793
|
+
"""Deserializes the ListAccountGroupsResponse from a dictionary."""
|
|
562
794
|
return cls(
|
|
563
795
|
items_per_page=d.get("itemsPerPage", None),
|
|
564
|
-
resources=_repeated_dict(d, "Resources",
|
|
565
|
-
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
796
|
+
resources=_repeated_dict(d, "Resources", AccountGroup),
|
|
566
797
|
start_index=d.get("startIndex", None),
|
|
567
798
|
total_results=d.get("totalResults", None),
|
|
568
799
|
)
|
|
569
800
|
|
|
570
801
|
|
|
571
|
-
class ListResponseSchema(Enum):
|
|
572
|
-
|
|
573
|
-
URN_IETF_PARAMS_SCIM_API_MESSAGES_2_0_LIST_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:ListResponse"
|
|
574
|
-
|
|
575
|
-
|
|
576
802
|
@dataclass
|
|
577
|
-
class
|
|
803
|
+
class ListAccountServicePrincipalsResponse:
|
|
578
804
|
items_per_page: Optional[int] = None
|
|
579
805
|
"""Total results returned in the response."""
|
|
580
806
|
|
|
581
|
-
resources: Optional[List[
|
|
807
|
+
resources: Optional[List[AccountServicePrincipal]] = None
|
|
582
808
|
"""User objects returned in the response."""
|
|
583
809
|
|
|
584
|
-
schemas: Optional[List[ListResponseSchema]] = None
|
|
585
|
-
"""The schema of the List response."""
|
|
586
|
-
|
|
587
810
|
start_index: Optional[int] = None
|
|
588
811
|
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
589
812
|
|
|
@@ -591,14 +814,12 @@ class ListServicePrincipalResponse:
|
|
|
591
814
|
"""Total results that match the request filters."""
|
|
592
815
|
|
|
593
816
|
def as_dict(self) -> dict:
|
|
594
|
-
"""Serializes the
|
|
817
|
+
"""Serializes the ListAccountServicePrincipalsResponse into a dictionary suitable for use as a JSON request body."""
|
|
595
818
|
body = {}
|
|
596
819
|
if self.items_per_page is not None:
|
|
597
820
|
body["itemsPerPage"] = self.items_per_page
|
|
598
821
|
if self.resources:
|
|
599
822
|
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
600
|
-
if self.schemas:
|
|
601
|
-
body["schemas"] = [v.value for v in self.schemas]
|
|
602
823
|
if self.start_index is not None:
|
|
603
824
|
body["startIndex"] = self.start_index
|
|
604
825
|
if self.total_results is not None:
|
|
@@ -606,14 +827,12 @@ class ListServicePrincipalResponse:
|
|
|
606
827
|
return body
|
|
607
828
|
|
|
608
829
|
def as_shallow_dict(self) -> dict:
|
|
609
|
-
"""Serializes the
|
|
830
|
+
"""Serializes the ListAccountServicePrincipalsResponse into a shallow dictionary of its immediate attributes."""
|
|
610
831
|
body = {}
|
|
611
832
|
if self.items_per_page is not None:
|
|
612
833
|
body["itemsPerPage"] = self.items_per_page
|
|
613
834
|
if self.resources:
|
|
614
835
|
body["Resources"] = self.resources
|
|
615
|
-
if self.schemas:
|
|
616
|
-
body["schemas"] = self.schemas
|
|
617
836
|
if self.start_index is not None:
|
|
618
837
|
body["startIndex"] = self.start_index
|
|
619
838
|
if self.total_results is not None:
|
|
@@ -621,34 +840,24 @@ class ListServicePrincipalResponse:
|
|
|
621
840
|
return body
|
|
622
841
|
|
|
623
842
|
@classmethod
|
|
624
|
-
def from_dict(cls, d: Dict[str, Any]) ->
|
|
625
|
-
"""Deserializes the
|
|
843
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListAccountServicePrincipalsResponse:
|
|
844
|
+
"""Deserializes the ListAccountServicePrincipalsResponse from a dictionary."""
|
|
626
845
|
return cls(
|
|
627
846
|
items_per_page=d.get("itemsPerPage", None),
|
|
628
|
-
resources=_repeated_dict(d, "Resources",
|
|
629
|
-
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
847
|
+
resources=_repeated_dict(d, "Resources", AccountServicePrincipal),
|
|
630
848
|
start_index=d.get("startIndex", None),
|
|
631
849
|
total_results=d.get("totalResults", None),
|
|
632
850
|
)
|
|
633
851
|
|
|
634
852
|
|
|
635
|
-
class ListSortOrder(Enum):
|
|
636
|
-
|
|
637
|
-
ASCENDING = "ascending"
|
|
638
|
-
DESCENDING = "descending"
|
|
639
|
-
|
|
640
|
-
|
|
641
853
|
@dataclass
|
|
642
|
-
class
|
|
854
|
+
class ListAccountUsersResponse:
|
|
643
855
|
items_per_page: Optional[int] = None
|
|
644
856
|
"""Total results returned in the response."""
|
|
645
857
|
|
|
646
|
-
resources: Optional[List[
|
|
858
|
+
resources: Optional[List[AccountUser]] = None
|
|
647
859
|
"""User objects returned in the response."""
|
|
648
860
|
|
|
649
|
-
schemas: Optional[List[ListResponseSchema]] = None
|
|
650
|
-
"""The schema of the List response."""
|
|
651
|
-
|
|
652
861
|
start_index: Optional[int] = None
|
|
653
862
|
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
654
863
|
|
|
@@ -656,14 +865,12 @@ class ListUsersResponse:
|
|
|
656
865
|
"""Total results that match the request filters."""
|
|
657
866
|
|
|
658
867
|
def as_dict(self) -> dict:
|
|
659
|
-
"""Serializes the
|
|
868
|
+
"""Serializes the ListAccountUsersResponse into a dictionary suitable for use as a JSON request body."""
|
|
660
869
|
body = {}
|
|
661
870
|
if self.items_per_page is not None:
|
|
662
871
|
body["itemsPerPage"] = self.items_per_page
|
|
663
872
|
if self.resources:
|
|
664
873
|
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
665
|
-
if self.schemas:
|
|
666
|
-
body["schemas"] = [v.value for v in self.schemas]
|
|
667
874
|
if self.start_index is not None:
|
|
668
875
|
body["startIndex"] = self.start_index
|
|
669
876
|
if self.total_results is not None:
|
|
@@ -671,14 +878,12 @@ class ListUsersResponse:
|
|
|
671
878
|
return body
|
|
672
879
|
|
|
673
880
|
def as_shallow_dict(self) -> dict:
|
|
674
|
-
"""Serializes the
|
|
881
|
+
"""Serializes the ListAccountUsersResponse into a shallow dictionary of its immediate attributes."""
|
|
675
882
|
body = {}
|
|
676
883
|
if self.items_per_page is not None:
|
|
677
884
|
body["itemsPerPage"] = self.items_per_page
|
|
678
885
|
if self.resources:
|
|
679
886
|
body["Resources"] = self.resources
|
|
680
|
-
if self.schemas:
|
|
681
|
-
body["schemas"] = self.schemas
|
|
682
887
|
if self.start_index is not None:
|
|
683
888
|
body["startIndex"] = self.start_index
|
|
684
889
|
if self.total_results is not None:
|
|
@@ -686,21 +891,208 @@ class ListUsersResponse:
|
|
|
686
891
|
return body
|
|
687
892
|
|
|
688
893
|
@classmethod
|
|
689
|
-
def from_dict(cls, d: Dict[str, Any]) ->
|
|
690
|
-
"""Deserializes the
|
|
894
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListAccountUsersResponse:
|
|
895
|
+
"""Deserializes the ListAccountUsersResponse from a dictionary."""
|
|
691
896
|
return cls(
|
|
692
897
|
items_per_page=d.get("itemsPerPage", None),
|
|
693
|
-
resources=_repeated_dict(d, "Resources",
|
|
694
|
-
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
898
|
+
resources=_repeated_dict(d, "Resources", AccountUser),
|
|
695
899
|
start_index=d.get("startIndex", None),
|
|
696
900
|
total_results=d.get("totalResults", None),
|
|
697
901
|
)
|
|
698
902
|
|
|
699
903
|
|
|
700
904
|
@dataclass
|
|
701
|
-
class
|
|
702
|
-
|
|
703
|
-
"""
|
|
905
|
+
class ListGroupsResponse:
|
|
906
|
+
items_per_page: Optional[int] = None
|
|
907
|
+
"""Total results returned in the response."""
|
|
908
|
+
|
|
909
|
+
resources: Optional[List[Group]] = None
|
|
910
|
+
"""User objects returned in the response."""
|
|
911
|
+
|
|
912
|
+
schemas: Optional[List[ListResponseSchema]] = None
|
|
913
|
+
"""The schema of the service principal."""
|
|
914
|
+
|
|
915
|
+
start_index: Optional[int] = None
|
|
916
|
+
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
917
|
+
|
|
918
|
+
total_results: Optional[int] = None
|
|
919
|
+
"""Total results that match the request filters."""
|
|
920
|
+
|
|
921
|
+
def as_dict(self) -> dict:
|
|
922
|
+
"""Serializes the ListGroupsResponse into a dictionary suitable for use as a JSON request body."""
|
|
923
|
+
body = {}
|
|
924
|
+
if self.items_per_page is not None:
|
|
925
|
+
body["itemsPerPage"] = self.items_per_page
|
|
926
|
+
if self.resources:
|
|
927
|
+
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
928
|
+
if self.schemas:
|
|
929
|
+
body["schemas"] = [v.value for v in self.schemas]
|
|
930
|
+
if self.start_index is not None:
|
|
931
|
+
body["startIndex"] = self.start_index
|
|
932
|
+
if self.total_results is not None:
|
|
933
|
+
body["totalResults"] = self.total_results
|
|
934
|
+
return body
|
|
935
|
+
|
|
936
|
+
def as_shallow_dict(self) -> dict:
|
|
937
|
+
"""Serializes the ListGroupsResponse into a shallow dictionary of its immediate attributes."""
|
|
938
|
+
body = {}
|
|
939
|
+
if self.items_per_page is not None:
|
|
940
|
+
body["itemsPerPage"] = self.items_per_page
|
|
941
|
+
if self.resources:
|
|
942
|
+
body["Resources"] = self.resources
|
|
943
|
+
if self.schemas:
|
|
944
|
+
body["schemas"] = self.schemas
|
|
945
|
+
if self.start_index is not None:
|
|
946
|
+
body["startIndex"] = self.start_index
|
|
947
|
+
if self.total_results is not None:
|
|
948
|
+
body["totalResults"] = self.total_results
|
|
949
|
+
return body
|
|
950
|
+
|
|
951
|
+
@classmethod
|
|
952
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListGroupsResponse:
|
|
953
|
+
"""Deserializes the ListGroupsResponse from a dictionary."""
|
|
954
|
+
return cls(
|
|
955
|
+
items_per_page=d.get("itemsPerPage", None),
|
|
956
|
+
resources=_repeated_dict(d, "Resources", Group),
|
|
957
|
+
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
958
|
+
start_index=d.get("startIndex", None),
|
|
959
|
+
total_results=d.get("totalResults", None),
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
class ListResponseSchema(Enum):
|
|
964
|
+
|
|
965
|
+
URN_IETF_PARAMS_SCIM_API_MESSAGES_2_0_LIST_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:ListResponse"
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
@dataclass
|
|
969
|
+
class ListServicePrincipalResponse:
|
|
970
|
+
items_per_page: Optional[int] = None
|
|
971
|
+
"""Total results returned in the response."""
|
|
972
|
+
|
|
973
|
+
resources: Optional[List[ServicePrincipal]] = None
|
|
974
|
+
"""User objects returned in the response."""
|
|
975
|
+
|
|
976
|
+
schemas: Optional[List[ListResponseSchema]] = None
|
|
977
|
+
"""The schema of the List response."""
|
|
978
|
+
|
|
979
|
+
start_index: Optional[int] = None
|
|
980
|
+
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
981
|
+
|
|
982
|
+
total_results: Optional[int] = None
|
|
983
|
+
"""Total results that match the request filters."""
|
|
984
|
+
|
|
985
|
+
def as_dict(self) -> dict:
|
|
986
|
+
"""Serializes the ListServicePrincipalResponse into a dictionary suitable for use as a JSON request body."""
|
|
987
|
+
body = {}
|
|
988
|
+
if self.items_per_page is not None:
|
|
989
|
+
body["itemsPerPage"] = self.items_per_page
|
|
990
|
+
if self.resources:
|
|
991
|
+
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
992
|
+
if self.schemas:
|
|
993
|
+
body["schemas"] = [v.value for v in self.schemas]
|
|
994
|
+
if self.start_index is not None:
|
|
995
|
+
body["startIndex"] = self.start_index
|
|
996
|
+
if self.total_results is not None:
|
|
997
|
+
body["totalResults"] = self.total_results
|
|
998
|
+
return body
|
|
999
|
+
|
|
1000
|
+
def as_shallow_dict(self) -> dict:
|
|
1001
|
+
"""Serializes the ListServicePrincipalResponse into a shallow dictionary of its immediate attributes."""
|
|
1002
|
+
body = {}
|
|
1003
|
+
if self.items_per_page is not None:
|
|
1004
|
+
body["itemsPerPage"] = self.items_per_page
|
|
1005
|
+
if self.resources:
|
|
1006
|
+
body["Resources"] = self.resources
|
|
1007
|
+
if self.schemas:
|
|
1008
|
+
body["schemas"] = self.schemas
|
|
1009
|
+
if self.start_index is not None:
|
|
1010
|
+
body["startIndex"] = self.start_index
|
|
1011
|
+
if self.total_results is not None:
|
|
1012
|
+
body["totalResults"] = self.total_results
|
|
1013
|
+
return body
|
|
1014
|
+
|
|
1015
|
+
@classmethod
|
|
1016
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListServicePrincipalResponse:
|
|
1017
|
+
"""Deserializes the ListServicePrincipalResponse from a dictionary."""
|
|
1018
|
+
return cls(
|
|
1019
|
+
items_per_page=d.get("itemsPerPage", None),
|
|
1020
|
+
resources=_repeated_dict(d, "Resources", ServicePrincipal),
|
|
1021
|
+
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
1022
|
+
start_index=d.get("startIndex", None),
|
|
1023
|
+
total_results=d.get("totalResults", None),
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
class ListSortOrder(Enum):
|
|
1028
|
+
|
|
1029
|
+
ASCENDING = "ascending"
|
|
1030
|
+
DESCENDING = "descending"
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
@dataclass
|
|
1034
|
+
class ListUsersResponse:
|
|
1035
|
+
items_per_page: Optional[int] = None
|
|
1036
|
+
"""Total results returned in the response."""
|
|
1037
|
+
|
|
1038
|
+
resources: Optional[List[User]] = None
|
|
1039
|
+
"""User objects returned in the response."""
|
|
1040
|
+
|
|
1041
|
+
schemas: Optional[List[ListResponseSchema]] = None
|
|
1042
|
+
"""The schema of the List response."""
|
|
1043
|
+
|
|
1044
|
+
start_index: Optional[int] = None
|
|
1045
|
+
"""Starting index of all the results that matched the request filters. First item is number 1."""
|
|
1046
|
+
|
|
1047
|
+
total_results: Optional[int] = None
|
|
1048
|
+
"""Total results that match the request filters."""
|
|
1049
|
+
|
|
1050
|
+
def as_dict(self) -> dict:
|
|
1051
|
+
"""Serializes the ListUsersResponse into a dictionary suitable for use as a JSON request body."""
|
|
1052
|
+
body = {}
|
|
1053
|
+
if self.items_per_page is not None:
|
|
1054
|
+
body["itemsPerPage"] = self.items_per_page
|
|
1055
|
+
if self.resources:
|
|
1056
|
+
body["Resources"] = [v.as_dict() for v in self.resources]
|
|
1057
|
+
if self.schemas:
|
|
1058
|
+
body["schemas"] = [v.value for v in self.schemas]
|
|
1059
|
+
if self.start_index is not None:
|
|
1060
|
+
body["startIndex"] = self.start_index
|
|
1061
|
+
if self.total_results is not None:
|
|
1062
|
+
body["totalResults"] = self.total_results
|
|
1063
|
+
return body
|
|
1064
|
+
|
|
1065
|
+
def as_shallow_dict(self) -> dict:
|
|
1066
|
+
"""Serializes the ListUsersResponse into a shallow dictionary of its immediate attributes."""
|
|
1067
|
+
body = {}
|
|
1068
|
+
if self.items_per_page is not None:
|
|
1069
|
+
body["itemsPerPage"] = self.items_per_page
|
|
1070
|
+
if self.resources:
|
|
1071
|
+
body["Resources"] = self.resources
|
|
1072
|
+
if self.schemas:
|
|
1073
|
+
body["schemas"] = self.schemas
|
|
1074
|
+
if self.start_index is not None:
|
|
1075
|
+
body["startIndex"] = self.start_index
|
|
1076
|
+
if self.total_results is not None:
|
|
1077
|
+
body["totalResults"] = self.total_results
|
|
1078
|
+
return body
|
|
1079
|
+
|
|
1080
|
+
@classmethod
|
|
1081
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListUsersResponse:
|
|
1082
|
+
"""Deserializes the ListUsersResponse from a dictionary."""
|
|
1083
|
+
return cls(
|
|
1084
|
+
items_per_page=d.get("itemsPerPage", None),
|
|
1085
|
+
resources=_repeated_dict(d, "Resources", User),
|
|
1086
|
+
schemas=_repeated_enum(d, "schemas", ListResponseSchema),
|
|
1087
|
+
start_index=d.get("startIndex", None),
|
|
1088
|
+
total_results=d.get("totalResults", None),
|
|
1089
|
+
)
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
@dataclass
|
|
1093
|
+
class MigratePermissionsResponse:
|
|
1094
|
+
permissions_migrated: Optional[int] = None
|
|
1095
|
+
"""Number of permissions migrated."""
|
|
704
1096
|
|
|
705
1097
|
def as_dict(self) -> dict:
|
|
706
1098
|
"""Serializes the MigratePermissionsResponse into a dictionary suitable for use as a JSON request body."""
|
|
@@ -1647,24 +2039,6 @@ class ServicePrincipalSchema(Enum):
|
|
|
1647
2039
|
URN_IETF_PARAMS_SCIM_SCHEMAS_CORE_2_0_SERVICE_PRINCIPAL = "urn:ietf:params:scim:schemas:core:2.0:ServicePrincipal"
|
|
1648
2040
|
|
|
1649
2041
|
|
|
1650
|
-
@dataclass
|
|
1651
|
-
class UpdateResponse:
|
|
1652
|
-
def as_dict(self) -> dict:
|
|
1653
|
-
"""Serializes the UpdateResponse into a dictionary suitable for use as a JSON request body."""
|
|
1654
|
-
body = {}
|
|
1655
|
-
return body
|
|
1656
|
-
|
|
1657
|
-
def as_shallow_dict(self) -> dict:
|
|
1658
|
-
"""Serializes the UpdateResponse into a shallow dictionary of its immediate attributes."""
|
|
1659
|
-
body = {}
|
|
1660
|
-
return body
|
|
1661
|
-
|
|
1662
|
-
@classmethod
|
|
1663
|
-
def from_dict(cls, d: Dict[str, Any]) -> UpdateResponse:
|
|
1664
|
-
"""Deserializes the UpdateResponse from a dictionary."""
|
|
1665
|
-
return cls()
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
2042
|
@dataclass
|
|
1669
2043
|
class User:
|
|
1670
2044
|
active: Optional[bool] = None
|
|
@@ -1886,7 +2260,8 @@ class AccountAccessControlAPI:
|
|
|
1886
2260
|
Examples | Summary :--- | :--- `resource=accounts/<ACCOUNT_ID>` | A resource name for the account.
|
|
1887
2261
|
`resource=accounts/<ACCOUNT_ID>/groups/<GROUP_ID>` | A resource name for the group.
|
|
1888
2262
|
`resource=accounts/<ACCOUNT_ID>/servicePrincipals/<SP_ID>` | A resource name for the service
|
|
1889
|
-
principal.
|
|
2263
|
+
principal. `resource=accounts/<ACCOUNT_ID>/tagPolicies/<TAG_POLICY_ID>` | A resource name for the
|
|
2264
|
+
tag policy.
|
|
1890
2265
|
|
|
1891
2266
|
:returns: :class:`GetAssignableRolesForResourceResponse`
|
|
1892
2267
|
"""
|
|
@@ -1918,6 +2293,8 @@ class AccountAccessControlAPI:
|
|
|
1918
2293
|
set on the group.
|
|
1919
2294
|
`name=accounts/<ACCOUNT_ID>/servicePrincipals/<SERVICE_PRINCIPAL_APPLICATION_ID>/ruleSets/default` |
|
|
1920
2295
|
A name for a rule set on the service principal.
|
|
2296
|
+
`name=accounts/<ACCOUNT_ID>/tagPolicies/<TAG_POLICY_ID>/ruleSets/default` | A name for a rule set on
|
|
2297
|
+
the tag policy.
|
|
1921
2298
|
:param etag: str
|
|
1922
2299
|
Etag used for versioning. The response is at least as fresh as the eTag provided. Etag is used for
|
|
1923
2300
|
optimistic concurrency control as a way to help prevent simultaneous updates of a rule set from
|
|
@@ -1997,7 +2374,8 @@ class AccountAccessControlProxyAPI:
|
|
|
1997
2374
|
Examples | Summary :--- | :--- `resource=accounts/<ACCOUNT_ID>` | A resource name for the account.
|
|
1998
2375
|
`resource=accounts/<ACCOUNT_ID>/groups/<GROUP_ID>` | A resource name for the group.
|
|
1999
2376
|
`resource=accounts/<ACCOUNT_ID>/servicePrincipals/<SP_ID>` | A resource name for the service
|
|
2000
|
-
principal.
|
|
2377
|
+
principal. `resource=accounts/<ACCOUNT_ID>/tagPolicies/<TAG_POLICY_ID>` | A resource name for the
|
|
2378
|
+
tag policy.
|
|
2001
2379
|
|
|
2002
2380
|
:returns: :class:`GetAssignableRolesForResourceResponse`
|
|
2003
2381
|
"""
|
|
@@ -2026,6 +2404,8 @@ class AccountAccessControlProxyAPI:
|
|
|
2026
2404
|
set on the group.
|
|
2027
2405
|
`name=accounts/<ACCOUNT_ID>/servicePrincipals/<SERVICE_PRINCIPAL_APPLICATION_ID>/ruleSets/default` |
|
|
2028
2406
|
A name for a rule set on the service principal.
|
|
2407
|
+
`name=accounts/<ACCOUNT_ID>/tagPolicies/<TAG_POLICY_ID>/ruleSets/default` | A name for a rule set on
|
|
2408
|
+
the tag policy.
|
|
2029
2409
|
:param etag: str
|
|
2030
2410
|
Etag used for versioning. The response is at least as fresh as the eTag provided. Etag is used for
|
|
2031
2411
|
optimistic concurrency control as a way to help prevent simultaneous updates of a rule set from
|
|
@@ -2077,6 +2457,2006 @@ class AccountAccessControlProxyAPI:
|
|
|
2077
2457
|
return RuleSetResponse.from_dict(res)
|
|
2078
2458
|
|
|
2079
2459
|
|
|
2460
|
+
class AccountGroupsV2API:
|
|
2461
|
+
"""Groups simplify identity management, making it easier to assign access to Databricks account, data, and
|
|
2462
|
+
other securable objects.
|
|
2463
|
+
|
|
2464
|
+
It is best practice to assign access to workspaces and access-control policies in Unity Catalog to groups,
|
|
2465
|
+
instead of to users individually. All Databricks account identities can be assigned as members of groups,
|
|
2466
|
+
and members inherit permissions that are assigned to their group."""
|
|
2467
|
+
|
|
2468
|
+
def __init__(self, api_client):
|
|
2469
|
+
self._api = api_client
|
|
2470
|
+
|
|
2471
|
+
def create(
|
|
2472
|
+
self,
|
|
2473
|
+
*,
|
|
2474
|
+
display_name: Optional[str] = None,
|
|
2475
|
+
external_id: Optional[str] = None,
|
|
2476
|
+
id: Optional[str] = None,
|
|
2477
|
+
members: Optional[List[ComplexValue]] = None,
|
|
2478
|
+
meta: Optional[ResourceMeta] = None,
|
|
2479
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
2480
|
+
) -> AccountGroup:
|
|
2481
|
+
"""Creates a group in the Databricks account with a unique name, using the supplied group details.
|
|
2482
|
+
|
|
2483
|
+
:param display_name: str (optional)
|
|
2484
|
+
String that represents a human-readable group name
|
|
2485
|
+
:param external_id: str (optional)
|
|
2486
|
+
:param id: str (optional)
|
|
2487
|
+
Databricks group ID
|
|
2488
|
+
:param members: List[:class:`ComplexValue`] (optional)
|
|
2489
|
+
:param meta: :class:`ResourceMeta` (optional)
|
|
2490
|
+
Container for the group identifier. Workspace local versus account.
|
|
2491
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
2492
|
+
Indicates if the group has the admin role.
|
|
2493
|
+
|
|
2494
|
+
:returns: :class:`AccountGroup`
|
|
2495
|
+
"""
|
|
2496
|
+
body = {}
|
|
2497
|
+
if display_name is not None:
|
|
2498
|
+
body["displayName"] = display_name
|
|
2499
|
+
if external_id is not None:
|
|
2500
|
+
body["externalId"] = external_id
|
|
2501
|
+
if id is not None:
|
|
2502
|
+
body["id"] = id
|
|
2503
|
+
if members is not None:
|
|
2504
|
+
body["members"] = [v.as_dict() for v in members]
|
|
2505
|
+
if meta is not None:
|
|
2506
|
+
body["meta"] = meta.as_dict()
|
|
2507
|
+
if roles is not None:
|
|
2508
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
2509
|
+
headers = {
|
|
2510
|
+
"Accept": "application/json",
|
|
2511
|
+
"Content-Type": "application/json",
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
res = self._api.do(
|
|
2515
|
+
"POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups", body=body, headers=headers
|
|
2516
|
+
)
|
|
2517
|
+
return AccountGroup.from_dict(res)
|
|
2518
|
+
|
|
2519
|
+
def delete(self, id: str):
|
|
2520
|
+
"""Deletes a group from the Databricks account.
|
|
2521
|
+
|
|
2522
|
+
:param id: str
|
|
2523
|
+
Unique ID for a group in the Databricks account.
|
|
2524
|
+
|
|
2525
|
+
|
|
2526
|
+
"""
|
|
2527
|
+
|
|
2528
|
+
headers = {}
|
|
2529
|
+
|
|
2530
|
+
self._api.do("DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", headers=headers)
|
|
2531
|
+
|
|
2532
|
+
def get(self, id: str) -> AccountGroup:
|
|
2533
|
+
"""Gets the information for a specific group in the Databricks account.
|
|
2534
|
+
|
|
2535
|
+
:param id: str
|
|
2536
|
+
Unique ID for a group in the Databricks account.
|
|
2537
|
+
|
|
2538
|
+
:returns: :class:`AccountGroup`
|
|
2539
|
+
"""
|
|
2540
|
+
|
|
2541
|
+
headers = {
|
|
2542
|
+
"Accept": "application/json",
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
res = self._api.do("GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", headers=headers)
|
|
2546
|
+
return AccountGroup.from_dict(res)
|
|
2547
|
+
|
|
2548
|
+
def list(
|
|
2549
|
+
self,
|
|
2550
|
+
*,
|
|
2551
|
+
attributes: Optional[str] = None,
|
|
2552
|
+
count: Optional[int] = None,
|
|
2553
|
+
excluded_attributes: Optional[str] = None,
|
|
2554
|
+
filter: Optional[str] = None,
|
|
2555
|
+
sort_by: Optional[str] = None,
|
|
2556
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
2557
|
+
start_index: Optional[int] = None,
|
|
2558
|
+
) -> Iterator[AccountGroup]:
|
|
2559
|
+
"""Gets all details of the groups associated with the Databricks account. As of 08/22/2025, this endpoint
|
|
2560
|
+
will not return members. Instead, members should be retrieved by iterating through `Get group
|
|
2561
|
+
details`.
|
|
2562
|
+
|
|
2563
|
+
:param attributes: str (optional)
|
|
2564
|
+
Comma-separated list of attributes to return in response.
|
|
2565
|
+
:param count: int (optional)
|
|
2566
|
+
Desired number of results per page. Default is 10000.
|
|
2567
|
+
:param excluded_attributes: str (optional)
|
|
2568
|
+
Comma-separated list of attributes to exclude in response.
|
|
2569
|
+
:param filter: str (optional)
|
|
2570
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
2571
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
2572
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
2573
|
+
only support simple expressions.
|
|
2574
|
+
|
|
2575
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
2576
|
+
:param sort_by: str (optional)
|
|
2577
|
+
Attribute to sort the results.
|
|
2578
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
2579
|
+
The order to sort the results.
|
|
2580
|
+
:param start_index: int (optional)
|
|
2581
|
+
Specifies the index of the first result. First item is number 1.
|
|
2582
|
+
|
|
2583
|
+
:returns: Iterator over :class:`AccountGroup`
|
|
2584
|
+
"""
|
|
2585
|
+
|
|
2586
|
+
query = {}
|
|
2587
|
+
if attributes is not None:
|
|
2588
|
+
query["attributes"] = attributes
|
|
2589
|
+
if count is not None:
|
|
2590
|
+
query["count"] = count
|
|
2591
|
+
if excluded_attributes is not None:
|
|
2592
|
+
query["excludedAttributes"] = excluded_attributes
|
|
2593
|
+
if filter is not None:
|
|
2594
|
+
query["filter"] = filter
|
|
2595
|
+
if sort_by is not None:
|
|
2596
|
+
query["sortBy"] = sort_by
|
|
2597
|
+
if sort_order is not None:
|
|
2598
|
+
query["sortOrder"] = sort_order.value
|
|
2599
|
+
if start_index is not None:
|
|
2600
|
+
query["startIndex"] = start_index
|
|
2601
|
+
headers = {
|
|
2602
|
+
"Accept": "application/json",
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
query["startIndex"] = 1
|
|
2606
|
+
if "count" not in query:
|
|
2607
|
+
query["count"] = 10000
|
|
2608
|
+
while True:
|
|
2609
|
+
json = self._api.do(
|
|
2610
|
+
"GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups", query=query, headers=headers
|
|
2611
|
+
)
|
|
2612
|
+
if "Resources" in json:
|
|
2613
|
+
for v in json["Resources"]:
|
|
2614
|
+
yield AccountGroup.from_dict(v)
|
|
2615
|
+
if "Resources" not in json or not json["Resources"]:
|
|
2616
|
+
return
|
|
2617
|
+
query["startIndex"] += len(json["Resources"])
|
|
2618
|
+
|
|
2619
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
2620
|
+
"""Partially updates the details of a group.
|
|
2621
|
+
|
|
2622
|
+
:param id: str
|
|
2623
|
+
Unique ID in the Databricks workspace.
|
|
2624
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
2625
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
2626
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
2627
|
+
|
|
2628
|
+
|
|
2629
|
+
"""
|
|
2630
|
+
body = {}
|
|
2631
|
+
if operations is not None:
|
|
2632
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
2633
|
+
if schemas is not None:
|
|
2634
|
+
body["schemas"] = [v.value for v in schemas]
|
|
2635
|
+
headers = {
|
|
2636
|
+
"Content-Type": "application/json",
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
self._api.do(
|
|
2640
|
+
"PATCH", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", body=body, headers=headers
|
|
2641
|
+
)
|
|
2642
|
+
|
|
2643
|
+
def update(
|
|
2644
|
+
self,
|
|
2645
|
+
id: str,
|
|
2646
|
+
*,
|
|
2647
|
+
display_name: Optional[str] = None,
|
|
2648
|
+
external_id: Optional[str] = None,
|
|
2649
|
+
members: Optional[List[ComplexValue]] = None,
|
|
2650
|
+
meta: Optional[ResourceMeta] = None,
|
|
2651
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
2652
|
+
):
|
|
2653
|
+
"""Updates the details of a group by replacing the entire group entity.
|
|
2654
|
+
|
|
2655
|
+
:param id: str
|
|
2656
|
+
Databricks group ID
|
|
2657
|
+
:param display_name: str (optional)
|
|
2658
|
+
String that represents a human-readable group name
|
|
2659
|
+
:param external_id: str (optional)
|
|
2660
|
+
:param members: List[:class:`ComplexValue`] (optional)
|
|
2661
|
+
:param meta: :class:`ResourceMeta` (optional)
|
|
2662
|
+
Container for the group identifier. Workspace local versus account.
|
|
2663
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
2664
|
+
Indicates if the group has the admin role.
|
|
2665
|
+
|
|
2666
|
+
|
|
2667
|
+
"""
|
|
2668
|
+
body = {}
|
|
2669
|
+
if display_name is not None:
|
|
2670
|
+
body["displayName"] = display_name
|
|
2671
|
+
if external_id is not None:
|
|
2672
|
+
body["externalId"] = external_id
|
|
2673
|
+
if members is not None:
|
|
2674
|
+
body["members"] = [v.as_dict() for v in members]
|
|
2675
|
+
if meta is not None:
|
|
2676
|
+
body["meta"] = meta.as_dict()
|
|
2677
|
+
if roles is not None:
|
|
2678
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
2679
|
+
headers = {
|
|
2680
|
+
"Accept": "application/json",
|
|
2681
|
+
"Content-Type": "application/json",
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
2685
|
+
|
|
2686
|
+
|
|
2687
|
+
class AccountServicePrincipalsV2API:
|
|
2688
|
+
"""Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.
|
|
2689
|
+
Databricks recommends creating service principals to run production jobs or modify production data. If all
|
|
2690
|
+
processes that act on production data run with service principals, interactive users do not need any
|
|
2691
|
+
write, delete, or modify privileges in production. This eliminates the risk of a user overwriting
|
|
2692
|
+
production data by accident."""
|
|
2693
|
+
|
|
2694
|
+
def __init__(self, api_client):
|
|
2695
|
+
self._api = api_client
|
|
2696
|
+
|
|
2697
|
+
def create(
|
|
2698
|
+
self,
|
|
2699
|
+
*,
|
|
2700
|
+
active: Optional[bool] = None,
|
|
2701
|
+
application_id: Optional[str] = None,
|
|
2702
|
+
display_name: Optional[str] = None,
|
|
2703
|
+
external_id: Optional[str] = None,
|
|
2704
|
+
id: Optional[str] = None,
|
|
2705
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
2706
|
+
) -> AccountServicePrincipal:
|
|
2707
|
+
"""Creates a new service principal in the Databricks account.
|
|
2708
|
+
|
|
2709
|
+
:param active: bool (optional)
|
|
2710
|
+
If this user is active
|
|
2711
|
+
:param application_id: str (optional)
|
|
2712
|
+
UUID relating to the service principal
|
|
2713
|
+
:param display_name: str (optional)
|
|
2714
|
+
String that represents a concatenation of given and family names.
|
|
2715
|
+
:param external_id: str (optional)
|
|
2716
|
+
:param id: str (optional)
|
|
2717
|
+
Databricks service principal ID.
|
|
2718
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
2719
|
+
Indicates if the group has the admin role.
|
|
2720
|
+
|
|
2721
|
+
:returns: :class:`AccountServicePrincipal`
|
|
2722
|
+
"""
|
|
2723
|
+
body = {}
|
|
2724
|
+
if active is not None:
|
|
2725
|
+
body["active"] = active
|
|
2726
|
+
if application_id is not None:
|
|
2727
|
+
body["applicationId"] = application_id
|
|
2728
|
+
if display_name is not None:
|
|
2729
|
+
body["displayName"] = display_name
|
|
2730
|
+
if external_id is not None:
|
|
2731
|
+
body["externalId"] = external_id
|
|
2732
|
+
if id is not None:
|
|
2733
|
+
body["id"] = id
|
|
2734
|
+
if roles is not None:
|
|
2735
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
2736
|
+
headers = {
|
|
2737
|
+
"Accept": "application/json",
|
|
2738
|
+
"Content-Type": "application/json",
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
res = self._api.do(
|
|
2742
|
+
"POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals", body=body, headers=headers
|
|
2743
|
+
)
|
|
2744
|
+
return AccountServicePrincipal.from_dict(res)
|
|
2745
|
+
|
|
2746
|
+
def delete(self, id: str):
|
|
2747
|
+
"""Delete a single service principal in the Databricks account.
|
|
2748
|
+
|
|
2749
|
+
:param id: str
|
|
2750
|
+
Unique ID for a service principal in the Databricks account.
|
|
2751
|
+
|
|
2752
|
+
|
|
2753
|
+
"""
|
|
2754
|
+
|
|
2755
|
+
headers = {}
|
|
2756
|
+
|
|
2757
|
+
self._api.do(
|
|
2758
|
+
"DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", headers=headers
|
|
2759
|
+
)
|
|
2760
|
+
|
|
2761
|
+
def get(self, id: str) -> AccountServicePrincipal:
|
|
2762
|
+
"""Gets the details for a single service principal define in the Databricks account.
|
|
2763
|
+
|
|
2764
|
+
:param id: str
|
|
2765
|
+
Unique ID for a service principal in the Databricks account.
|
|
2766
|
+
|
|
2767
|
+
:returns: :class:`AccountServicePrincipal`
|
|
2768
|
+
"""
|
|
2769
|
+
|
|
2770
|
+
headers = {
|
|
2771
|
+
"Accept": "application/json",
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
res = self._api.do(
|
|
2775
|
+
"GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", headers=headers
|
|
2776
|
+
)
|
|
2777
|
+
return AccountServicePrincipal.from_dict(res)
|
|
2778
|
+
|
|
2779
|
+
def list(
|
|
2780
|
+
self,
|
|
2781
|
+
*,
|
|
2782
|
+
attributes: Optional[str] = None,
|
|
2783
|
+
count: Optional[int] = None,
|
|
2784
|
+
excluded_attributes: Optional[str] = None,
|
|
2785
|
+
filter: Optional[str] = None,
|
|
2786
|
+
sort_by: Optional[str] = None,
|
|
2787
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
2788
|
+
start_index: Optional[int] = None,
|
|
2789
|
+
) -> Iterator[AccountServicePrincipal]:
|
|
2790
|
+
"""Gets the set of service principals associated with a Databricks account.
|
|
2791
|
+
|
|
2792
|
+
:param attributes: str (optional)
|
|
2793
|
+
Comma-separated list of attributes to return in response.
|
|
2794
|
+
:param count: int (optional)
|
|
2795
|
+
Desired number of results per page. Default is 10000.
|
|
2796
|
+
:param excluded_attributes: str (optional)
|
|
2797
|
+
Comma-separated list of attributes to exclude in response.
|
|
2798
|
+
:param filter: str (optional)
|
|
2799
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
2800
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
2801
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
2802
|
+
only support simple expressions.
|
|
2803
|
+
|
|
2804
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
2805
|
+
:param sort_by: str (optional)
|
|
2806
|
+
Attribute to sort the results.
|
|
2807
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
2808
|
+
The order to sort the results.
|
|
2809
|
+
:param start_index: int (optional)
|
|
2810
|
+
Specifies the index of the first result. First item is number 1.
|
|
2811
|
+
|
|
2812
|
+
:returns: Iterator over :class:`AccountServicePrincipal`
|
|
2813
|
+
"""
|
|
2814
|
+
|
|
2815
|
+
query = {}
|
|
2816
|
+
if attributes is not None:
|
|
2817
|
+
query["attributes"] = attributes
|
|
2818
|
+
if count is not None:
|
|
2819
|
+
query["count"] = count
|
|
2820
|
+
if excluded_attributes is not None:
|
|
2821
|
+
query["excludedAttributes"] = excluded_attributes
|
|
2822
|
+
if filter is not None:
|
|
2823
|
+
query["filter"] = filter
|
|
2824
|
+
if sort_by is not None:
|
|
2825
|
+
query["sortBy"] = sort_by
|
|
2826
|
+
if sort_order is not None:
|
|
2827
|
+
query["sortOrder"] = sort_order.value
|
|
2828
|
+
if start_index is not None:
|
|
2829
|
+
query["startIndex"] = start_index
|
|
2830
|
+
headers = {
|
|
2831
|
+
"Accept": "application/json",
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
query["startIndex"] = 1
|
|
2835
|
+
if "count" not in query:
|
|
2836
|
+
query["count"] = 10000
|
|
2837
|
+
while True:
|
|
2838
|
+
json = self._api.do(
|
|
2839
|
+
"GET",
|
|
2840
|
+
f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals",
|
|
2841
|
+
query=query,
|
|
2842
|
+
headers=headers,
|
|
2843
|
+
)
|
|
2844
|
+
if "Resources" in json:
|
|
2845
|
+
for v in json["Resources"]:
|
|
2846
|
+
yield AccountServicePrincipal.from_dict(v)
|
|
2847
|
+
if "Resources" not in json or not json["Resources"]:
|
|
2848
|
+
return
|
|
2849
|
+
query["startIndex"] += len(json["Resources"])
|
|
2850
|
+
|
|
2851
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
2852
|
+
"""Partially updates the details of a single service principal in the Databricks account.
|
|
2853
|
+
|
|
2854
|
+
:param id: str
|
|
2855
|
+
Unique ID in the Databricks workspace.
|
|
2856
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
2857
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
2858
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
2859
|
+
|
|
2860
|
+
|
|
2861
|
+
"""
|
|
2862
|
+
body = {}
|
|
2863
|
+
if operations is not None:
|
|
2864
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
2865
|
+
if schemas is not None:
|
|
2866
|
+
body["schemas"] = [v.value for v in schemas]
|
|
2867
|
+
headers = {
|
|
2868
|
+
"Accept": "application/json",
|
|
2869
|
+
"Content-Type": "application/json",
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
self._api.do(
|
|
2873
|
+
"PATCH",
|
|
2874
|
+
f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}",
|
|
2875
|
+
body=body,
|
|
2876
|
+
headers=headers,
|
|
2877
|
+
)
|
|
2878
|
+
|
|
2879
|
+
def update(
|
|
2880
|
+
self,
|
|
2881
|
+
id: str,
|
|
2882
|
+
*,
|
|
2883
|
+
active: Optional[bool] = None,
|
|
2884
|
+
application_id: Optional[str] = None,
|
|
2885
|
+
display_name: Optional[str] = None,
|
|
2886
|
+
external_id: Optional[str] = None,
|
|
2887
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
2888
|
+
):
|
|
2889
|
+
"""Updates the details of a single service principal.
|
|
2890
|
+
|
|
2891
|
+
This action replaces the existing service principal with the same name.
|
|
2892
|
+
|
|
2893
|
+
:param id: str
|
|
2894
|
+
Databricks service principal ID.
|
|
2895
|
+
:param active: bool (optional)
|
|
2896
|
+
If this user is active
|
|
2897
|
+
:param application_id: str (optional)
|
|
2898
|
+
UUID relating to the service principal
|
|
2899
|
+
:param display_name: str (optional)
|
|
2900
|
+
String that represents a concatenation of given and family names.
|
|
2901
|
+
:param external_id: str (optional)
|
|
2902
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
2903
|
+
Indicates if the group has the admin role.
|
|
2904
|
+
|
|
2905
|
+
|
|
2906
|
+
"""
|
|
2907
|
+
body = {}
|
|
2908
|
+
if active is not None:
|
|
2909
|
+
body["active"] = active
|
|
2910
|
+
if application_id is not None:
|
|
2911
|
+
body["applicationId"] = application_id
|
|
2912
|
+
if display_name is not None:
|
|
2913
|
+
body["displayName"] = display_name
|
|
2914
|
+
if external_id is not None:
|
|
2915
|
+
body["externalId"] = external_id
|
|
2916
|
+
if roles is not None:
|
|
2917
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
2918
|
+
headers = {
|
|
2919
|
+
"Accept": "application/json",
|
|
2920
|
+
"Content-Type": "application/json",
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2923
|
+
self._api.do(
|
|
2924
|
+
"PUT",
|
|
2925
|
+
f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}",
|
|
2926
|
+
body=body,
|
|
2927
|
+
headers=headers,
|
|
2928
|
+
)
|
|
2929
|
+
|
|
2930
|
+
|
|
2931
|
+
class AccountUsersV2API:
|
|
2932
|
+
"""User identities recognized by Databricks and represented by email addresses.
|
|
2933
|
+
|
|
2934
|
+
Databricks recommends using SCIM provisioning to sync users and groups automatically from your identity
|
|
2935
|
+
provider to your Databricks account. SCIM streamlines onboarding a new employee or team by using your
|
|
2936
|
+
identity provider to create users and groups in Databricks account and give them the proper level of
|
|
2937
|
+
access. When a user leaves your organization or no longer needs access to Databricks account, admins can
|
|
2938
|
+
terminate the user in your identity provider and that user’s account will also be removed from
|
|
2939
|
+
Databricks account. This ensures a consistent offboarding process and prevents unauthorized users from
|
|
2940
|
+
accessing sensitive data."""
|
|
2941
|
+
|
|
2942
|
+
def __init__(self, api_client):
|
|
2943
|
+
self._api = api_client
|
|
2944
|
+
|
|
2945
|
+
def create(
|
|
2946
|
+
self,
|
|
2947
|
+
*,
|
|
2948
|
+
active: Optional[bool] = None,
|
|
2949
|
+
display_name: Optional[str] = None,
|
|
2950
|
+
emails: Optional[List[ComplexValue]] = None,
|
|
2951
|
+
external_id: Optional[str] = None,
|
|
2952
|
+
id: Optional[str] = None,
|
|
2953
|
+
name: Optional[Name] = None,
|
|
2954
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
2955
|
+
user_name: Optional[str] = None,
|
|
2956
|
+
) -> AccountUser:
|
|
2957
|
+
"""Creates a new user in the Databricks account. This new user will also be added to the Databricks
|
|
2958
|
+
account.
|
|
2959
|
+
|
|
2960
|
+
:param active: bool (optional)
|
|
2961
|
+
If this user is active
|
|
2962
|
+
:param display_name: str (optional)
|
|
2963
|
+
String that represents a concatenation of given and family names. For example `John Smith`.
|
|
2964
|
+
:param emails: List[:class:`ComplexValue`] (optional)
|
|
2965
|
+
All the emails associated with the Databricks user.
|
|
2966
|
+
:param external_id: str (optional)
|
|
2967
|
+
External ID is not currently supported. It is reserved for future use.
|
|
2968
|
+
:param id: str (optional)
|
|
2969
|
+
Databricks user ID.
|
|
2970
|
+
:param name: :class:`Name` (optional)
|
|
2971
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
2972
|
+
Indicates if the group has the admin role.
|
|
2973
|
+
:param user_name: str (optional)
|
|
2974
|
+
Email address of the Databricks user.
|
|
2975
|
+
|
|
2976
|
+
:returns: :class:`AccountUser`
|
|
2977
|
+
"""
|
|
2978
|
+
body = {}
|
|
2979
|
+
if active is not None:
|
|
2980
|
+
body["active"] = active
|
|
2981
|
+
if display_name is not None:
|
|
2982
|
+
body["displayName"] = display_name
|
|
2983
|
+
if emails is not None:
|
|
2984
|
+
body["emails"] = [v.as_dict() for v in emails]
|
|
2985
|
+
if external_id is not None:
|
|
2986
|
+
body["externalId"] = external_id
|
|
2987
|
+
if id is not None:
|
|
2988
|
+
body["id"] = id
|
|
2989
|
+
if name is not None:
|
|
2990
|
+
body["name"] = name.as_dict()
|
|
2991
|
+
if roles is not None:
|
|
2992
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
2993
|
+
if user_name is not None:
|
|
2994
|
+
body["userName"] = user_name
|
|
2995
|
+
headers = {
|
|
2996
|
+
"Accept": "application/json",
|
|
2997
|
+
"Content-Type": "application/json",
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
res = self._api.do(
|
|
3001
|
+
"POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users", body=body, headers=headers
|
|
3002
|
+
)
|
|
3003
|
+
return AccountUser.from_dict(res)
|
|
3004
|
+
|
|
3005
|
+
def delete(self, id: str):
|
|
3006
|
+
"""Deletes a user. Deleting a user from a Databricks account also removes objects associated with the
|
|
3007
|
+
user.
|
|
3008
|
+
|
|
3009
|
+
:param id: str
|
|
3010
|
+
Unique ID for a user in the Databricks account.
|
|
3011
|
+
|
|
3012
|
+
|
|
3013
|
+
"""
|
|
3014
|
+
|
|
3015
|
+
headers = {}
|
|
3016
|
+
|
|
3017
|
+
self._api.do("DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", headers=headers)
|
|
3018
|
+
|
|
3019
|
+
def get(
|
|
3020
|
+
self,
|
|
3021
|
+
id: str,
|
|
3022
|
+
*,
|
|
3023
|
+
attributes: Optional[str] = None,
|
|
3024
|
+
count: Optional[int] = None,
|
|
3025
|
+
excluded_attributes: Optional[str] = None,
|
|
3026
|
+
filter: Optional[str] = None,
|
|
3027
|
+
sort_by: Optional[str] = None,
|
|
3028
|
+
sort_order: Optional[GetSortOrder] = None,
|
|
3029
|
+
start_index: Optional[int] = None,
|
|
3030
|
+
) -> AccountUser:
|
|
3031
|
+
"""Gets information for a specific user in Databricks account.
|
|
3032
|
+
|
|
3033
|
+
:param id: str
|
|
3034
|
+
Unique ID for a user in the Databricks account.
|
|
3035
|
+
:param attributes: str (optional)
|
|
3036
|
+
Comma-separated list of attributes to return in response.
|
|
3037
|
+
:param count: int (optional)
|
|
3038
|
+
Desired number of results per page. Default is 10000.
|
|
3039
|
+
:param excluded_attributes: str (optional)
|
|
3040
|
+
Comma-separated list of attributes to exclude in response.
|
|
3041
|
+
:param filter: str (optional)
|
|
3042
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
3043
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
3044
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
3045
|
+
only support simple expressions.
|
|
3046
|
+
|
|
3047
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
3048
|
+
:param sort_by: str (optional)
|
|
3049
|
+
Attribute to sort the results. Multi-part paths are supported. For example, `userName`,
|
|
3050
|
+
`name.givenName`, and `emails`.
|
|
3051
|
+
:param sort_order: :class:`GetSortOrder` (optional)
|
|
3052
|
+
The order to sort the results.
|
|
3053
|
+
:param start_index: int (optional)
|
|
3054
|
+
Specifies the index of the first result. First item is number 1.
|
|
3055
|
+
|
|
3056
|
+
:returns: :class:`AccountUser`
|
|
3057
|
+
"""
|
|
3058
|
+
|
|
3059
|
+
query = {}
|
|
3060
|
+
if attributes is not None:
|
|
3061
|
+
query["attributes"] = attributes
|
|
3062
|
+
if count is not None:
|
|
3063
|
+
query["count"] = count
|
|
3064
|
+
if excluded_attributes is not None:
|
|
3065
|
+
query["excludedAttributes"] = excluded_attributes
|
|
3066
|
+
if filter is not None:
|
|
3067
|
+
query["filter"] = filter
|
|
3068
|
+
if sort_by is not None:
|
|
3069
|
+
query["sortBy"] = sort_by
|
|
3070
|
+
if sort_order is not None:
|
|
3071
|
+
query["sortOrder"] = sort_order.value
|
|
3072
|
+
if start_index is not None:
|
|
3073
|
+
query["startIndex"] = start_index
|
|
3074
|
+
headers = {
|
|
3075
|
+
"Accept": "application/json",
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
res = self._api.do(
|
|
3079
|
+
"GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", query=query, headers=headers
|
|
3080
|
+
)
|
|
3081
|
+
return AccountUser.from_dict(res)
|
|
3082
|
+
|
|
3083
|
+
def list(
|
|
3084
|
+
self,
|
|
3085
|
+
*,
|
|
3086
|
+
attributes: Optional[str] = None,
|
|
3087
|
+
count: Optional[int] = None,
|
|
3088
|
+
excluded_attributes: Optional[str] = None,
|
|
3089
|
+
filter: Optional[str] = None,
|
|
3090
|
+
sort_by: Optional[str] = None,
|
|
3091
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
3092
|
+
start_index: Optional[int] = None,
|
|
3093
|
+
) -> Iterator[AccountUser]:
|
|
3094
|
+
"""Gets details for all the users associated with a Databricks account.
|
|
3095
|
+
|
|
3096
|
+
:param attributes: str (optional)
|
|
3097
|
+
Comma-separated list of attributes to return in response.
|
|
3098
|
+
:param count: int (optional)
|
|
3099
|
+
Desired number of results per page. Default is 10000.
|
|
3100
|
+
:param excluded_attributes: str (optional)
|
|
3101
|
+
Comma-separated list of attributes to exclude in response.
|
|
3102
|
+
:param filter: str (optional)
|
|
3103
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
3104
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
3105
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
3106
|
+
only support simple expressions.
|
|
3107
|
+
|
|
3108
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
3109
|
+
:param sort_by: str (optional)
|
|
3110
|
+
Attribute to sort the results. Multi-part paths are supported. For example, `userName`,
|
|
3111
|
+
`name.givenName`, and `emails`.
|
|
3112
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
3113
|
+
The order to sort the results.
|
|
3114
|
+
:param start_index: int (optional)
|
|
3115
|
+
Specifies the index of the first result. First item is number 1.
|
|
3116
|
+
|
|
3117
|
+
:returns: Iterator over :class:`AccountUser`
|
|
3118
|
+
"""
|
|
3119
|
+
|
|
3120
|
+
query = {}
|
|
3121
|
+
if attributes is not None:
|
|
3122
|
+
query["attributes"] = attributes
|
|
3123
|
+
if count is not None:
|
|
3124
|
+
query["count"] = count
|
|
3125
|
+
if excluded_attributes is not None:
|
|
3126
|
+
query["excludedAttributes"] = excluded_attributes
|
|
3127
|
+
if filter is not None:
|
|
3128
|
+
query["filter"] = filter
|
|
3129
|
+
if sort_by is not None:
|
|
3130
|
+
query["sortBy"] = sort_by
|
|
3131
|
+
if sort_order is not None:
|
|
3132
|
+
query["sortOrder"] = sort_order.value
|
|
3133
|
+
if start_index is not None:
|
|
3134
|
+
query["startIndex"] = start_index
|
|
3135
|
+
headers = {
|
|
3136
|
+
"Accept": "application/json",
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
query["startIndex"] = 1
|
|
3140
|
+
if "count" not in query:
|
|
3141
|
+
query["count"] = 10000
|
|
3142
|
+
while True:
|
|
3143
|
+
json = self._api.do(
|
|
3144
|
+
"GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users", query=query, headers=headers
|
|
3145
|
+
)
|
|
3146
|
+
if "Resources" in json:
|
|
3147
|
+
for v in json["Resources"]:
|
|
3148
|
+
yield AccountUser.from_dict(v)
|
|
3149
|
+
if "Resources" not in json or not json["Resources"]:
|
|
3150
|
+
return
|
|
3151
|
+
query["startIndex"] += len(json["Resources"])
|
|
3152
|
+
|
|
3153
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
3154
|
+
"""Partially updates a user resource by applying the supplied operations on specific user attributes.
|
|
3155
|
+
|
|
3156
|
+
:param id: str
|
|
3157
|
+
Unique ID in the Databricks workspace.
|
|
3158
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
3159
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
3160
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
3161
|
+
|
|
3162
|
+
|
|
3163
|
+
"""
|
|
3164
|
+
body = {}
|
|
3165
|
+
if operations is not None:
|
|
3166
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
3167
|
+
if schemas is not None:
|
|
3168
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3169
|
+
headers = {
|
|
3170
|
+
"Accept": "application/json",
|
|
3171
|
+
"Content-Type": "application/json",
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
self._api.do(
|
|
3175
|
+
"PATCH", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers
|
|
3176
|
+
)
|
|
3177
|
+
|
|
3178
|
+
def update(
|
|
3179
|
+
self,
|
|
3180
|
+
id: str,
|
|
3181
|
+
*,
|
|
3182
|
+
active: Optional[bool] = None,
|
|
3183
|
+
display_name: Optional[str] = None,
|
|
3184
|
+
emails: Optional[List[ComplexValue]] = None,
|
|
3185
|
+
external_id: Optional[str] = None,
|
|
3186
|
+
name: Optional[Name] = None,
|
|
3187
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3188
|
+
user_name: Optional[str] = None,
|
|
3189
|
+
):
|
|
3190
|
+
"""Replaces a user's information with the data supplied in request.
|
|
3191
|
+
|
|
3192
|
+
:param id: str
|
|
3193
|
+
Databricks user ID.
|
|
3194
|
+
:param active: bool (optional)
|
|
3195
|
+
If this user is active
|
|
3196
|
+
:param display_name: str (optional)
|
|
3197
|
+
String that represents a concatenation of given and family names. For example `John Smith`.
|
|
3198
|
+
:param emails: List[:class:`ComplexValue`] (optional)
|
|
3199
|
+
All the emails associated with the Databricks user.
|
|
3200
|
+
:param external_id: str (optional)
|
|
3201
|
+
External ID is not currently supported. It is reserved for future use.
|
|
3202
|
+
:param name: :class:`Name` (optional)
|
|
3203
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3204
|
+
Indicates if the group has the admin role.
|
|
3205
|
+
:param user_name: str (optional)
|
|
3206
|
+
Email address of the Databricks user.
|
|
3207
|
+
|
|
3208
|
+
|
|
3209
|
+
"""
|
|
3210
|
+
body = {}
|
|
3211
|
+
if active is not None:
|
|
3212
|
+
body["active"] = active
|
|
3213
|
+
if display_name is not None:
|
|
3214
|
+
body["displayName"] = display_name
|
|
3215
|
+
if emails is not None:
|
|
3216
|
+
body["emails"] = [v.as_dict() for v in emails]
|
|
3217
|
+
if external_id is not None:
|
|
3218
|
+
body["externalId"] = external_id
|
|
3219
|
+
if name is not None:
|
|
3220
|
+
body["name"] = name.as_dict()
|
|
3221
|
+
if roles is not None:
|
|
3222
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
3223
|
+
if user_name is not None:
|
|
3224
|
+
body["userName"] = user_name
|
|
3225
|
+
headers = {
|
|
3226
|
+
"Accept": "application/json",
|
|
3227
|
+
"Content-Type": "application/json",
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers)
|
|
3231
|
+
|
|
3232
|
+
|
|
3233
|
+
class CurrentUserAPI:
|
|
3234
|
+
"""This API allows retrieving information about currently authenticated user or service principal."""
|
|
3235
|
+
|
|
3236
|
+
def __init__(self, api_client):
|
|
3237
|
+
self._api = api_client
|
|
3238
|
+
|
|
3239
|
+
def me(self) -> User:
|
|
3240
|
+
"""Get details about the current method caller's identity.
|
|
3241
|
+
|
|
3242
|
+
|
|
3243
|
+
:returns: :class:`User`
|
|
3244
|
+
"""
|
|
3245
|
+
|
|
3246
|
+
headers = {
|
|
3247
|
+
"Accept": "application/json",
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
res = self._api.do("GET", "/api/2.0/preview/scim/v2/Me", headers=headers)
|
|
3251
|
+
return User.from_dict(res)
|
|
3252
|
+
|
|
3253
|
+
|
|
3254
|
+
class GroupsV2API:
|
|
3255
|
+
"""Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and
|
|
3256
|
+
other securable objects.
|
|
3257
|
+
|
|
3258
|
+
It is best practice to assign access to workspaces and access-control policies in Unity Catalog to groups,
|
|
3259
|
+
instead of to users individually. All Databricks workspace identities can be assigned as members of
|
|
3260
|
+
groups, and members inherit permissions that are assigned to their group."""
|
|
3261
|
+
|
|
3262
|
+
def __init__(self, api_client):
|
|
3263
|
+
self._api = api_client
|
|
3264
|
+
|
|
3265
|
+
def create(
|
|
3266
|
+
self,
|
|
3267
|
+
*,
|
|
3268
|
+
display_name: Optional[str] = None,
|
|
3269
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
3270
|
+
external_id: Optional[str] = None,
|
|
3271
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
3272
|
+
id: Optional[str] = None,
|
|
3273
|
+
members: Optional[List[ComplexValue]] = None,
|
|
3274
|
+
meta: Optional[ResourceMeta] = None,
|
|
3275
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3276
|
+
schemas: Optional[List[GroupSchema]] = None,
|
|
3277
|
+
) -> Group:
|
|
3278
|
+
"""Creates a group in the Databricks workspace with a unique name, using the supplied group details.
|
|
3279
|
+
|
|
3280
|
+
:param display_name: str (optional)
|
|
3281
|
+
String that represents a human-readable group name
|
|
3282
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3283
|
+
Entitlements assigned to the group. See [assigning entitlements] for a full list of supported
|
|
3284
|
+
values.
|
|
3285
|
+
|
|
3286
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3287
|
+
:param external_id: str (optional)
|
|
3288
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
3289
|
+
:param id: str (optional)
|
|
3290
|
+
Databricks group ID
|
|
3291
|
+
:param members: List[:class:`ComplexValue`] (optional)
|
|
3292
|
+
:param meta: :class:`ResourceMeta` (optional)
|
|
3293
|
+
Container for the group identifier. Workspace local versus account.
|
|
3294
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3295
|
+
Corresponds to AWS instance profile/arn role.
|
|
3296
|
+
:param schemas: List[:class:`GroupSchema`] (optional)
|
|
3297
|
+
The schema of the group.
|
|
3298
|
+
|
|
3299
|
+
:returns: :class:`Group`
|
|
3300
|
+
"""
|
|
3301
|
+
body = {}
|
|
3302
|
+
if display_name is not None:
|
|
3303
|
+
body["displayName"] = display_name
|
|
3304
|
+
if entitlements is not None:
|
|
3305
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
3306
|
+
if external_id is not None:
|
|
3307
|
+
body["externalId"] = external_id
|
|
3308
|
+
if groups is not None:
|
|
3309
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
3310
|
+
if id is not None:
|
|
3311
|
+
body["id"] = id
|
|
3312
|
+
if members is not None:
|
|
3313
|
+
body["members"] = [v.as_dict() for v in members]
|
|
3314
|
+
if meta is not None:
|
|
3315
|
+
body["meta"] = meta.as_dict()
|
|
3316
|
+
if roles is not None:
|
|
3317
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
3318
|
+
if schemas is not None:
|
|
3319
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3320
|
+
headers = {
|
|
3321
|
+
"Accept": "application/json",
|
|
3322
|
+
"Content-Type": "application/json",
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
res = self._api.do("POST", "/api/2.0/preview/scim/v2/Groups", body=body, headers=headers)
|
|
3326
|
+
return Group.from_dict(res)
|
|
3327
|
+
|
|
3328
|
+
def delete(self, id: str):
|
|
3329
|
+
"""Deletes a group from the Databricks workspace.
|
|
3330
|
+
|
|
3331
|
+
:param id: str
|
|
3332
|
+
Unique ID for a group in the Databricks workspace.
|
|
3333
|
+
|
|
3334
|
+
|
|
3335
|
+
"""
|
|
3336
|
+
|
|
3337
|
+
headers = {}
|
|
3338
|
+
|
|
3339
|
+
self._api.do("DELETE", f"/api/2.0/preview/scim/v2/Groups/{id}", headers=headers)
|
|
3340
|
+
|
|
3341
|
+
def get(self, id: str) -> Group:
|
|
3342
|
+
"""Gets the information for a specific group in the Databricks workspace.
|
|
3343
|
+
|
|
3344
|
+
:param id: str
|
|
3345
|
+
Unique ID for a group in the Databricks workspace.
|
|
3346
|
+
|
|
3347
|
+
:returns: :class:`Group`
|
|
3348
|
+
"""
|
|
3349
|
+
|
|
3350
|
+
headers = {
|
|
3351
|
+
"Accept": "application/json",
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3354
|
+
res = self._api.do("GET", f"/api/2.0/preview/scim/v2/Groups/{id}", headers=headers)
|
|
3355
|
+
return Group.from_dict(res)
|
|
3356
|
+
|
|
3357
|
+
def list(
|
|
3358
|
+
self,
|
|
3359
|
+
*,
|
|
3360
|
+
attributes: Optional[str] = None,
|
|
3361
|
+
count: Optional[int] = None,
|
|
3362
|
+
excluded_attributes: Optional[str] = None,
|
|
3363
|
+
filter: Optional[str] = None,
|
|
3364
|
+
sort_by: Optional[str] = None,
|
|
3365
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
3366
|
+
start_index: Optional[int] = None,
|
|
3367
|
+
) -> Iterator[Group]:
|
|
3368
|
+
"""Gets all details of the groups associated with the Databricks workspace.
|
|
3369
|
+
|
|
3370
|
+
:param attributes: str (optional)
|
|
3371
|
+
Comma-separated list of attributes to return in response.
|
|
3372
|
+
:param count: int (optional)
|
|
3373
|
+
Desired number of results per page.
|
|
3374
|
+
:param excluded_attributes: str (optional)
|
|
3375
|
+
Comma-separated list of attributes to exclude in response.
|
|
3376
|
+
:param filter: str (optional)
|
|
3377
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
3378
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
3379
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
3380
|
+
only support simple expressions.
|
|
3381
|
+
|
|
3382
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
3383
|
+
:param sort_by: str (optional)
|
|
3384
|
+
Attribute to sort the results.
|
|
3385
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
3386
|
+
The order to sort the results.
|
|
3387
|
+
:param start_index: int (optional)
|
|
3388
|
+
Specifies the index of the first result. First item is number 1.
|
|
3389
|
+
|
|
3390
|
+
:returns: Iterator over :class:`Group`
|
|
3391
|
+
"""
|
|
3392
|
+
|
|
3393
|
+
query = {}
|
|
3394
|
+
if attributes is not None:
|
|
3395
|
+
query["attributes"] = attributes
|
|
3396
|
+
if count is not None:
|
|
3397
|
+
query["count"] = count
|
|
3398
|
+
if excluded_attributes is not None:
|
|
3399
|
+
query["excludedAttributes"] = excluded_attributes
|
|
3400
|
+
if filter is not None:
|
|
3401
|
+
query["filter"] = filter
|
|
3402
|
+
if sort_by is not None:
|
|
3403
|
+
query["sortBy"] = sort_by
|
|
3404
|
+
if sort_order is not None:
|
|
3405
|
+
query["sortOrder"] = sort_order.value
|
|
3406
|
+
if start_index is not None:
|
|
3407
|
+
query["startIndex"] = start_index
|
|
3408
|
+
headers = {
|
|
3409
|
+
"Accept": "application/json",
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3412
|
+
query["startIndex"] = 1
|
|
3413
|
+
if "count" not in query:
|
|
3414
|
+
query["count"] = 10000
|
|
3415
|
+
while True:
|
|
3416
|
+
json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers)
|
|
3417
|
+
if "Resources" in json:
|
|
3418
|
+
for v in json["Resources"]:
|
|
3419
|
+
yield Group.from_dict(v)
|
|
3420
|
+
if "Resources" not in json or not json["Resources"]:
|
|
3421
|
+
return
|
|
3422
|
+
query["startIndex"] += len(json["Resources"])
|
|
3423
|
+
|
|
3424
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
3425
|
+
"""Partially updates the details of a group.
|
|
3426
|
+
|
|
3427
|
+
:param id: str
|
|
3428
|
+
Unique ID in the Databricks workspace.
|
|
3429
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
3430
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
3431
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
3432
|
+
|
|
3433
|
+
|
|
3434
|
+
"""
|
|
3435
|
+
body = {}
|
|
3436
|
+
if operations is not None:
|
|
3437
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
3438
|
+
if schemas is not None:
|
|
3439
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3440
|
+
headers = {
|
|
3441
|
+
"Accept": "application/json",
|
|
3442
|
+
"Content-Type": "application/json",
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3446
|
+
|
|
3447
|
+
def update(
|
|
3448
|
+
self,
|
|
3449
|
+
id: str,
|
|
3450
|
+
*,
|
|
3451
|
+
display_name: Optional[str] = None,
|
|
3452
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
3453
|
+
external_id: Optional[str] = None,
|
|
3454
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
3455
|
+
members: Optional[List[ComplexValue]] = None,
|
|
3456
|
+
meta: Optional[ResourceMeta] = None,
|
|
3457
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3458
|
+
schemas: Optional[List[GroupSchema]] = None,
|
|
3459
|
+
):
|
|
3460
|
+
"""Updates the details of a group by replacing the entire group entity.
|
|
3461
|
+
|
|
3462
|
+
:param id: str
|
|
3463
|
+
Databricks group ID
|
|
3464
|
+
:param display_name: str (optional)
|
|
3465
|
+
String that represents a human-readable group name
|
|
3466
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3467
|
+
Entitlements assigned to the group. See [assigning entitlements] for a full list of supported
|
|
3468
|
+
values.
|
|
3469
|
+
|
|
3470
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3471
|
+
:param external_id: str (optional)
|
|
3472
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
3473
|
+
:param members: List[:class:`ComplexValue`] (optional)
|
|
3474
|
+
:param meta: :class:`ResourceMeta` (optional)
|
|
3475
|
+
Container for the group identifier. Workspace local versus account.
|
|
3476
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3477
|
+
Corresponds to AWS instance profile/arn role.
|
|
3478
|
+
:param schemas: List[:class:`GroupSchema`] (optional)
|
|
3479
|
+
The schema of the group.
|
|
3480
|
+
|
|
3481
|
+
|
|
3482
|
+
"""
|
|
3483
|
+
body = {}
|
|
3484
|
+
if display_name is not None:
|
|
3485
|
+
body["displayName"] = display_name
|
|
3486
|
+
if entitlements is not None:
|
|
3487
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
3488
|
+
if external_id is not None:
|
|
3489
|
+
body["externalId"] = external_id
|
|
3490
|
+
if groups is not None:
|
|
3491
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
3492
|
+
if members is not None:
|
|
3493
|
+
body["members"] = [v.as_dict() for v in members]
|
|
3494
|
+
if meta is not None:
|
|
3495
|
+
body["meta"] = meta.as_dict()
|
|
3496
|
+
if roles is not None:
|
|
3497
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
3498
|
+
if schemas is not None:
|
|
3499
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3500
|
+
headers = {
|
|
3501
|
+
"Accept": "application/json",
|
|
3502
|
+
"Content-Type": "application/json",
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3506
|
+
|
|
3507
|
+
|
|
3508
|
+
class PermissionMigrationAPI:
|
|
3509
|
+
"""APIs for migrating acl permissions, used only by the ucx tool: https://github.com/databrickslabs/ucx"""
|
|
3510
|
+
|
|
3511
|
+
def __init__(self, api_client):
|
|
3512
|
+
self._api = api_client
|
|
3513
|
+
|
|
3514
|
+
def migrate_permissions(
|
|
3515
|
+
self,
|
|
3516
|
+
workspace_id: int,
|
|
3517
|
+
from_workspace_group_name: str,
|
|
3518
|
+
to_account_group_name: str,
|
|
3519
|
+
*,
|
|
3520
|
+
size: Optional[int] = None,
|
|
3521
|
+
) -> MigratePermissionsResponse:
|
|
3522
|
+
"""Migrate Permissions.
|
|
3523
|
+
|
|
3524
|
+
:param workspace_id: int
|
|
3525
|
+
WorkspaceId of the associated workspace where the permission migration will occur.
|
|
3526
|
+
:param from_workspace_group_name: str
|
|
3527
|
+
The name of the workspace group that permissions will be migrated from.
|
|
3528
|
+
:param to_account_group_name: str
|
|
3529
|
+
The name of the account group that permissions will be migrated to.
|
|
3530
|
+
:param size: int (optional)
|
|
3531
|
+
The maximum number of permissions that will be migrated.
|
|
3532
|
+
|
|
3533
|
+
:returns: :class:`MigratePermissionsResponse`
|
|
3534
|
+
"""
|
|
3535
|
+
body = {}
|
|
3536
|
+
if from_workspace_group_name is not None:
|
|
3537
|
+
body["from_workspace_group_name"] = from_workspace_group_name
|
|
3538
|
+
if size is not None:
|
|
3539
|
+
body["size"] = size
|
|
3540
|
+
if to_account_group_name is not None:
|
|
3541
|
+
body["to_account_group_name"] = to_account_group_name
|
|
3542
|
+
if workspace_id is not None:
|
|
3543
|
+
body["workspace_id"] = workspace_id
|
|
3544
|
+
headers = {
|
|
3545
|
+
"Accept": "application/json",
|
|
3546
|
+
"Content-Type": "application/json",
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
res = self._api.do("POST", "/api/2.0/permissionmigration", body=body, headers=headers)
|
|
3550
|
+
return MigratePermissionsResponse.from_dict(res)
|
|
3551
|
+
|
|
3552
|
+
|
|
3553
|
+
class PermissionsAPI:
|
|
3554
|
+
"""Permissions API are used to create read, write, edit, update and manage access for various users on
|
|
3555
|
+
different objects and endpoints. * **[Apps permissions](:service:apps)** — Manage which users can manage
|
|
3556
|
+
or use apps. * **[Cluster permissions](:service:clusters)** — Manage which users can manage, restart, or
|
|
3557
|
+
attach to clusters. * **[Cluster policy permissions](:service:clusterpolicies)** — Manage which users
|
|
3558
|
+
can use cluster policies. * **[Delta Live Tables pipeline permissions](:service:pipelines)** — Manage
|
|
3559
|
+
which users can view, manage, run, cancel, or own a Delta Live Tables pipeline. * **[Job
|
|
3560
|
+
permissions](:service:jobs)** — Manage which users can view, manage, trigger, cancel, or own a job. *
|
|
3561
|
+
**[MLflow experiment permissions](:service:experiments)** — Manage which users can read, edit, or manage
|
|
3562
|
+
MLflow experiments. * **[MLflow registered model permissions](:service:modelregistry)** — Manage which
|
|
3563
|
+
users can read, edit, or manage MLflow registered models. * **[Instance Pool
|
|
3564
|
+
permissions](:service:instancepools)** — Manage which users can manage or attach to pools. * **[Repo
|
|
3565
|
+
permissions](repos)** — Manage which users can read, run, edit, or manage a repo. * **[Serving endpoint
|
|
3566
|
+
permissions](:service:servingendpoints)** — Manage which users can view, query, or manage a serving
|
|
3567
|
+
endpoint. * **[SQL warehouse permissions](:service:warehouses)** — Manage which users can use or manage
|
|
3568
|
+
SQL warehouses. * **[Token permissions](:service:tokenmanagement)** — Manage which users can create or
|
|
3569
|
+
use tokens. * **[Workspace object permissions](:service:workspace)** — Manage which users can read, run,
|
|
3570
|
+
edit, or manage alerts, dbsql-dashboards, directories, files, notebooks and queries. For the mapping of
|
|
3571
|
+
the required permissions for specific actions or abilities and other important information, see [Access
|
|
3572
|
+
Control]. Note that to manage access control on service principals, use **[Account Access Control
|
|
3573
|
+
Proxy](:service:accountaccesscontrolproxy)**.
|
|
3574
|
+
|
|
3575
|
+
[Access Control]: https://docs.databricks.com/security/auth-authz/access-control/index.html"""
|
|
3576
|
+
|
|
3577
|
+
def __init__(self, api_client):
|
|
3578
|
+
self._api = api_client
|
|
3579
|
+
|
|
3580
|
+
def get(self, request_object_type: str, request_object_id: str) -> ObjectPermissions:
|
|
3581
|
+
"""Gets the permissions of an object. Objects can inherit permissions from their parent objects or root
|
|
3582
|
+
object.
|
|
3583
|
+
|
|
3584
|
+
:param request_object_type: str
|
|
3585
|
+
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3586
|
+
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3587
|
+
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3588
|
+
warehouses.
|
|
3589
|
+
:param request_object_id: str
|
|
3590
|
+
The id of the request object.
|
|
3591
|
+
|
|
3592
|
+
:returns: :class:`ObjectPermissions`
|
|
3593
|
+
"""
|
|
3594
|
+
|
|
3595
|
+
headers = {
|
|
3596
|
+
"Accept": "application/json",
|
|
3597
|
+
}
|
|
3598
|
+
|
|
3599
|
+
res = self._api.do("GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", headers=headers)
|
|
3600
|
+
return ObjectPermissions.from_dict(res)
|
|
3601
|
+
|
|
3602
|
+
def get_permission_levels(self, request_object_type: str, request_object_id: str) -> GetPermissionLevelsResponse:
|
|
3603
|
+
"""Gets the permission levels that a user can have on an object.
|
|
3604
|
+
|
|
3605
|
+
:param request_object_type: str
|
|
3606
|
+
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3607
|
+
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3608
|
+
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3609
|
+
warehouses.
|
|
3610
|
+
:param request_object_id: str
|
|
3611
|
+
|
|
3612
|
+
:returns: :class:`GetPermissionLevelsResponse`
|
|
3613
|
+
"""
|
|
3614
|
+
|
|
3615
|
+
headers = {
|
|
3616
|
+
"Accept": "application/json",
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
res = self._api.do(
|
|
3620
|
+
"GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}/permissionLevels", headers=headers
|
|
3621
|
+
)
|
|
3622
|
+
return GetPermissionLevelsResponse.from_dict(res)
|
|
3623
|
+
|
|
3624
|
+
def set(
|
|
3625
|
+
self,
|
|
3626
|
+
request_object_type: str,
|
|
3627
|
+
request_object_id: str,
|
|
3628
|
+
*,
|
|
3629
|
+
access_control_list: Optional[List[AccessControlRequest]] = None,
|
|
3630
|
+
) -> ObjectPermissions:
|
|
3631
|
+
"""Sets permissions on an object, replacing existing permissions if they exist. Deletes all direct
|
|
3632
|
+
permissions if none are specified. Objects can inherit permissions from their parent objects or root
|
|
3633
|
+
object.
|
|
3634
|
+
|
|
3635
|
+
:param request_object_type: str
|
|
3636
|
+
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3637
|
+
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3638
|
+
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3639
|
+
warehouses.
|
|
3640
|
+
:param request_object_id: str
|
|
3641
|
+
The id of the request object.
|
|
3642
|
+
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
|
3643
|
+
|
|
3644
|
+
:returns: :class:`ObjectPermissions`
|
|
3645
|
+
"""
|
|
3646
|
+
body = {}
|
|
3647
|
+
if access_control_list is not None:
|
|
3648
|
+
body["access_control_list"] = [v.as_dict() for v in access_control_list]
|
|
3649
|
+
headers = {
|
|
3650
|
+
"Accept": "application/json",
|
|
3651
|
+
"Content-Type": "application/json",
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
res = self._api.do(
|
|
3655
|
+
"PUT", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers
|
|
3656
|
+
)
|
|
3657
|
+
return ObjectPermissions.from_dict(res)
|
|
3658
|
+
|
|
3659
|
+
def update(
|
|
3660
|
+
self,
|
|
3661
|
+
request_object_type: str,
|
|
3662
|
+
request_object_id: str,
|
|
3663
|
+
*,
|
|
3664
|
+
access_control_list: Optional[List[AccessControlRequest]] = None,
|
|
3665
|
+
) -> ObjectPermissions:
|
|
3666
|
+
"""Updates the permissions on an object. Objects can inherit permissions from their parent objects or
|
|
3667
|
+
root object.
|
|
3668
|
+
|
|
3669
|
+
:param request_object_type: str
|
|
3670
|
+
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3671
|
+
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3672
|
+
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3673
|
+
warehouses.
|
|
3674
|
+
:param request_object_id: str
|
|
3675
|
+
The id of the request object.
|
|
3676
|
+
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
|
3677
|
+
|
|
3678
|
+
:returns: :class:`ObjectPermissions`
|
|
3679
|
+
"""
|
|
3680
|
+
body = {}
|
|
3681
|
+
if access_control_list is not None:
|
|
3682
|
+
body["access_control_list"] = [v.as_dict() for v in access_control_list]
|
|
3683
|
+
headers = {
|
|
3684
|
+
"Accept": "application/json",
|
|
3685
|
+
"Content-Type": "application/json",
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
res = self._api.do(
|
|
3689
|
+
"PATCH", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers
|
|
3690
|
+
)
|
|
3691
|
+
return ObjectPermissions.from_dict(res)
|
|
3692
|
+
|
|
3693
|
+
|
|
3694
|
+
class ServicePrincipalsV2API:
|
|
3695
|
+
"""Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.
|
|
3696
|
+
Databricks recommends creating service principals to run production jobs or modify production data. If all
|
|
3697
|
+
processes that act on production data run with service principals, interactive users do not need any
|
|
3698
|
+
write, delete, or modify privileges in production. This eliminates the risk of a user overwriting
|
|
3699
|
+
production data by accident."""
|
|
3700
|
+
|
|
3701
|
+
def __init__(self, api_client):
|
|
3702
|
+
self._api = api_client
|
|
3703
|
+
|
|
3704
|
+
def create(
|
|
3705
|
+
self,
|
|
3706
|
+
*,
|
|
3707
|
+
active: Optional[bool] = None,
|
|
3708
|
+
application_id: Optional[str] = None,
|
|
3709
|
+
display_name: Optional[str] = None,
|
|
3710
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
3711
|
+
external_id: Optional[str] = None,
|
|
3712
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
3713
|
+
id: Optional[str] = None,
|
|
3714
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3715
|
+
schemas: Optional[List[ServicePrincipalSchema]] = None,
|
|
3716
|
+
) -> ServicePrincipal:
|
|
3717
|
+
"""Creates a new service principal in the Databricks workspace.
|
|
3718
|
+
|
|
3719
|
+
:param active: bool (optional)
|
|
3720
|
+
If this user is active
|
|
3721
|
+
:param application_id: str (optional)
|
|
3722
|
+
UUID relating to the service principal
|
|
3723
|
+
:param display_name: str (optional)
|
|
3724
|
+
String that represents a concatenation of given and family names.
|
|
3725
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3726
|
+
Entitlements assigned to the service principal. See [assigning entitlements] for a full list of
|
|
3727
|
+
supported values.
|
|
3728
|
+
|
|
3729
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3730
|
+
:param external_id: str (optional)
|
|
3731
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
3732
|
+
:param id: str (optional)
|
|
3733
|
+
Databricks service principal ID.
|
|
3734
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3735
|
+
Corresponds to AWS instance profile/arn role.
|
|
3736
|
+
:param schemas: List[:class:`ServicePrincipalSchema`] (optional)
|
|
3737
|
+
The schema of the List response.
|
|
3738
|
+
|
|
3739
|
+
:returns: :class:`ServicePrincipal`
|
|
3740
|
+
"""
|
|
3741
|
+
body = {}
|
|
3742
|
+
if active is not None:
|
|
3743
|
+
body["active"] = active
|
|
3744
|
+
if application_id is not None:
|
|
3745
|
+
body["applicationId"] = application_id
|
|
3746
|
+
if display_name is not None:
|
|
3747
|
+
body["displayName"] = display_name
|
|
3748
|
+
if entitlements is not None:
|
|
3749
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
3750
|
+
if external_id is not None:
|
|
3751
|
+
body["externalId"] = external_id
|
|
3752
|
+
if groups is not None:
|
|
3753
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
3754
|
+
if id is not None:
|
|
3755
|
+
body["id"] = id
|
|
3756
|
+
if roles is not None:
|
|
3757
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
3758
|
+
if schemas is not None:
|
|
3759
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3760
|
+
headers = {
|
|
3761
|
+
"Accept": "application/json",
|
|
3762
|
+
"Content-Type": "application/json",
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
res = self._api.do("POST", "/api/2.0/preview/scim/v2/ServicePrincipals", body=body, headers=headers)
|
|
3766
|
+
return ServicePrincipal.from_dict(res)
|
|
3767
|
+
|
|
3768
|
+
def delete(self, id: str):
|
|
3769
|
+
"""Delete a single service principal in the Databricks workspace.
|
|
3770
|
+
|
|
3771
|
+
:param id: str
|
|
3772
|
+
Unique ID for a service principal in the Databricks workspace.
|
|
3773
|
+
|
|
3774
|
+
|
|
3775
|
+
"""
|
|
3776
|
+
|
|
3777
|
+
headers = {}
|
|
3778
|
+
|
|
3779
|
+
self._api.do("DELETE", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", headers=headers)
|
|
3780
|
+
|
|
3781
|
+
def get(self, id: str) -> ServicePrincipal:
|
|
3782
|
+
"""Gets the details for a single service principal define in the Databricks workspace.
|
|
3783
|
+
|
|
3784
|
+
:param id: str
|
|
3785
|
+
Unique ID for a service principal in the Databricks workspace.
|
|
3786
|
+
|
|
3787
|
+
:returns: :class:`ServicePrincipal`
|
|
3788
|
+
"""
|
|
3789
|
+
|
|
3790
|
+
headers = {
|
|
3791
|
+
"Accept": "application/json",
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
res = self._api.do("GET", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", headers=headers)
|
|
3795
|
+
return ServicePrincipal.from_dict(res)
|
|
3796
|
+
|
|
3797
|
+
def list(
|
|
3798
|
+
self,
|
|
3799
|
+
*,
|
|
3800
|
+
attributes: Optional[str] = None,
|
|
3801
|
+
count: Optional[int] = None,
|
|
3802
|
+
excluded_attributes: Optional[str] = None,
|
|
3803
|
+
filter: Optional[str] = None,
|
|
3804
|
+
sort_by: Optional[str] = None,
|
|
3805
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
3806
|
+
start_index: Optional[int] = None,
|
|
3807
|
+
) -> Iterator[ServicePrincipal]:
|
|
3808
|
+
"""Gets the set of service principals associated with a Databricks workspace.
|
|
3809
|
+
|
|
3810
|
+
:param attributes: str (optional)
|
|
3811
|
+
Comma-separated list of attributes to return in response.
|
|
3812
|
+
:param count: int (optional)
|
|
3813
|
+
Desired number of results per page.
|
|
3814
|
+
:param excluded_attributes: str (optional)
|
|
3815
|
+
Comma-separated list of attributes to exclude in response.
|
|
3816
|
+
:param filter: str (optional)
|
|
3817
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
3818
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
3819
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
3820
|
+
only support simple expressions.
|
|
3821
|
+
|
|
3822
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
3823
|
+
:param sort_by: str (optional)
|
|
3824
|
+
Attribute to sort the results.
|
|
3825
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
3826
|
+
The order to sort the results.
|
|
3827
|
+
:param start_index: int (optional)
|
|
3828
|
+
Specifies the index of the first result. First item is number 1.
|
|
3829
|
+
|
|
3830
|
+
:returns: Iterator over :class:`ServicePrincipal`
|
|
3831
|
+
"""
|
|
3832
|
+
|
|
3833
|
+
query = {}
|
|
3834
|
+
if attributes is not None:
|
|
3835
|
+
query["attributes"] = attributes
|
|
3836
|
+
if count is not None:
|
|
3837
|
+
query["count"] = count
|
|
3838
|
+
if excluded_attributes is not None:
|
|
3839
|
+
query["excludedAttributes"] = excluded_attributes
|
|
3840
|
+
if filter is not None:
|
|
3841
|
+
query["filter"] = filter
|
|
3842
|
+
if sort_by is not None:
|
|
3843
|
+
query["sortBy"] = sort_by
|
|
3844
|
+
if sort_order is not None:
|
|
3845
|
+
query["sortOrder"] = sort_order.value
|
|
3846
|
+
if start_index is not None:
|
|
3847
|
+
query["startIndex"] = start_index
|
|
3848
|
+
headers = {
|
|
3849
|
+
"Accept": "application/json",
|
|
3850
|
+
}
|
|
3851
|
+
|
|
3852
|
+
query["startIndex"] = 1
|
|
3853
|
+
if "count" not in query:
|
|
3854
|
+
query["count"] = 10000
|
|
3855
|
+
while True:
|
|
3856
|
+
json = self._api.do("GET", "/api/2.0/preview/scim/v2/ServicePrincipals", query=query, headers=headers)
|
|
3857
|
+
if "Resources" in json:
|
|
3858
|
+
for v in json["Resources"]:
|
|
3859
|
+
yield ServicePrincipal.from_dict(v)
|
|
3860
|
+
if "Resources" not in json or not json["Resources"]:
|
|
3861
|
+
return
|
|
3862
|
+
query["startIndex"] += len(json["Resources"])
|
|
3863
|
+
|
|
3864
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
3865
|
+
"""Partially updates the details of a single service principal in the Databricks workspace.
|
|
3866
|
+
|
|
3867
|
+
:param id: str
|
|
3868
|
+
Unique ID in the Databricks workspace.
|
|
3869
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
3870
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
3871
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
3872
|
+
|
|
3873
|
+
|
|
3874
|
+
"""
|
|
3875
|
+
body = {}
|
|
3876
|
+
if operations is not None:
|
|
3877
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
3878
|
+
if schemas is not None:
|
|
3879
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3880
|
+
headers = {
|
|
3881
|
+
"Accept": "application/json",
|
|
3882
|
+
"Content-Type": "application/json",
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
self._api.do("PATCH", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", body=body, headers=headers)
|
|
3886
|
+
|
|
3887
|
+
def update(
|
|
3888
|
+
self,
|
|
3889
|
+
id: str,
|
|
3890
|
+
*,
|
|
3891
|
+
active: Optional[bool] = None,
|
|
3892
|
+
application_id: Optional[str] = None,
|
|
3893
|
+
display_name: Optional[str] = None,
|
|
3894
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
3895
|
+
external_id: Optional[str] = None,
|
|
3896
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
3897
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3898
|
+
schemas: Optional[List[ServicePrincipalSchema]] = None,
|
|
3899
|
+
):
|
|
3900
|
+
"""Updates the details of a single service principal.
|
|
3901
|
+
|
|
3902
|
+
This action replaces the existing service principal with the same name.
|
|
3903
|
+
|
|
3904
|
+
:param id: str
|
|
3905
|
+
Databricks service principal ID.
|
|
3906
|
+
:param active: bool (optional)
|
|
3907
|
+
If this user is active
|
|
3908
|
+
:param application_id: str (optional)
|
|
3909
|
+
UUID relating to the service principal
|
|
3910
|
+
:param display_name: str (optional)
|
|
3911
|
+
String that represents a concatenation of given and family names.
|
|
3912
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3913
|
+
Entitlements assigned to the service principal. See [assigning entitlements] for a full list of
|
|
3914
|
+
supported values.
|
|
3915
|
+
|
|
3916
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3917
|
+
:param external_id: str (optional)
|
|
3918
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
3919
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3920
|
+
Corresponds to AWS instance profile/arn role.
|
|
3921
|
+
:param schemas: List[:class:`ServicePrincipalSchema`] (optional)
|
|
3922
|
+
The schema of the List response.
|
|
3923
|
+
|
|
3924
|
+
|
|
3925
|
+
"""
|
|
3926
|
+
body = {}
|
|
3927
|
+
if active is not None:
|
|
3928
|
+
body["active"] = active
|
|
3929
|
+
if application_id is not None:
|
|
3930
|
+
body["applicationId"] = application_id
|
|
3931
|
+
if display_name is not None:
|
|
3932
|
+
body["displayName"] = display_name
|
|
3933
|
+
if entitlements is not None:
|
|
3934
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
3935
|
+
if external_id is not None:
|
|
3936
|
+
body["externalId"] = external_id
|
|
3937
|
+
if groups is not None:
|
|
3938
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
3939
|
+
if roles is not None:
|
|
3940
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
3941
|
+
if schemas is not None:
|
|
3942
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3943
|
+
headers = {
|
|
3944
|
+
"Accept": "application/json",
|
|
3945
|
+
"Content-Type": "application/json",
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
self._api.do("PUT", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", body=body, headers=headers)
|
|
3949
|
+
|
|
3950
|
+
|
|
3951
|
+
class UsersV2API:
|
|
3952
|
+
"""User identities recognized by Databricks and represented by email addresses.
|
|
3953
|
+
|
|
3954
|
+
Databricks recommends using SCIM provisioning to sync users and groups automatically from your identity
|
|
3955
|
+
provider to your Databricks workspace. SCIM streamlines onboarding a new employee or team by using your
|
|
3956
|
+
identity provider to create users and groups in Databricks workspace and give them the proper level of
|
|
3957
|
+
access. When a user leaves your organization or no longer needs access to Databricks workspace, admins can
|
|
3958
|
+
terminate the user in your identity provider and that user’s account will also be removed from
|
|
3959
|
+
Databricks workspace. This ensures a consistent offboarding process and prevents unauthorized users from
|
|
3960
|
+
accessing sensitive data."""
|
|
3961
|
+
|
|
3962
|
+
def __init__(self, api_client):
|
|
3963
|
+
self._api = api_client
|
|
3964
|
+
|
|
3965
|
+
def create(
|
|
3966
|
+
self,
|
|
3967
|
+
*,
|
|
3968
|
+
active: Optional[bool] = None,
|
|
3969
|
+
display_name: Optional[str] = None,
|
|
3970
|
+
emails: Optional[List[ComplexValue]] = None,
|
|
3971
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
3972
|
+
external_id: Optional[str] = None,
|
|
3973
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
3974
|
+
id: Optional[str] = None,
|
|
3975
|
+
name: Optional[Name] = None,
|
|
3976
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
3977
|
+
schemas: Optional[List[UserSchema]] = None,
|
|
3978
|
+
user_name: Optional[str] = None,
|
|
3979
|
+
) -> User:
|
|
3980
|
+
"""Creates a new user in the Databricks workspace. This new user will also be added to the Databricks
|
|
3981
|
+
account.
|
|
3982
|
+
|
|
3983
|
+
:param active: bool (optional)
|
|
3984
|
+
If this user is active
|
|
3985
|
+
:param display_name: str (optional)
|
|
3986
|
+
String that represents a concatenation of given and family names. For example `John Smith`. This
|
|
3987
|
+
field cannot be updated through the Workspace SCIM APIs when [identity federation is enabled]. Use
|
|
3988
|
+
Account SCIM APIs to update `displayName`.
|
|
3989
|
+
|
|
3990
|
+
[identity federation is enabled]: https://docs.databricks.com/administration-guide/users-groups/best-practices.html#enable-identity-federation
|
|
3991
|
+
:param emails: List[:class:`ComplexValue`] (optional)
|
|
3992
|
+
All the emails associated with the Databricks user.
|
|
3993
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3994
|
+
Entitlements assigned to the user. See [assigning entitlements] for a full list of supported values.
|
|
3995
|
+
|
|
3996
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3997
|
+
:param external_id: str (optional)
|
|
3998
|
+
External ID is not currently supported. It is reserved for future use.
|
|
3999
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
4000
|
+
:param id: str (optional)
|
|
4001
|
+
Databricks user ID.
|
|
4002
|
+
:param name: :class:`Name` (optional)
|
|
4003
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
4004
|
+
Corresponds to AWS instance profile/arn role.
|
|
4005
|
+
:param schemas: List[:class:`UserSchema`] (optional)
|
|
4006
|
+
The schema of the user.
|
|
4007
|
+
:param user_name: str (optional)
|
|
4008
|
+
Email address of the Databricks user.
|
|
4009
|
+
|
|
4010
|
+
:returns: :class:`User`
|
|
4011
|
+
"""
|
|
4012
|
+
body = {}
|
|
4013
|
+
if active is not None:
|
|
4014
|
+
body["active"] = active
|
|
4015
|
+
if display_name is not None:
|
|
4016
|
+
body["displayName"] = display_name
|
|
4017
|
+
if emails is not None:
|
|
4018
|
+
body["emails"] = [v.as_dict() for v in emails]
|
|
4019
|
+
if entitlements is not None:
|
|
4020
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
4021
|
+
if external_id is not None:
|
|
4022
|
+
body["externalId"] = external_id
|
|
4023
|
+
if groups is not None:
|
|
4024
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
4025
|
+
if id is not None:
|
|
4026
|
+
body["id"] = id
|
|
4027
|
+
if name is not None:
|
|
4028
|
+
body["name"] = name.as_dict()
|
|
4029
|
+
if roles is not None:
|
|
4030
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
4031
|
+
if schemas is not None:
|
|
4032
|
+
body["schemas"] = [v.value for v in schemas]
|
|
4033
|
+
if user_name is not None:
|
|
4034
|
+
body["userName"] = user_name
|
|
4035
|
+
headers = {
|
|
4036
|
+
"Accept": "application/json",
|
|
4037
|
+
"Content-Type": "application/json",
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
res = self._api.do("POST", "/api/2.0/preview/scim/v2/Users", body=body, headers=headers)
|
|
4041
|
+
return User.from_dict(res)
|
|
4042
|
+
|
|
4043
|
+
def delete(self, id: str):
|
|
4044
|
+
"""Deletes a user. Deleting a user from a Databricks workspace also removes objects associated with the
|
|
4045
|
+
user.
|
|
4046
|
+
|
|
4047
|
+
:param id: str
|
|
4048
|
+
Unique ID for a user in the Databricks workspace.
|
|
4049
|
+
|
|
4050
|
+
|
|
4051
|
+
"""
|
|
4052
|
+
|
|
4053
|
+
headers = {}
|
|
4054
|
+
|
|
4055
|
+
self._api.do("DELETE", f"/api/2.0/preview/scim/v2/Users/{id}", headers=headers)
|
|
4056
|
+
|
|
4057
|
+
def get(
|
|
4058
|
+
self,
|
|
4059
|
+
id: str,
|
|
4060
|
+
*,
|
|
4061
|
+
attributes: Optional[str] = None,
|
|
4062
|
+
count: Optional[int] = None,
|
|
4063
|
+
excluded_attributes: Optional[str] = None,
|
|
4064
|
+
filter: Optional[str] = None,
|
|
4065
|
+
sort_by: Optional[str] = None,
|
|
4066
|
+
sort_order: Optional[GetSortOrder] = None,
|
|
4067
|
+
start_index: Optional[int] = None,
|
|
4068
|
+
) -> User:
|
|
4069
|
+
"""Gets information for a specific user in Databricks workspace.
|
|
4070
|
+
|
|
4071
|
+
:param id: str
|
|
4072
|
+
Unique ID for a user in the Databricks workspace.
|
|
4073
|
+
:param attributes: str (optional)
|
|
4074
|
+
Comma-separated list of attributes to return in response.
|
|
4075
|
+
:param count: int (optional)
|
|
4076
|
+
Desired number of results per page.
|
|
4077
|
+
:param excluded_attributes: str (optional)
|
|
4078
|
+
Comma-separated list of attributes to exclude in response.
|
|
4079
|
+
:param filter: str (optional)
|
|
4080
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
4081
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
4082
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
4083
|
+
only support simple expressions.
|
|
4084
|
+
|
|
4085
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
4086
|
+
:param sort_by: str (optional)
|
|
4087
|
+
Attribute to sort the results. Multi-part paths are supported. For example, `userName`,
|
|
4088
|
+
`name.givenName`, and `emails`.
|
|
4089
|
+
:param sort_order: :class:`GetSortOrder` (optional)
|
|
4090
|
+
The order to sort the results.
|
|
4091
|
+
:param start_index: int (optional)
|
|
4092
|
+
Specifies the index of the first result. First item is number 1.
|
|
4093
|
+
|
|
4094
|
+
:returns: :class:`User`
|
|
4095
|
+
"""
|
|
4096
|
+
|
|
4097
|
+
query = {}
|
|
4098
|
+
if attributes is not None:
|
|
4099
|
+
query["attributes"] = attributes
|
|
4100
|
+
if count is not None:
|
|
4101
|
+
query["count"] = count
|
|
4102
|
+
if excluded_attributes is not None:
|
|
4103
|
+
query["excludedAttributes"] = excluded_attributes
|
|
4104
|
+
if filter is not None:
|
|
4105
|
+
query["filter"] = filter
|
|
4106
|
+
if sort_by is not None:
|
|
4107
|
+
query["sortBy"] = sort_by
|
|
4108
|
+
if sort_order is not None:
|
|
4109
|
+
query["sortOrder"] = sort_order.value
|
|
4110
|
+
if start_index is not None:
|
|
4111
|
+
query["startIndex"] = start_index
|
|
4112
|
+
headers = {
|
|
4113
|
+
"Accept": "application/json",
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
res = self._api.do("GET", f"/api/2.0/preview/scim/v2/Users/{id}", query=query, headers=headers)
|
|
4117
|
+
return User.from_dict(res)
|
|
4118
|
+
|
|
4119
|
+
def get_permission_levels(self) -> GetPasswordPermissionLevelsResponse:
|
|
4120
|
+
"""Gets the permission levels that a user can have on an object.
|
|
4121
|
+
|
|
4122
|
+
|
|
4123
|
+
:returns: :class:`GetPasswordPermissionLevelsResponse`
|
|
4124
|
+
"""
|
|
4125
|
+
|
|
4126
|
+
headers = {
|
|
4127
|
+
"Accept": "application/json",
|
|
4128
|
+
}
|
|
4129
|
+
|
|
4130
|
+
res = self._api.do("GET", "/api/2.0/permissions/authorization/passwords/permissionLevels", headers=headers)
|
|
4131
|
+
return GetPasswordPermissionLevelsResponse.from_dict(res)
|
|
4132
|
+
|
|
4133
|
+
def get_permissions(self) -> PasswordPermissions:
|
|
4134
|
+
"""Gets the permissions of all passwords. Passwords can inherit permissions from their root object.
|
|
4135
|
+
|
|
4136
|
+
|
|
4137
|
+
:returns: :class:`PasswordPermissions`
|
|
4138
|
+
"""
|
|
4139
|
+
|
|
4140
|
+
headers = {
|
|
4141
|
+
"Accept": "application/json",
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
res = self._api.do("GET", "/api/2.0/permissions/authorization/passwords", headers=headers)
|
|
4145
|
+
return PasswordPermissions.from_dict(res)
|
|
4146
|
+
|
|
4147
|
+
def list(
|
|
4148
|
+
self,
|
|
4149
|
+
*,
|
|
4150
|
+
attributes: Optional[str] = None,
|
|
4151
|
+
count: Optional[int] = None,
|
|
4152
|
+
excluded_attributes: Optional[str] = None,
|
|
4153
|
+
filter: Optional[str] = None,
|
|
4154
|
+
sort_by: Optional[str] = None,
|
|
4155
|
+
sort_order: Optional[ListSortOrder] = None,
|
|
4156
|
+
start_index: Optional[int] = None,
|
|
4157
|
+
) -> Iterator[User]:
|
|
4158
|
+
"""Gets details for all the users associated with a Databricks workspace.
|
|
4159
|
+
|
|
4160
|
+
:param attributes: str (optional)
|
|
4161
|
+
Comma-separated list of attributes to return in response.
|
|
4162
|
+
:param count: int (optional)
|
|
4163
|
+
Desired number of results per page.
|
|
4164
|
+
:param excluded_attributes: str (optional)
|
|
4165
|
+
Comma-separated list of attributes to exclude in response.
|
|
4166
|
+
:param filter: str (optional)
|
|
4167
|
+
Query by which the results have to be filtered. Supported operators are equals(`eq`),
|
|
4168
|
+
contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be
|
|
4169
|
+
formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently
|
|
4170
|
+
only support simple expressions.
|
|
4171
|
+
|
|
4172
|
+
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
4173
|
+
:param sort_by: str (optional)
|
|
4174
|
+
Attribute to sort the results. Multi-part paths are supported. For example, `userName`,
|
|
4175
|
+
`name.givenName`, and `emails`.
|
|
4176
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
4177
|
+
The order to sort the results.
|
|
4178
|
+
:param start_index: int (optional)
|
|
4179
|
+
Specifies the index of the first result. First item is number 1.
|
|
4180
|
+
|
|
4181
|
+
:returns: Iterator over :class:`User`
|
|
4182
|
+
"""
|
|
4183
|
+
|
|
4184
|
+
query = {}
|
|
4185
|
+
if attributes is not None:
|
|
4186
|
+
query["attributes"] = attributes
|
|
4187
|
+
if count is not None:
|
|
4188
|
+
query["count"] = count
|
|
4189
|
+
if excluded_attributes is not None:
|
|
4190
|
+
query["excludedAttributes"] = excluded_attributes
|
|
4191
|
+
if filter is not None:
|
|
4192
|
+
query["filter"] = filter
|
|
4193
|
+
if sort_by is not None:
|
|
4194
|
+
query["sortBy"] = sort_by
|
|
4195
|
+
if sort_order is not None:
|
|
4196
|
+
query["sortOrder"] = sort_order.value
|
|
4197
|
+
if start_index is not None:
|
|
4198
|
+
query["startIndex"] = start_index
|
|
4199
|
+
headers = {
|
|
4200
|
+
"Accept": "application/json",
|
|
4201
|
+
}
|
|
4202
|
+
|
|
4203
|
+
query["startIndex"] = 1
|
|
4204
|
+
if "count" not in query:
|
|
4205
|
+
query["count"] = 10000
|
|
4206
|
+
while True:
|
|
4207
|
+
json = self._api.do("GET", "/api/2.0/preview/scim/v2/Users", query=query, headers=headers)
|
|
4208
|
+
if "Resources" in json:
|
|
4209
|
+
for v in json["Resources"]:
|
|
4210
|
+
yield User.from_dict(v)
|
|
4211
|
+
if "Resources" not in json or not json["Resources"]:
|
|
4212
|
+
return
|
|
4213
|
+
query["startIndex"] += len(json["Resources"])
|
|
4214
|
+
|
|
4215
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
4216
|
+
"""Partially updates a user resource by applying the supplied operations on specific user attributes.
|
|
4217
|
+
|
|
4218
|
+
:param id: str
|
|
4219
|
+
Unique ID in the Databricks workspace.
|
|
4220
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
4221
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
4222
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
4223
|
+
|
|
4224
|
+
|
|
4225
|
+
"""
|
|
4226
|
+
body = {}
|
|
4227
|
+
if operations is not None:
|
|
4228
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
4229
|
+
if schemas is not None:
|
|
4230
|
+
body["schemas"] = [v.value for v in schemas]
|
|
4231
|
+
headers = {
|
|
4232
|
+
"Accept": "application/json",
|
|
4233
|
+
"Content-Type": "application/json",
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Users/{id}", body=body, headers=headers)
|
|
4237
|
+
|
|
4238
|
+
def set_permissions(
|
|
4239
|
+
self, *, access_control_list: Optional[List[PasswordAccessControlRequest]] = None
|
|
4240
|
+
) -> PasswordPermissions:
|
|
4241
|
+
"""Sets permissions on an object, replacing existing permissions if they exist. Deletes all direct
|
|
4242
|
+
permissions if none are specified. Objects can inherit permissions from their root object.
|
|
4243
|
+
|
|
4244
|
+
:param access_control_list: List[:class:`PasswordAccessControlRequest`] (optional)
|
|
4245
|
+
|
|
4246
|
+
:returns: :class:`PasswordPermissions`
|
|
4247
|
+
"""
|
|
4248
|
+
body = {}
|
|
4249
|
+
if access_control_list is not None:
|
|
4250
|
+
body["access_control_list"] = [v.as_dict() for v in access_control_list]
|
|
4251
|
+
headers = {
|
|
4252
|
+
"Accept": "application/json",
|
|
4253
|
+
"Content-Type": "application/json",
|
|
4254
|
+
}
|
|
4255
|
+
|
|
4256
|
+
res = self._api.do("PUT", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers)
|
|
4257
|
+
return PasswordPermissions.from_dict(res)
|
|
4258
|
+
|
|
4259
|
+
def update(
|
|
4260
|
+
self,
|
|
4261
|
+
id: str,
|
|
4262
|
+
*,
|
|
4263
|
+
active: Optional[bool] = None,
|
|
4264
|
+
display_name: Optional[str] = None,
|
|
4265
|
+
emails: Optional[List[ComplexValue]] = None,
|
|
4266
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
4267
|
+
external_id: Optional[str] = None,
|
|
4268
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
4269
|
+
name: Optional[Name] = None,
|
|
4270
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
4271
|
+
schemas: Optional[List[UserSchema]] = None,
|
|
4272
|
+
user_name: Optional[str] = None,
|
|
4273
|
+
):
|
|
4274
|
+
"""Replaces a user's information with the data supplied in request.
|
|
4275
|
+
|
|
4276
|
+
:param id: str
|
|
4277
|
+
Databricks user ID.
|
|
4278
|
+
:param active: bool (optional)
|
|
4279
|
+
If this user is active
|
|
4280
|
+
:param display_name: str (optional)
|
|
4281
|
+
String that represents a concatenation of given and family names. For example `John Smith`. This
|
|
4282
|
+
field cannot be updated through the Workspace SCIM APIs when [identity federation is enabled]. Use
|
|
4283
|
+
Account SCIM APIs to update `displayName`.
|
|
4284
|
+
|
|
4285
|
+
[identity federation is enabled]: https://docs.databricks.com/administration-guide/users-groups/best-practices.html#enable-identity-federation
|
|
4286
|
+
:param emails: List[:class:`ComplexValue`] (optional)
|
|
4287
|
+
All the emails associated with the Databricks user.
|
|
4288
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
4289
|
+
Entitlements assigned to the user. See [assigning entitlements] for a full list of supported values.
|
|
4290
|
+
|
|
4291
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
4292
|
+
:param external_id: str (optional)
|
|
4293
|
+
External ID is not currently supported. It is reserved for future use.
|
|
4294
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
4295
|
+
:param name: :class:`Name` (optional)
|
|
4296
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
4297
|
+
Corresponds to AWS instance profile/arn role.
|
|
4298
|
+
:param schemas: List[:class:`UserSchema`] (optional)
|
|
4299
|
+
The schema of the user.
|
|
4300
|
+
:param user_name: str (optional)
|
|
4301
|
+
Email address of the Databricks user.
|
|
4302
|
+
|
|
4303
|
+
|
|
4304
|
+
"""
|
|
4305
|
+
body = {}
|
|
4306
|
+
if active is not None:
|
|
4307
|
+
body["active"] = active
|
|
4308
|
+
if display_name is not None:
|
|
4309
|
+
body["displayName"] = display_name
|
|
4310
|
+
if emails is not None:
|
|
4311
|
+
body["emails"] = [v.as_dict() for v in emails]
|
|
4312
|
+
if entitlements is not None:
|
|
4313
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
4314
|
+
if external_id is not None:
|
|
4315
|
+
body["externalId"] = external_id
|
|
4316
|
+
if groups is not None:
|
|
4317
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
4318
|
+
if name is not None:
|
|
4319
|
+
body["name"] = name.as_dict()
|
|
4320
|
+
if roles is not None:
|
|
4321
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
4322
|
+
if schemas is not None:
|
|
4323
|
+
body["schemas"] = [v.value for v in schemas]
|
|
4324
|
+
if user_name is not None:
|
|
4325
|
+
body["userName"] = user_name
|
|
4326
|
+
headers = {
|
|
4327
|
+
"Accept": "application/json",
|
|
4328
|
+
"Content-Type": "application/json",
|
|
4329
|
+
}
|
|
4330
|
+
|
|
4331
|
+
self._api.do("PUT", f"/api/2.0/preview/scim/v2/Users/{id}", body=body, headers=headers)
|
|
4332
|
+
|
|
4333
|
+
def update_permissions(
|
|
4334
|
+
self, *, access_control_list: Optional[List[PasswordAccessControlRequest]] = None
|
|
4335
|
+
) -> PasswordPermissions:
|
|
4336
|
+
"""Updates the permissions on all passwords. Passwords can inherit permissions from their root object.
|
|
4337
|
+
|
|
4338
|
+
:param access_control_list: List[:class:`PasswordAccessControlRequest`] (optional)
|
|
4339
|
+
|
|
4340
|
+
:returns: :class:`PasswordPermissions`
|
|
4341
|
+
"""
|
|
4342
|
+
body = {}
|
|
4343
|
+
if access_control_list is not None:
|
|
4344
|
+
body["access_control_list"] = [v.as_dict() for v in access_control_list]
|
|
4345
|
+
headers = {
|
|
4346
|
+
"Accept": "application/json",
|
|
4347
|
+
"Content-Type": "application/json",
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
res = self._api.do("PATCH", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers)
|
|
4351
|
+
return PasswordPermissions.from_dict(res)
|
|
4352
|
+
|
|
4353
|
+
|
|
4354
|
+
class WorkspaceAssignmentAPI:
|
|
4355
|
+
"""The Workspace Permission Assignment API allows you to manage workspace permissions for principals in your
|
|
4356
|
+
account."""
|
|
4357
|
+
|
|
4358
|
+
def __init__(self, api_client):
|
|
4359
|
+
self._api = api_client
|
|
4360
|
+
|
|
4361
|
+
def delete(self, workspace_id: int, principal_id: int):
|
|
4362
|
+
"""Deletes the workspace permissions assignment in a given account and workspace for the specified
|
|
4363
|
+
principal.
|
|
4364
|
+
|
|
4365
|
+
:param workspace_id: int
|
|
4366
|
+
The workspace ID for the account.
|
|
4367
|
+
:param principal_id: int
|
|
4368
|
+
The ID of the user, service principal, or group.
|
|
4369
|
+
|
|
4370
|
+
|
|
4371
|
+
"""
|
|
4372
|
+
|
|
4373
|
+
headers = {
|
|
4374
|
+
"Accept": "application/json",
|
|
4375
|
+
}
|
|
4376
|
+
|
|
4377
|
+
self._api.do(
|
|
4378
|
+
"DELETE",
|
|
4379
|
+
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}",
|
|
4380
|
+
headers=headers,
|
|
4381
|
+
)
|
|
4382
|
+
|
|
4383
|
+
def get(self, workspace_id: int) -> WorkspacePermissions:
|
|
4384
|
+
"""Get an array of workspace permissions for the specified account and workspace.
|
|
4385
|
+
|
|
4386
|
+
:param workspace_id: int
|
|
4387
|
+
The workspace ID.
|
|
4388
|
+
|
|
4389
|
+
:returns: :class:`WorkspacePermissions`
|
|
4390
|
+
"""
|
|
4391
|
+
|
|
4392
|
+
headers = {
|
|
4393
|
+
"Accept": "application/json",
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
res = self._api.do(
|
|
4397
|
+
"GET",
|
|
4398
|
+
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/permissions",
|
|
4399
|
+
headers=headers,
|
|
4400
|
+
)
|
|
4401
|
+
return WorkspacePermissions.from_dict(res)
|
|
4402
|
+
|
|
4403
|
+
def list(self, workspace_id: int) -> Iterator[PermissionAssignment]:
|
|
4404
|
+
"""Get the permission assignments for the specified Databricks account and Databricks workspace.
|
|
4405
|
+
|
|
4406
|
+
:param workspace_id: int
|
|
4407
|
+
The workspace ID for the account.
|
|
4408
|
+
|
|
4409
|
+
:returns: Iterator over :class:`PermissionAssignment`
|
|
4410
|
+
"""
|
|
4411
|
+
|
|
4412
|
+
headers = {
|
|
4413
|
+
"Accept": "application/json",
|
|
4414
|
+
}
|
|
4415
|
+
|
|
4416
|
+
json = self._api.do(
|
|
4417
|
+
"GET",
|
|
4418
|
+
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments",
|
|
4419
|
+
headers=headers,
|
|
4420
|
+
)
|
|
4421
|
+
parsed = PermissionAssignments.from_dict(json).permission_assignments
|
|
4422
|
+
return parsed if parsed is not None else []
|
|
4423
|
+
|
|
4424
|
+
def update(
|
|
4425
|
+
self, workspace_id: int, principal_id: int, *, permissions: Optional[List[WorkspacePermission]] = None
|
|
4426
|
+
) -> PermissionAssignment:
|
|
4427
|
+
"""Creates or updates the workspace permissions assignment in a given account and workspace for the
|
|
4428
|
+
specified principal.
|
|
4429
|
+
|
|
4430
|
+
:param workspace_id: int
|
|
4431
|
+
The workspace ID.
|
|
4432
|
+
:param principal_id: int
|
|
4433
|
+
The ID of the user, service principal, or group.
|
|
4434
|
+
:param permissions: List[:class:`WorkspacePermission`] (optional)
|
|
4435
|
+
Array of permissions assignments to update on the workspace. Valid values are "USER" and "ADMIN"
|
|
4436
|
+
(case-sensitive). If both "USER" and "ADMIN" are provided, "ADMIN" takes precedence. Other values
|
|
4437
|
+
will be ignored. Note that excluding this field, or providing unsupported values, will have the same
|
|
4438
|
+
effect as providing an empty list, which will result in the deletion of all permissions for the
|
|
4439
|
+
principal.
|
|
4440
|
+
|
|
4441
|
+
:returns: :class:`PermissionAssignment`
|
|
4442
|
+
"""
|
|
4443
|
+
body = {}
|
|
4444
|
+
if permissions is not None:
|
|
4445
|
+
body["permissions"] = [v.value for v in permissions]
|
|
4446
|
+
headers = {
|
|
4447
|
+
"Accept": "application/json",
|
|
4448
|
+
"Content-Type": "application/json",
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
res = self._api.do(
|
|
4452
|
+
"PUT",
|
|
4453
|
+
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}",
|
|
4454
|
+
body=body,
|
|
4455
|
+
headers=headers,
|
|
4456
|
+
)
|
|
4457
|
+
return PermissionAssignment.from_dict(res)
|
|
4458
|
+
|
|
4459
|
+
|
|
2080
4460
|
class AccountGroupsAPI:
|
|
2081
4461
|
"""Groups simplify identity management, making it easier to assign access to Databricks account, data, and
|
|
2082
4462
|
other securable objects.
|
|
@@ -2193,9 +4573,7 @@ class AccountGroupsAPI:
|
|
|
2193
4573
|
sort_order: Optional[ListSortOrder] = None,
|
|
2194
4574
|
start_index: Optional[int] = None,
|
|
2195
4575
|
) -> Iterator[Group]:
|
|
2196
|
-
"""Gets all details of the groups associated with the Databricks account.
|
|
2197
|
-
will not return members. Instead, members should be retrieved by iterating through `Get group
|
|
2198
|
-
details`.
|
|
4576
|
+
"""Gets all details of the groups associated with the Databricks account.
|
|
2199
4577
|
|
|
2200
4578
|
:param attributes: str (optional)
|
|
2201
4579
|
Comma-separated list of attributes to return in response.
|
|
@@ -2971,27 +5349,6 @@ class AccountUsersAPI:
|
|
|
2971
5349
|
self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers)
|
|
2972
5350
|
|
|
2973
5351
|
|
|
2974
|
-
class CurrentUserAPI:
|
|
2975
|
-
"""This API allows retrieving information about currently authenticated user or service principal."""
|
|
2976
|
-
|
|
2977
|
-
def __init__(self, api_client):
|
|
2978
|
-
self._api = api_client
|
|
2979
|
-
|
|
2980
|
-
def me(self) -> User:
|
|
2981
|
-
"""Get details about the current method caller's identity.
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
:returns: :class:`User`
|
|
2985
|
-
"""
|
|
2986
|
-
|
|
2987
|
-
headers = {
|
|
2988
|
-
"Accept": "application/json",
|
|
2989
|
-
}
|
|
2990
|
-
|
|
2991
|
-
res = self._api.do("GET", "/api/2.0/preview/scim/v2/Me", headers=headers)
|
|
2992
|
-
return User.from_dict(res)
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
5352
|
class GroupsAPI:
|
|
2996
5353
|
"""Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and
|
|
2997
5354
|
other securable objects.
|
|
@@ -3123,317 +5480,131 @@ class GroupsAPI:
|
|
|
3123
5480
|
[SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2
|
|
3124
5481
|
:param sort_by: str (optional)
|
|
3125
5482
|
Attribute to sort the results.
|
|
3126
|
-
:param sort_order: :class:`ListSortOrder` (optional)
|
|
3127
|
-
The order to sort the results.
|
|
3128
|
-
:param start_index: int (optional)
|
|
3129
|
-
Specifies the index of the first result. First item is number 1.
|
|
3130
|
-
|
|
3131
|
-
:returns: Iterator over :class:`Group`
|
|
3132
|
-
"""
|
|
3133
|
-
|
|
3134
|
-
query = {}
|
|
3135
|
-
if attributes is not None:
|
|
3136
|
-
query["attributes"] = attributes
|
|
3137
|
-
if count is not None:
|
|
3138
|
-
query["count"] = count
|
|
3139
|
-
if excluded_attributes is not None:
|
|
3140
|
-
query["excludedAttributes"] = excluded_attributes
|
|
3141
|
-
if filter is not None:
|
|
3142
|
-
query["filter"] = filter
|
|
3143
|
-
if sort_by is not None:
|
|
3144
|
-
query["sortBy"] = sort_by
|
|
3145
|
-
if sort_order is not None:
|
|
3146
|
-
query["sortOrder"] = sort_order.value
|
|
3147
|
-
if start_index is not None:
|
|
3148
|
-
query["startIndex"] = start_index
|
|
3149
|
-
headers = {
|
|
3150
|
-
"Accept": "application/json",
|
|
3151
|
-
}
|
|
3152
|
-
|
|
3153
|
-
# deduplicate items that may have been added during iteration
|
|
3154
|
-
seen = set()
|
|
3155
|
-
query["startIndex"] = 1
|
|
3156
|
-
if "count" not in query:
|
|
3157
|
-
query["count"] = 10000
|
|
3158
|
-
while True:
|
|
3159
|
-
json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers)
|
|
3160
|
-
if "Resources" in json:
|
|
3161
|
-
for v in json["Resources"]:
|
|
3162
|
-
i = v["id"]
|
|
3163
|
-
if i in seen:
|
|
3164
|
-
continue
|
|
3165
|
-
seen.add(i)
|
|
3166
|
-
yield Group.from_dict(v)
|
|
3167
|
-
if "Resources" not in json or not json["Resources"]:
|
|
3168
|
-
return
|
|
3169
|
-
query["startIndex"] += len(json["Resources"])
|
|
3170
|
-
|
|
3171
|
-
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
3172
|
-
"""Partially updates the details of a group.
|
|
3173
|
-
|
|
3174
|
-
:param id: str
|
|
3175
|
-
Unique ID in the Databricks workspace.
|
|
3176
|
-
:param operations: List[:class:`Patch`] (optional)
|
|
3177
|
-
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
3178
|
-
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
"""
|
|
3182
|
-
body = {}
|
|
3183
|
-
if operations is not None:
|
|
3184
|
-
body["Operations"] = [v.as_dict() for v in operations]
|
|
3185
|
-
if schemas is not None:
|
|
3186
|
-
body["schemas"] = [v.value for v in schemas]
|
|
3187
|
-
headers = {
|
|
3188
|
-
"Content-Type": "application/json",
|
|
3189
|
-
}
|
|
3190
|
-
|
|
3191
|
-
self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3192
|
-
|
|
3193
|
-
def update(
|
|
3194
|
-
self,
|
|
3195
|
-
id: str,
|
|
3196
|
-
*,
|
|
3197
|
-
display_name: Optional[str] = None,
|
|
3198
|
-
entitlements: Optional[List[ComplexValue]] = None,
|
|
3199
|
-
external_id: Optional[str] = None,
|
|
3200
|
-
groups: Optional[List[ComplexValue]] = None,
|
|
3201
|
-
members: Optional[List[ComplexValue]] = None,
|
|
3202
|
-
meta: Optional[ResourceMeta] = None,
|
|
3203
|
-
roles: Optional[List[ComplexValue]] = None,
|
|
3204
|
-
schemas: Optional[List[GroupSchema]] = None,
|
|
3205
|
-
):
|
|
3206
|
-
"""Updates the details of a group by replacing the entire group entity.
|
|
3207
|
-
|
|
3208
|
-
:param id: str
|
|
3209
|
-
Databricks group ID
|
|
3210
|
-
:param display_name: str (optional)
|
|
3211
|
-
String that represents a human-readable group name
|
|
3212
|
-
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
3213
|
-
Entitlements assigned to the group. See [assigning entitlements] for a full list of supported
|
|
3214
|
-
values.
|
|
3215
|
-
|
|
3216
|
-
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
3217
|
-
:param external_id: str (optional)
|
|
3218
|
-
:param groups: List[:class:`ComplexValue`] (optional)
|
|
3219
|
-
:param members: List[:class:`ComplexValue`] (optional)
|
|
3220
|
-
:param meta: :class:`ResourceMeta` (optional)
|
|
3221
|
-
Container for the group identifier. Workspace local versus account.
|
|
3222
|
-
:param roles: List[:class:`ComplexValue`] (optional)
|
|
3223
|
-
Corresponds to AWS instance profile/arn role.
|
|
3224
|
-
:param schemas: List[:class:`GroupSchema`] (optional)
|
|
3225
|
-
The schema of the group.
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
"""
|
|
3229
|
-
body = {}
|
|
3230
|
-
if display_name is not None:
|
|
3231
|
-
body["displayName"] = display_name
|
|
3232
|
-
if entitlements is not None:
|
|
3233
|
-
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
3234
|
-
if external_id is not None:
|
|
3235
|
-
body["externalId"] = external_id
|
|
3236
|
-
if groups is not None:
|
|
3237
|
-
body["groups"] = [v.as_dict() for v in groups]
|
|
3238
|
-
if members is not None:
|
|
3239
|
-
body["members"] = [v.as_dict() for v in members]
|
|
3240
|
-
if meta is not None:
|
|
3241
|
-
body["meta"] = meta.as_dict()
|
|
3242
|
-
if roles is not None:
|
|
3243
|
-
body["roles"] = [v.as_dict() for v in roles]
|
|
3244
|
-
if schemas is not None:
|
|
3245
|
-
body["schemas"] = [v.value for v in schemas]
|
|
3246
|
-
headers = {
|
|
3247
|
-
"Content-Type": "application/json",
|
|
3248
|
-
}
|
|
3249
|
-
|
|
3250
|
-
self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
class PermissionMigrationAPI:
|
|
3254
|
-
"""APIs for migrating acl permissions, used only by the ucx tool: https://github.com/databrickslabs/ucx"""
|
|
3255
|
-
|
|
3256
|
-
def __init__(self, api_client):
|
|
3257
|
-
self._api = api_client
|
|
3258
|
-
|
|
3259
|
-
def migrate_permissions(
|
|
3260
|
-
self,
|
|
3261
|
-
workspace_id: int,
|
|
3262
|
-
from_workspace_group_name: str,
|
|
3263
|
-
to_account_group_name: str,
|
|
3264
|
-
*,
|
|
3265
|
-
size: Optional[int] = None,
|
|
3266
|
-
) -> MigratePermissionsResponse:
|
|
3267
|
-
"""Migrate Permissions.
|
|
3268
|
-
|
|
3269
|
-
:param workspace_id: int
|
|
3270
|
-
WorkspaceId of the associated workspace where the permission migration will occur.
|
|
3271
|
-
:param from_workspace_group_name: str
|
|
3272
|
-
The name of the workspace group that permissions will be migrated from.
|
|
3273
|
-
:param to_account_group_name: str
|
|
3274
|
-
The name of the account group that permissions will be migrated to.
|
|
3275
|
-
:param size: int (optional)
|
|
3276
|
-
The maximum number of permissions that will be migrated.
|
|
3277
|
-
|
|
3278
|
-
:returns: :class:`MigratePermissionsResponse`
|
|
3279
|
-
"""
|
|
3280
|
-
body = {}
|
|
3281
|
-
if from_workspace_group_name is not None:
|
|
3282
|
-
body["from_workspace_group_name"] = from_workspace_group_name
|
|
3283
|
-
if size is not None:
|
|
3284
|
-
body["size"] = size
|
|
3285
|
-
if to_account_group_name is not None:
|
|
3286
|
-
body["to_account_group_name"] = to_account_group_name
|
|
3287
|
-
if workspace_id is not None:
|
|
3288
|
-
body["workspace_id"] = workspace_id
|
|
3289
|
-
headers = {
|
|
3290
|
-
"Accept": "application/json",
|
|
3291
|
-
"Content-Type": "application/json",
|
|
3292
|
-
}
|
|
3293
|
-
|
|
3294
|
-
res = self._api.do("POST", "/api/2.0/permissionmigration", body=body, headers=headers)
|
|
3295
|
-
return MigratePermissionsResponse.from_dict(res)
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
class PermissionsAPI:
|
|
3299
|
-
"""Permissions API are used to create read, write, edit, update and manage access for various users on
|
|
3300
|
-
different objects and endpoints. * **[Apps permissions](:service:apps)** — Manage which users can manage
|
|
3301
|
-
or use apps. * **[Cluster permissions](:service:clusters)** — Manage which users can manage, restart, or
|
|
3302
|
-
attach to clusters. * **[Cluster policy permissions](:service:clusterpolicies)** — Manage which users
|
|
3303
|
-
can use cluster policies. * **[Delta Live Tables pipeline permissions](:service:pipelines)** — Manage
|
|
3304
|
-
which users can view, manage, run, cancel, or own a Delta Live Tables pipeline. * **[Job
|
|
3305
|
-
permissions](:service:jobs)** — Manage which users can view, manage, trigger, cancel, or own a job. *
|
|
3306
|
-
**[MLflow experiment permissions](:service:experiments)** — Manage which users can read, edit, or manage
|
|
3307
|
-
MLflow experiments. * **[MLflow registered model permissions](:service:modelregistry)** — Manage which
|
|
3308
|
-
users can read, edit, or manage MLflow registered models. * **[Instance Pool
|
|
3309
|
-
permissions](:service:instancepools)** — Manage which users can manage or attach to pools. * **[Repo
|
|
3310
|
-
permissions](repos)** — Manage which users can read, run, edit, or manage a repo. * **[Serving endpoint
|
|
3311
|
-
permissions](:service:servingendpoints)** — Manage which users can view, query, or manage a serving
|
|
3312
|
-
endpoint. * **[SQL warehouse permissions](:service:warehouses)** — Manage which users can use or manage
|
|
3313
|
-
SQL warehouses. * **[Token permissions](:service:tokenmanagement)** — Manage which users can create or
|
|
3314
|
-
use tokens. * **[Workspace object permissions](:service:workspace)** — Manage which users can read, run,
|
|
3315
|
-
edit, or manage alerts, dbsql-dashboards, directories, files, notebooks and queries. For the mapping of
|
|
3316
|
-
the required permissions for specific actions or abilities and other important information, see [Access
|
|
3317
|
-
Control]. Note that to manage access control on service principals, use **[Account Access Control
|
|
3318
|
-
Proxy](:service:accountaccesscontrolproxy)**.
|
|
3319
|
-
|
|
3320
|
-
[Access Control]: https://docs.databricks.com/security/auth-authz/access-control/index.html"""
|
|
3321
|
-
|
|
3322
|
-
def __init__(self, api_client):
|
|
3323
|
-
self._api = api_client
|
|
3324
|
-
|
|
3325
|
-
def get(self, request_object_type: str, request_object_id: str) -> ObjectPermissions:
|
|
3326
|
-
"""Gets the permissions of an object. Objects can inherit permissions from their parent objects or root
|
|
3327
|
-
object.
|
|
3328
|
-
|
|
3329
|
-
:param request_object_type: str
|
|
3330
|
-
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3331
|
-
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3332
|
-
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3333
|
-
warehouses.
|
|
3334
|
-
:param request_object_id: str
|
|
3335
|
-
The id of the request object.
|
|
3336
|
-
|
|
3337
|
-
:returns: :class:`ObjectPermissions`
|
|
3338
|
-
"""
|
|
3339
|
-
|
|
3340
|
-
headers = {
|
|
3341
|
-
"Accept": "application/json",
|
|
3342
|
-
}
|
|
3343
|
-
|
|
3344
|
-
res = self._api.do("GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", headers=headers)
|
|
3345
|
-
return ObjectPermissions.from_dict(res)
|
|
3346
|
-
|
|
3347
|
-
def get_permission_levels(self, request_object_type: str, request_object_id: str) -> GetPermissionLevelsResponse:
|
|
3348
|
-
"""Gets the permission levels that a user can have on an object.
|
|
3349
|
-
|
|
3350
|
-
:param request_object_type: str
|
|
3351
|
-
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3352
|
-
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3353
|
-
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3354
|
-
warehouses.
|
|
3355
|
-
:param request_object_id: str
|
|
5483
|
+
:param sort_order: :class:`ListSortOrder` (optional)
|
|
5484
|
+
The order to sort the results.
|
|
5485
|
+
:param start_index: int (optional)
|
|
5486
|
+
Specifies the index of the first result. First item is number 1.
|
|
3356
5487
|
|
|
3357
|
-
:returns: :class:`
|
|
5488
|
+
:returns: Iterator over :class:`Group`
|
|
3358
5489
|
"""
|
|
3359
5490
|
|
|
5491
|
+
query = {}
|
|
5492
|
+
if attributes is not None:
|
|
5493
|
+
query["attributes"] = attributes
|
|
5494
|
+
if count is not None:
|
|
5495
|
+
query["count"] = count
|
|
5496
|
+
if excluded_attributes is not None:
|
|
5497
|
+
query["excludedAttributes"] = excluded_attributes
|
|
5498
|
+
if filter is not None:
|
|
5499
|
+
query["filter"] = filter
|
|
5500
|
+
if sort_by is not None:
|
|
5501
|
+
query["sortBy"] = sort_by
|
|
5502
|
+
if sort_order is not None:
|
|
5503
|
+
query["sortOrder"] = sort_order.value
|
|
5504
|
+
if start_index is not None:
|
|
5505
|
+
query["startIndex"] = start_index
|
|
3360
5506
|
headers = {
|
|
3361
5507
|
"Accept": "application/json",
|
|
3362
5508
|
}
|
|
3363
5509
|
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
5510
|
+
# deduplicate items that may have been added during iteration
|
|
5511
|
+
seen = set()
|
|
5512
|
+
query["startIndex"] = 1
|
|
5513
|
+
if "count" not in query:
|
|
5514
|
+
query["count"] = 10000
|
|
5515
|
+
while True:
|
|
5516
|
+
json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers)
|
|
5517
|
+
if "Resources" in json:
|
|
5518
|
+
for v in json["Resources"]:
|
|
5519
|
+
i = v["id"]
|
|
5520
|
+
if i in seen:
|
|
5521
|
+
continue
|
|
5522
|
+
seen.add(i)
|
|
5523
|
+
yield Group.from_dict(v)
|
|
5524
|
+
if "Resources" not in json or not json["Resources"]:
|
|
5525
|
+
return
|
|
5526
|
+
query["startIndex"] += len(json["Resources"])
|
|
3368
5527
|
|
|
3369
|
-
def
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
permissions if none are specified. Objects can inherit permissions from their parent objects or root
|
|
3378
|
-
object.
|
|
5528
|
+
def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None):
|
|
5529
|
+
"""Partially updates the details of a group.
|
|
5530
|
+
|
|
5531
|
+
:param id: str
|
|
5532
|
+
Unique ID in the Databricks workspace.
|
|
5533
|
+
:param operations: List[:class:`Patch`] (optional)
|
|
5534
|
+
:param schemas: List[:class:`PatchSchema`] (optional)
|
|
5535
|
+
The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"].
|
|
3379
5536
|
|
|
3380
|
-
:param request_object_type: str
|
|
3381
|
-
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3382
|
-
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3383
|
-
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3384
|
-
warehouses.
|
|
3385
|
-
:param request_object_id: str
|
|
3386
|
-
The id of the request object.
|
|
3387
|
-
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
|
3388
5537
|
|
|
3389
|
-
:returns: :class:`ObjectPermissions`
|
|
3390
5538
|
"""
|
|
3391
5539
|
body = {}
|
|
3392
|
-
if
|
|
3393
|
-
body["
|
|
5540
|
+
if operations is not None:
|
|
5541
|
+
body["Operations"] = [v.as_dict() for v in operations]
|
|
5542
|
+
if schemas is not None:
|
|
5543
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3394
5544
|
headers = {
|
|
3395
|
-
"Accept": "application/json",
|
|
3396
5545
|
"Content-Type": "application/json",
|
|
3397
5546
|
}
|
|
3398
5547
|
|
|
3399
|
-
|
|
3400
|
-
"PUT", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers
|
|
3401
|
-
)
|
|
3402
|
-
return ObjectPermissions.from_dict(res)
|
|
5548
|
+
self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3403
5549
|
|
|
3404
5550
|
def update(
|
|
3405
5551
|
self,
|
|
3406
|
-
|
|
3407
|
-
request_object_id: str,
|
|
5552
|
+
id: str,
|
|
3408
5553
|
*,
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
5554
|
+
display_name: Optional[str] = None,
|
|
5555
|
+
entitlements: Optional[List[ComplexValue]] = None,
|
|
5556
|
+
external_id: Optional[str] = None,
|
|
5557
|
+
groups: Optional[List[ComplexValue]] = None,
|
|
5558
|
+
members: Optional[List[ComplexValue]] = None,
|
|
5559
|
+
meta: Optional[ResourceMeta] = None,
|
|
5560
|
+
roles: Optional[List[ComplexValue]] = None,
|
|
5561
|
+
schemas: Optional[List[GroupSchema]] = None,
|
|
5562
|
+
):
|
|
5563
|
+
"""Updates the details of a group by replacing the entire group entity.
|
|
5564
|
+
|
|
5565
|
+
:param id: str
|
|
5566
|
+
Databricks group ID
|
|
5567
|
+
:param display_name: str (optional)
|
|
5568
|
+
String that represents a human-readable group name
|
|
5569
|
+
:param entitlements: List[:class:`ComplexValue`] (optional)
|
|
5570
|
+
Entitlements assigned to the group. See [assigning entitlements] for a full list of supported
|
|
5571
|
+
values.
|
|
5572
|
+
|
|
5573
|
+
[assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements
|
|
5574
|
+
:param external_id: str (optional)
|
|
5575
|
+
:param groups: List[:class:`ComplexValue`] (optional)
|
|
5576
|
+
:param members: List[:class:`ComplexValue`] (optional)
|
|
5577
|
+
:param meta: :class:`ResourceMeta` (optional)
|
|
5578
|
+
Container for the group identifier. Workspace local versus account.
|
|
5579
|
+
:param roles: List[:class:`ComplexValue`] (optional)
|
|
5580
|
+
Corresponds to AWS instance profile/arn role.
|
|
5581
|
+
:param schemas: List[:class:`GroupSchema`] (optional)
|
|
5582
|
+
The schema of the group.
|
|
3413
5583
|
|
|
3414
|
-
:param request_object_type: str
|
|
3415
|
-
The type of the request object. Can be one of the following: alerts, alertsv2, authorization,
|
|
3416
|
-
clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files,
|
|
3417
|
-
instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or
|
|
3418
|
-
warehouses.
|
|
3419
|
-
:param request_object_id: str
|
|
3420
|
-
The id of the request object.
|
|
3421
|
-
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
|
3422
5584
|
|
|
3423
|
-
:returns: :class:`ObjectPermissions`
|
|
3424
5585
|
"""
|
|
3425
5586
|
body = {}
|
|
3426
|
-
if
|
|
3427
|
-
body["
|
|
5587
|
+
if display_name is not None:
|
|
5588
|
+
body["displayName"] = display_name
|
|
5589
|
+
if entitlements is not None:
|
|
5590
|
+
body["entitlements"] = [v.as_dict() for v in entitlements]
|
|
5591
|
+
if external_id is not None:
|
|
5592
|
+
body["externalId"] = external_id
|
|
5593
|
+
if groups is not None:
|
|
5594
|
+
body["groups"] = [v.as_dict() for v in groups]
|
|
5595
|
+
if members is not None:
|
|
5596
|
+
body["members"] = [v.as_dict() for v in members]
|
|
5597
|
+
if meta is not None:
|
|
5598
|
+
body["meta"] = meta.as_dict()
|
|
5599
|
+
if roles is not None:
|
|
5600
|
+
body["roles"] = [v.as_dict() for v in roles]
|
|
5601
|
+
if schemas is not None:
|
|
5602
|
+
body["schemas"] = [v.value for v in schemas]
|
|
3428
5603
|
headers = {
|
|
3429
|
-
"Accept": "application/json",
|
|
3430
5604
|
"Content-Type": "application/json",
|
|
3431
5605
|
}
|
|
3432
5606
|
|
|
3433
|
-
|
|
3434
|
-
"PATCH", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers
|
|
3435
|
-
)
|
|
3436
|
-
return ObjectPermissions.from_dict(res)
|
|
5607
|
+
self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers)
|
|
3437
5608
|
|
|
3438
5609
|
|
|
3439
5610
|
class ServicePrincipalsAPI:
|
|
@@ -4102,109 +6273,3 @@ class UsersAPI:
|
|
|
4102
6273
|
|
|
4103
6274
|
res = self._api.do("PATCH", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers)
|
|
4104
6275
|
return PasswordPermissions.from_dict(res)
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
class WorkspaceAssignmentAPI:
|
|
4108
|
-
"""The Workspace Permission Assignment API allows you to manage workspace permissions for principals in your
|
|
4109
|
-
account."""
|
|
4110
|
-
|
|
4111
|
-
def __init__(self, api_client):
|
|
4112
|
-
self._api = api_client
|
|
4113
|
-
|
|
4114
|
-
def delete(self, workspace_id: int, principal_id: int):
|
|
4115
|
-
"""Deletes the workspace permissions assignment in a given account and workspace for the specified
|
|
4116
|
-
principal.
|
|
4117
|
-
|
|
4118
|
-
:param workspace_id: int
|
|
4119
|
-
The workspace ID for the account.
|
|
4120
|
-
:param principal_id: int
|
|
4121
|
-
The ID of the user, service principal, or group.
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
"""
|
|
4125
|
-
|
|
4126
|
-
headers = {
|
|
4127
|
-
"Accept": "application/json",
|
|
4128
|
-
}
|
|
4129
|
-
|
|
4130
|
-
self._api.do(
|
|
4131
|
-
"DELETE",
|
|
4132
|
-
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}",
|
|
4133
|
-
headers=headers,
|
|
4134
|
-
)
|
|
4135
|
-
|
|
4136
|
-
def get(self, workspace_id: int) -> WorkspacePermissions:
|
|
4137
|
-
"""Get an array of workspace permissions for the specified account and workspace.
|
|
4138
|
-
|
|
4139
|
-
:param workspace_id: int
|
|
4140
|
-
The workspace ID.
|
|
4141
|
-
|
|
4142
|
-
:returns: :class:`WorkspacePermissions`
|
|
4143
|
-
"""
|
|
4144
|
-
|
|
4145
|
-
headers = {
|
|
4146
|
-
"Accept": "application/json",
|
|
4147
|
-
}
|
|
4148
|
-
|
|
4149
|
-
res = self._api.do(
|
|
4150
|
-
"GET",
|
|
4151
|
-
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/permissions",
|
|
4152
|
-
headers=headers,
|
|
4153
|
-
)
|
|
4154
|
-
return WorkspacePermissions.from_dict(res)
|
|
4155
|
-
|
|
4156
|
-
def list(self, workspace_id: int) -> Iterator[PermissionAssignment]:
|
|
4157
|
-
"""Get the permission assignments for the specified Databricks account and Databricks workspace.
|
|
4158
|
-
|
|
4159
|
-
:param workspace_id: int
|
|
4160
|
-
The workspace ID for the account.
|
|
4161
|
-
|
|
4162
|
-
:returns: Iterator over :class:`PermissionAssignment`
|
|
4163
|
-
"""
|
|
4164
|
-
|
|
4165
|
-
headers = {
|
|
4166
|
-
"Accept": "application/json",
|
|
4167
|
-
}
|
|
4168
|
-
|
|
4169
|
-
json = self._api.do(
|
|
4170
|
-
"GET",
|
|
4171
|
-
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments",
|
|
4172
|
-
headers=headers,
|
|
4173
|
-
)
|
|
4174
|
-
parsed = PermissionAssignments.from_dict(json).permission_assignments
|
|
4175
|
-
return parsed if parsed is not None else []
|
|
4176
|
-
|
|
4177
|
-
def update(
|
|
4178
|
-
self, workspace_id: int, principal_id: int, *, permissions: Optional[List[WorkspacePermission]] = None
|
|
4179
|
-
) -> PermissionAssignment:
|
|
4180
|
-
"""Creates or updates the workspace permissions assignment in a given account and workspace for the
|
|
4181
|
-
specified principal.
|
|
4182
|
-
|
|
4183
|
-
:param workspace_id: int
|
|
4184
|
-
The workspace ID.
|
|
4185
|
-
:param principal_id: int
|
|
4186
|
-
The ID of the user, service principal, or group.
|
|
4187
|
-
:param permissions: List[:class:`WorkspacePermission`] (optional)
|
|
4188
|
-
Array of permissions assignments to update on the workspace. Valid values are "USER" and "ADMIN"
|
|
4189
|
-
(case-sensitive). If both "USER" and "ADMIN" are provided, "ADMIN" takes precedence. Other values
|
|
4190
|
-
will be ignored. Note that excluding this field, or providing unsupported values, will have the same
|
|
4191
|
-
effect as providing an empty list, which will result in the deletion of all permissions for the
|
|
4192
|
-
principal.
|
|
4193
|
-
|
|
4194
|
-
:returns: :class:`PermissionAssignment`
|
|
4195
|
-
"""
|
|
4196
|
-
body = {}
|
|
4197
|
-
if permissions is not None:
|
|
4198
|
-
body["permissions"] = [v.value for v in permissions]
|
|
4199
|
-
headers = {
|
|
4200
|
-
"Accept": "application/json",
|
|
4201
|
-
"Content-Type": "application/json",
|
|
4202
|
-
}
|
|
4203
|
-
|
|
4204
|
-
res = self._api.do(
|
|
4205
|
-
"PUT",
|
|
4206
|
-
f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}",
|
|
4207
|
-
body=body,
|
|
4208
|
-
headers=headers,
|
|
4209
|
-
)
|
|
4210
|
-
return PermissionAssignment.from_dict(res)
|