databricks-sdk 0.36.0__py3-none-any.whl → 0.37.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.

@@ -3,11 +3,15 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
+ import random
7
+ import time
6
8
  from dataclasses import dataclass
9
+ from datetime import timedelta
7
10
  from enum import Enum
8
- from typing import Dict, Iterator, List, Optional
11
+ from typing import Callable, Dict, Iterator, List, Optional
9
12
 
10
- from ._internal import _enum, _from_dict, _repeated_dict, _repeated_enum
13
+ from ..errors import OperationFailed
14
+ from ._internal import Wait, _enum, _from_dict, _repeated_dict, _repeated_enum
11
15
 
12
16
  _LOG = logging.getLogger('databricks.sdk')
13
17
 
@@ -310,6 +314,36 @@ class AwsCredentials:
310
314
  session_token=d.get('session_token', None))
311
315
 
312
316
 
317
+ @dataclass
318
+ class AwsIamRole:
319
+ """The AWS IAM role configuration"""
320
+
321
+ external_id: Optional[str] = None
322
+ """The external ID used in role assumption to prevent the confused deputy problem."""
323
+
324
+ role_arn: Optional[str] = None
325
+ """The Amazon Resource Name (ARN) of the AWS IAM role used to vend temporary credentials."""
326
+
327
+ unity_catalog_iam_arn: Optional[str] = None
328
+ """The Amazon Resource Name (ARN) of the AWS IAM user managed by Databricks. This is the identity
329
+ that is going to assume the AWS IAM role."""
330
+
331
+ def as_dict(self) -> dict:
332
+ """Serializes the AwsIamRole into a dictionary suitable for use as a JSON request body."""
333
+ body = {}
334
+ if self.external_id is not None: body['external_id'] = self.external_id
335
+ if self.role_arn is not None: body['role_arn'] = self.role_arn
336
+ if self.unity_catalog_iam_arn is not None: body['unity_catalog_iam_arn'] = self.unity_catalog_iam_arn
337
+ return body
338
+
339
+ @classmethod
340
+ def from_dict(cls, d: Dict[str, any]) -> AwsIamRole:
341
+ """Deserializes the AwsIamRole from a dictionary."""
342
+ return cls(external_id=d.get('external_id', None),
343
+ role_arn=d.get('role_arn', None),
344
+ unity_catalog_iam_arn=d.get('unity_catalog_iam_arn', None))
345
+
346
+
313
347
  @dataclass
314
348
  class AwsIamRoleRequest:
315
349
  role_arn: str
@@ -355,6 +389,64 @@ class AwsIamRoleResponse:
355
389
  unity_catalog_iam_arn=d.get('unity_catalog_iam_arn', None))
356
390
 
357
391
 
392
+ @dataclass
393
+ class AzureActiveDirectoryToken:
394
+ """Azure Active Directory token, essentially the Oauth token for Azure Service Principal or Managed
395
+ Identity. Read more at
396
+ https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token"""
397
+
398
+ aad_token: Optional[str] = None
399
+ """Opaque token that contains claims that you can use in Azure Active Directory to access cloud
400
+ services."""
401
+
402
+ def as_dict(self) -> dict:
403
+ """Serializes the AzureActiveDirectoryToken into a dictionary suitable for use as a JSON request body."""
404
+ body = {}
405
+ if self.aad_token is not None: body['aad_token'] = self.aad_token
406
+ return body
407
+
408
+ @classmethod
409
+ def from_dict(cls, d: Dict[str, any]) -> AzureActiveDirectoryToken:
410
+ """Deserializes the AzureActiveDirectoryToken from a dictionary."""
411
+ return cls(aad_token=d.get('aad_token', None))
412
+
413
+
414
+ @dataclass
415
+ class AzureManagedIdentity:
416
+ """The Azure managed identity configuration."""
417
+
418
+ access_connector_id: Optional[str] = None
419
+ """The Azure resource ID of the Azure Databricks Access Connector. Use the format
420
+ `/subscriptions/{guid}/resourceGroups/{rg-name}/providers/Microsoft.Databricks/accessConnectors/{connector-name}`."""
421
+
422
+ credential_id: Optional[str] = None
423
+ """The Databricks internal ID that represents this managed identity. This field is only used to
424
+ persist the credential_id once it is fetched from the credentials manager - as we only use the
425
+ protobuf serializer to store credentials, this ID gets persisted to the database. ."""
426
+
427
+ managed_identity_id: Optional[str] = None
428
+ """The Azure resource ID of the managed identity. Use the format,
429
+ `/subscriptions/{guid}/resourceGroups/{rg-name}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identity-name}`
430
+ This is only available for user-assgined identities. For system-assigned identities, the
431
+ access_connector_id is used to identify the identity. If this field is not provided, then we
432
+ assume the AzureManagedIdentity is using the system-assigned identity."""
433
+
434
+ def as_dict(self) -> dict:
435
+ """Serializes the AzureManagedIdentity into a dictionary suitable for use as a JSON request body."""
436
+ body = {}
437
+ if self.access_connector_id is not None: body['access_connector_id'] = self.access_connector_id
438
+ if self.credential_id is not None: body['credential_id'] = self.credential_id
439
+ if self.managed_identity_id is not None: body['managed_identity_id'] = self.managed_identity_id
440
+ return body
441
+
442
+ @classmethod
443
+ def from_dict(cls, d: Dict[str, any]) -> AzureManagedIdentity:
444
+ """Deserializes the AzureManagedIdentity from a dictionary."""
445
+ return cls(access_connector_id=d.get('access_connector_id', None),
446
+ credential_id=d.get('credential_id', None),
447
+ managed_identity_id=d.get('managed_identity_id', None))
448
+
449
+
358
450
  @dataclass
359
451
  class AzureManagedIdentityRequest:
360
452
  access_connector_id: str
@@ -793,6 +885,7 @@ class ColumnTypeName(Enum):
793
885
  TIMESTAMP = 'TIMESTAMP'
794
886
  TIMESTAMP_NTZ = 'TIMESTAMP_NTZ'
795
887
  USER_DEFINED_TYPE = 'USER_DEFINED_TYPE'
888
+ VARIANT = 'VARIANT'
796
889
 
797
890
 
798
891
  @dataclass
@@ -1066,6 +1159,49 @@ class CreateConnection:
1066
1159
  read_only=d.get('read_only', None))
1067
1160
 
1068
1161
 
1162
+ @dataclass
1163
+ class CreateCredentialRequest:
1164
+ aws_iam_role: Optional[AwsIamRole] = None
1165
+ """The AWS IAM role configuration"""
1166
+
1167
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
1168
+ """The Azure managed identity configuration."""
1169
+
1170
+ comment: Optional[str] = None
1171
+ """Comment associated with the credential."""
1172
+
1173
+ name: Optional[str] = None
1174
+ """The credential name. The name must be unique among storage and service credentials within the
1175
+ metastore."""
1176
+
1177
+ purpose: Optional[CredentialPurpose] = None
1178
+ """Indicates the purpose of the credential."""
1179
+
1180
+ skip_validation: Optional[bool] = None
1181
+ """Optional. Supplying true to this argument skips validation of the created set of credentials."""
1182
+
1183
+ def as_dict(self) -> dict:
1184
+ """Serializes the CreateCredentialRequest into a dictionary suitable for use as a JSON request body."""
1185
+ body = {}
1186
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
1187
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
1188
+ if self.comment is not None: body['comment'] = self.comment
1189
+ if self.name is not None: body['name'] = self.name
1190
+ if self.purpose is not None: body['purpose'] = self.purpose.value
1191
+ if self.skip_validation is not None: body['skip_validation'] = self.skip_validation
1192
+ return body
1193
+
1194
+ @classmethod
1195
+ def from_dict(cls, d: Dict[str, any]) -> CreateCredentialRequest:
1196
+ """Deserializes the CreateCredentialRequest from a dictionary."""
1197
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
1198
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
1199
+ comment=d.get('comment', None),
1200
+ name=d.get('name', None),
1201
+ purpose=_enum(d, 'purpose', CredentialPurpose),
1202
+ skip_validation=d.get('skip_validation', None))
1203
+
1204
+
1069
1205
  @dataclass
1070
1206
  class CreateExternalLocation:
1071
1207
  name: str
@@ -1278,7 +1414,7 @@ class CreateFunctionRoutineBody(Enum):
1278
1414
 
1279
1415
 
1280
1416
  class CreateFunctionSecurityType(Enum):
1281
- """Function security type."""
1417
+ """The security type of the function."""
1282
1418
 
1283
1419
  DEFINER = 'DEFINER'
1284
1420
 
@@ -1439,29 +1575,6 @@ class CreateMonitor:
1439
1575
  warehouse_id=d.get('warehouse_id', None))
1440
1576
 
1441
1577
 
1442
- @dataclass
1443
- class CreateOnlineTableRequest:
1444
- """Online Table information."""
1445
-
1446
- name: Optional[str] = None
1447
- """Full three-part (catalog, schema, table) name of the table."""
1448
-
1449
- spec: Optional[OnlineTableSpec] = None
1450
- """Specification of the online table."""
1451
-
1452
- def as_dict(self) -> dict:
1453
- """Serializes the CreateOnlineTableRequest into a dictionary suitable for use as a JSON request body."""
1454
- body = {}
1455
- if self.name is not None: body['name'] = self.name
1456
- if self.spec: body['spec'] = self.spec.as_dict()
1457
- return body
1458
-
1459
- @classmethod
1460
- def from_dict(cls, d: Dict[str, any]) -> CreateOnlineTableRequest:
1461
- """Deserializes the CreateOnlineTableRequest from a dictionary."""
1462
- return cls(name=d.get('name', None), spec=_from_dict(d, 'spec', OnlineTableSpec))
1463
-
1464
-
1465
1578
  @dataclass
1466
1579
  class CreateRegisteredModelRequest:
1467
1580
  catalog_name: str
@@ -1675,6 +1788,94 @@ class CreateVolumeRequestContent:
1675
1788
  volume_type=_enum(d, 'volume_type', VolumeType))
1676
1789
 
1677
1790
 
1791
+ @dataclass
1792
+ class CredentialInfo:
1793
+ aws_iam_role: Optional[AwsIamRole] = None
1794
+ """The AWS IAM role configuration"""
1795
+
1796
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
1797
+ """The Azure managed identity configuration."""
1798
+
1799
+ comment: Optional[str] = None
1800
+ """Comment associated with the credential."""
1801
+
1802
+ created_at: Optional[int] = None
1803
+ """Time at which this credential was created, in epoch milliseconds."""
1804
+
1805
+ created_by: Optional[str] = None
1806
+ """Username of credential creator."""
1807
+
1808
+ full_name: Optional[str] = None
1809
+ """The full name of the credential."""
1810
+
1811
+ id: Optional[str] = None
1812
+ """The unique identifier of the credential."""
1813
+
1814
+ isolation_mode: Optional[IsolationMode] = None
1815
+ """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
1816
+
1817
+ metastore_id: Optional[str] = None
1818
+ """Unique identifier of the parent metastore."""
1819
+
1820
+ name: Optional[str] = None
1821
+ """The credential name. The name must be unique among storage and service credentials within the
1822
+ metastore."""
1823
+
1824
+ owner: Optional[str] = None
1825
+ """Username of current owner of credential."""
1826
+
1827
+ purpose: Optional[CredentialPurpose] = None
1828
+ """Indicates the purpose of the credential."""
1829
+
1830
+ updated_at: Optional[int] = None
1831
+ """Time at which this credential was last modified, in epoch milliseconds."""
1832
+
1833
+ updated_by: Optional[str] = None
1834
+ """Username of user who last modified the credential."""
1835
+
1836
+ def as_dict(self) -> dict:
1837
+ """Serializes the CredentialInfo into a dictionary suitable for use as a JSON request body."""
1838
+ body = {}
1839
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
1840
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
1841
+ if self.comment is not None: body['comment'] = self.comment
1842
+ if self.created_at is not None: body['created_at'] = self.created_at
1843
+ if self.created_by is not None: body['created_by'] = self.created_by
1844
+ if self.full_name is not None: body['full_name'] = self.full_name
1845
+ if self.id is not None: body['id'] = self.id
1846
+ if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
1847
+ if self.metastore_id is not None: body['metastore_id'] = self.metastore_id
1848
+ if self.name is not None: body['name'] = self.name
1849
+ if self.owner is not None: body['owner'] = self.owner
1850
+ if self.purpose is not None: body['purpose'] = self.purpose.value
1851
+ if self.updated_at is not None: body['updated_at'] = self.updated_at
1852
+ if self.updated_by is not None: body['updated_by'] = self.updated_by
1853
+ return body
1854
+
1855
+ @classmethod
1856
+ def from_dict(cls, d: Dict[str, any]) -> CredentialInfo:
1857
+ """Deserializes the CredentialInfo from a dictionary."""
1858
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
1859
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
1860
+ comment=d.get('comment', None),
1861
+ created_at=d.get('created_at', None),
1862
+ created_by=d.get('created_by', None),
1863
+ full_name=d.get('full_name', None),
1864
+ id=d.get('id', None),
1865
+ isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
1866
+ metastore_id=d.get('metastore_id', None),
1867
+ name=d.get('name', None),
1868
+ owner=d.get('owner', None),
1869
+ purpose=_enum(d, 'purpose', CredentialPurpose),
1870
+ updated_at=d.get('updated_at', None),
1871
+ updated_by=d.get('updated_by', None))
1872
+
1873
+
1874
+ class CredentialPurpose(Enum):
1875
+
1876
+ SERVICE = 'SERVICE'
1877
+
1878
+
1678
1879
  class CredentialType(Enum):
1679
1880
  """The type of credential."""
1680
1881
 
@@ -1682,6 +1883,27 @@ class CredentialType(Enum):
1682
1883
  USERNAME_PASSWORD = 'USERNAME_PASSWORD'
1683
1884
 
1684
1885
 
1886
+ @dataclass
1887
+ class CredentialValidationResult:
1888
+ message: Optional[str] = None
1889
+ """Error message would exist when the result does not equal to **PASS**."""
1890
+
1891
+ result: Optional[ValidateCredentialResult] = None
1892
+ """The results of the tested operation."""
1893
+
1894
+ def as_dict(self) -> dict:
1895
+ """Serializes the CredentialValidationResult into a dictionary suitable for use as a JSON request body."""
1896
+ body = {}
1897
+ if self.message is not None: body['message'] = self.message
1898
+ if self.result is not None: body['result'] = self.result.value
1899
+ return body
1900
+
1901
+ @classmethod
1902
+ def from_dict(cls, d: Dict[str, any]) -> CredentialValidationResult:
1903
+ """Deserializes the CredentialValidationResult from a dictionary."""
1904
+ return cls(message=d.get('message', None), result=_enum(d, 'result', ValidateCredentialResult))
1905
+
1906
+
1685
1907
  @dataclass
1686
1908
  class CurrentWorkspaceBindings:
1687
1909
  """Currently assigned workspaces"""
@@ -1778,6 +2000,20 @@ class DeleteAliasResponse:
1778
2000
  return cls()
1779
2001
 
1780
2002
 
2003
+ @dataclass
2004
+ class DeleteCredentialResponse:
2005
+
2006
+ def as_dict(self) -> dict:
2007
+ """Serializes the DeleteCredentialResponse into a dictionary suitable for use as a JSON request body."""
2008
+ body = {}
2009
+ return body
2010
+
2011
+ @classmethod
2012
+ def from_dict(cls, d: Dict[str, any]) -> DeleteCredentialResponse:
2013
+ """Deserializes the DeleteCredentialResponse from a dictionary."""
2014
+ return cls()
2015
+
2016
+
1781
2017
  @dataclass
1782
2018
  class DeleteResponse:
1783
2019
 
@@ -2052,7 +2288,6 @@ class ExternalLocationInfo:
2052
2288
  sufficient."""
2053
2289
 
2054
2290
  isolation_mode: Optional[IsolationMode] = None
2055
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
2056
2291
 
2057
2292
  metastore_id: Optional[str] = None
2058
2293
  """Unique identifier of metastore hosting the external location."""
@@ -2382,7 +2617,7 @@ class FunctionInfoRoutineBody(Enum):
2382
2617
 
2383
2618
 
2384
2619
  class FunctionInfoSecurityType(Enum):
2385
- """Function security type."""
2620
+ """The security type of the function."""
2386
2621
 
2387
2622
  DEFINER = 'DEFINER'
2388
2623
 
@@ -2516,6 +2751,50 @@ class GcpOauthToken:
2516
2751
  return cls(oauth_token=d.get('oauth_token', None))
2517
2752
 
2518
2753
 
2754
+ @dataclass
2755
+ class GenerateTemporaryServiceCredentialAzureOptions:
2756
+ """Options to customize the requested temporary credential"""
2757
+
2758
+ resources: Optional[List[str]] = None
2759
+ """The resources to which the temporary Azure credential should apply. These resources are the
2760
+ scopes that are passed to the token provider (see
2761
+ https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential?view=azure-python)"""
2762
+
2763
+ def as_dict(self) -> dict:
2764
+ """Serializes the GenerateTemporaryServiceCredentialAzureOptions into a dictionary suitable for use as a JSON request body."""
2765
+ body = {}
2766
+ if self.resources: body['resources'] = [v for v in self.resources]
2767
+ return body
2768
+
2769
+ @classmethod
2770
+ def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryServiceCredentialAzureOptions:
2771
+ """Deserializes the GenerateTemporaryServiceCredentialAzureOptions from a dictionary."""
2772
+ return cls(resources=d.get('resources', None))
2773
+
2774
+
2775
+ @dataclass
2776
+ class GenerateTemporaryServiceCredentialRequest:
2777
+ azure_options: Optional[GenerateTemporaryServiceCredentialAzureOptions] = None
2778
+ """Options to customize the requested temporary credential"""
2779
+
2780
+ credential_name: Optional[str] = None
2781
+ """The name of the service credential used to generate a temporary credential"""
2782
+
2783
+ def as_dict(self) -> dict:
2784
+ """Serializes the GenerateTemporaryServiceCredentialRequest into a dictionary suitable for use as a JSON request body."""
2785
+ body = {}
2786
+ if self.azure_options: body['azure_options'] = self.azure_options.as_dict()
2787
+ if self.credential_name is not None: body['credential_name'] = self.credential_name
2788
+ return body
2789
+
2790
+ @classmethod
2791
+ def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryServiceCredentialRequest:
2792
+ """Deserializes the GenerateTemporaryServiceCredentialRequest from a dictionary."""
2793
+ return cls(azure_options=_from_dict(d, 'azure_options',
2794
+ GenerateTemporaryServiceCredentialAzureOptions),
2795
+ credential_name=d.get('credential_name', None))
2796
+
2797
+
2519
2798
  @dataclass
2520
2799
  class GenerateTemporaryTableCredentialRequest:
2521
2800
  operation: Optional[TableOperation] = None
@@ -2545,6 +2824,11 @@ class GenerateTemporaryTableCredentialResponse:
2545
2824
  """AWS temporary credentials for API authentication. Read more at
2546
2825
  https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html."""
2547
2826
 
2827
+ azure_aad: Optional[AzureActiveDirectoryToken] = None
2828
+ """Azure Active Directory token, essentially the Oauth token for Azure Service Principal or Managed
2829
+ Identity. Read more at
2830
+ https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token"""
2831
+
2548
2832
  azure_user_delegation_sas: Optional[AzureUserDelegationSas] = None
2549
2833
  """Azure temporary credentials for API authentication. Read more at
2550
2834
  https://docs.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas"""
@@ -2568,6 +2852,7 @@ class GenerateTemporaryTableCredentialResponse:
2568
2852
  """Serializes the GenerateTemporaryTableCredentialResponse into a dictionary suitable for use as a JSON request body."""
2569
2853
  body = {}
2570
2854
  if self.aws_temp_credentials: body['aws_temp_credentials'] = self.aws_temp_credentials.as_dict()
2855
+ if self.azure_aad: body['azure_aad'] = self.azure_aad.as_dict()
2571
2856
  if self.azure_user_delegation_sas:
2572
2857
  body['azure_user_delegation_sas'] = self.azure_user_delegation_sas.as_dict()
2573
2858
  if self.expiration_time is not None: body['expiration_time'] = self.expiration_time
@@ -2580,6 +2865,7 @@ class GenerateTemporaryTableCredentialResponse:
2580
2865
  def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryTableCredentialResponse:
2581
2866
  """Deserializes the GenerateTemporaryTableCredentialResponse from a dictionary."""
2582
2867
  return cls(aws_temp_credentials=_from_dict(d, 'aws_temp_credentials', AwsCredentials),
2868
+ azure_aad=_from_dict(d, 'azure_aad', AzureActiveDirectoryToken),
2583
2869
  azure_user_delegation_sas=_from_dict(d, 'azure_user_delegation_sas',
2584
2870
  AzureUserDelegationSas),
2585
2871
  expiration_time=d.get('expiration_time', None),
@@ -2592,6 +2878,7 @@ class GetBindingsSecurableType(Enum):
2592
2878
 
2593
2879
  CATALOG = 'catalog'
2594
2880
  EXTERNAL_LOCATION = 'external_location'
2881
+ SERVICE_CREDENTIAL = 'service_credential'
2595
2882
  STORAGE_CREDENTIAL = 'storage_credential'
2596
2883
 
2597
2884
 
@@ -2738,7 +3025,6 @@ class GetQuotaResponse:
2738
3025
 
2739
3026
 
2740
3027
  class IsolationMode(Enum):
2741
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
2742
3028
 
2743
3029
  ISOLATION_MODE_ISOLATED = 'ISOLATION_MODE_ISOLATED'
2744
3030
  ISOLATION_MODE_OPEN = 'ISOLATION_MODE_OPEN'
@@ -2826,6 +3112,28 @@ class ListConnectionsResponse:
2826
3112
  next_page_token=d.get('next_page_token', None))
2827
3113
 
2828
3114
 
3115
+ @dataclass
3116
+ class ListCredentialsResponse:
3117
+ credentials: Optional[List[CredentialInfo]] = None
3118
+
3119
+ next_page_token: Optional[str] = None
3120
+ """Opaque token to retrieve the next page of results. Absent if there are no more pages.
3121
+ __page_token__ should be set to this value for the next request (for the next page of results)."""
3122
+
3123
+ def as_dict(self) -> dict:
3124
+ """Serializes the ListCredentialsResponse into a dictionary suitable for use as a JSON request body."""
3125
+ body = {}
3126
+ if self.credentials: body['credentials'] = [v.as_dict() for v in self.credentials]
3127
+ if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
3128
+ return body
3129
+
3130
+ @classmethod
3131
+ def from_dict(cls, d: Dict[str, any]) -> ListCredentialsResponse:
3132
+ """Deserializes the ListCredentialsResponse from a dictionary."""
3133
+ return cls(credentials=_repeated_dict(d, 'credentials', CredentialInfo),
3134
+ next_page_token=d.get('next_page_token', None))
3135
+
3136
+
2829
3137
  @dataclass
2830
3138
  class ListExternalLocationsResponse:
2831
3139
  external_locations: Optional[List[ExternalLocationInfo]] = None
@@ -4619,6 +4927,7 @@ class SecurableType(Enum):
4619
4927
 
4620
4928
  CATALOG = 'catalog'
4621
4929
  CONNECTION = 'connection'
4930
+ CREDENTIAL = 'credential'
4622
4931
  EXTERNAL_LOCATION = 'external_location'
4623
4932
  FUNCTION = 'function'
4624
4933
  METASTORE = 'metastore'
@@ -4738,11 +5047,13 @@ class StorageCredentialInfo:
4738
5047
  databricks_gcp_service_account: Optional[DatabricksGcpServiceAccountResponse] = None
4739
5048
  """The Databricks managed GCP service account configuration."""
4740
5049
 
5050
+ full_name: Optional[str] = None
5051
+ """The full name of the credential."""
5052
+
4741
5053
  id: Optional[str] = None
4742
5054
  """The unique identifier of the credential."""
4743
5055
 
4744
5056
  isolation_mode: Optional[IsolationMode] = None
4745
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
4746
5057
 
4747
5058
  metastore_id: Optional[str] = None
4748
5059
  """Unique identifier of parent metastore."""
@@ -4778,6 +5089,7 @@ class StorageCredentialInfo:
4778
5089
  if self.created_by is not None: body['created_by'] = self.created_by
4779
5090
  if self.databricks_gcp_service_account:
4780
5091
  body['databricks_gcp_service_account'] = self.databricks_gcp_service_account.as_dict()
5092
+ if self.full_name is not None: body['full_name'] = self.full_name
4781
5093
  if self.id is not None: body['id'] = self.id
4782
5094
  if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
4783
5095
  if self.metastore_id is not None: body['metastore_id'] = self.metastore_id
@@ -4803,6 +5115,7 @@ class StorageCredentialInfo:
4803
5115
  created_by=d.get('created_by', None),
4804
5116
  databricks_gcp_service_account=_from_dict(d, 'databricks_gcp_service_account',
4805
5117
  DatabricksGcpServiceAccountResponse),
5118
+ full_name=d.get('full_name', None),
4806
5119
  id=d.get('id', None),
4807
5120
  isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
4808
5121
  metastore_id=d.get('metastore_id', None),
@@ -5158,6 +5471,37 @@ class TableType(Enum):
5158
5471
  VIEW = 'VIEW'
5159
5472
 
5160
5473
 
5474
+ @dataclass
5475
+ class TemporaryCredentials:
5476
+ aws_temp_credentials: Optional[AwsCredentials] = None
5477
+ """AWS temporary credentials for API authentication. Read more at
5478
+ https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html."""
5479
+
5480
+ azure_aad: Optional[AzureActiveDirectoryToken] = None
5481
+ """Azure Active Directory token, essentially the Oauth token for Azure Service Principal or Managed
5482
+ Identity. Read more at
5483
+ https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token"""
5484
+
5485
+ expiration_time: Optional[int] = None
5486
+ """Server time when the credential will expire, in epoch milliseconds. The API client is advised to
5487
+ cache the credential given this expiration time."""
5488
+
5489
+ def as_dict(self) -> dict:
5490
+ """Serializes the TemporaryCredentials into a dictionary suitable for use as a JSON request body."""
5491
+ body = {}
5492
+ if self.aws_temp_credentials: body['aws_temp_credentials'] = self.aws_temp_credentials.as_dict()
5493
+ if self.azure_aad: body['azure_aad'] = self.azure_aad.as_dict()
5494
+ if self.expiration_time is not None: body['expiration_time'] = self.expiration_time
5495
+ return body
5496
+
5497
+ @classmethod
5498
+ def from_dict(cls, d: Dict[str, any]) -> TemporaryCredentials:
5499
+ """Deserializes the TemporaryCredentials from a dictionary."""
5500
+ return cls(aws_temp_credentials=_from_dict(d, 'aws_temp_credentials', AwsCredentials),
5501
+ azure_aad=_from_dict(d, 'azure_aad', AzureActiveDirectoryToken),
5502
+ expiration_time=d.get('expiration_time', None))
5503
+
5504
+
5161
5505
  @dataclass
5162
5506
  class TriggeredUpdateStatus:
5163
5507
  """Detailed status of an online table. Shown if the online table is in the ONLINE_TRIGGERED_UPDATE
@@ -5224,6 +5568,7 @@ class UpdateBindingsSecurableType(Enum):
5224
5568
 
5225
5569
  CATALOG = 'catalog'
5226
5570
  EXTERNAL_LOCATION = 'external_location'
5571
+ SERVICE_CREDENTIAL = 'service_credential'
5227
5572
  STORAGE_CREDENTIAL = 'storage_credential'
5228
5573
 
5229
5574
 
@@ -5308,6 +5653,63 @@ class UpdateConnection:
5308
5653
  owner=d.get('owner', None))
5309
5654
 
5310
5655
 
5656
+ @dataclass
5657
+ class UpdateCredentialRequest:
5658
+ aws_iam_role: Optional[AwsIamRole] = None
5659
+ """The AWS IAM role configuration"""
5660
+
5661
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
5662
+ """The Azure managed identity configuration."""
5663
+
5664
+ comment: Optional[str] = None
5665
+ """Comment associated with the credential."""
5666
+
5667
+ force: Optional[bool] = None
5668
+ """Force update even if there are dependent services."""
5669
+
5670
+ isolation_mode: Optional[IsolationMode] = None
5671
+ """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5672
+
5673
+ name_arg: Optional[str] = None
5674
+ """Name of the credential."""
5675
+
5676
+ new_name: Optional[str] = None
5677
+ """New name of credential."""
5678
+
5679
+ owner: Optional[str] = None
5680
+ """Username of current owner of credential."""
5681
+
5682
+ skip_validation: Optional[bool] = None
5683
+ """Supply true to this argument to skip validation of the updated credential."""
5684
+
5685
+ def as_dict(self) -> dict:
5686
+ """Serializes the UpdateCredentialRequest into a dictionary suitable for use as a JSON request body."""
5687
+ body = {}
5688
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
5689
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
5690
+ if self.comment is not None: body['comment'] = self.comment
5691
+ if self.force is not None: body['force'] = self.force
5692
+ if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
5693
+ if self.name_arg is not None: body['name_arg'] = self.name_arg
5694
+ if self.new_name is not None: body['new_name'] = self.new_name
5695
+ if self.owner is not None: body['owner'] = self.owner
5696
+ if self.skip_validation is not None: body['skip_validation'] = self.skip_validation
5697
+ return body
5698
+
5699
+ @classmethod
5700
+ def from_dict(cls, d: Dict[str, any]) -> UpdateCredentialRequest:
5701
+ """Deserializes the UpdateCredentialRequest from a dictionary."""
5702
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
5703
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
5704
+ comment=d.get('comment', None),
5705
+ force=d.get('force', None),
5706
+ isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
5707
+ name_arg=d.get('name_arg', None),
5708
+ new_name=d.get('new_name', None),
5709
+ owner=d.get('owner', None),
5710
+ skip_validation=d.get('skip_validation', None))
5711
+
5712
+
5311
5713
  @dataclass
5312
5714
  class UpdateExternalLocation:
5313
5715
  access_point: Optional[str] = None
@@ -5331,7 +5733,6 @@ class UpdateExternalLocation:
5331
5733
  """Force update even if changing url invalidates dependent external tables or mounts."""
5332
5734
 
5333
5735
  isolation_mode: Optional[IsolationMode] = None
5334
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5335
5736
 
5336
5737
  name: Optional[str] = None
5337
5738
  """Name of the external location."""
@@ -5751,7 +6152,6 @@ class UpdateStorageCredential:
5751
6152
  """Force update even if there are dependent external locations or external tables."""
5752
6153
 
5753
6154
  isolation_mode: Optional[IsolationMode] = None
5754
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5755
6155
 
5756
6156
  name: Optional[str] = None
5757
6157
  """Name of the storage credential."""
@@ -5899,6 +6299,63 @@ class UpdateWorkspaceBindingsParameters:
5899
6299
  securable_type=_enum(d, 'securable_type', UpdateBindingsSecurableType))
5900
6300
 
5901
6301
 
6302
+ @dataclass
6303
+ class ValidateCredentialRequest:
6304
+ aws_iam_role: Optional[AwsIamRole] = None
6305
+ """The AWS IAM role configuration"""
6306
+
6307
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
6308
+ """The Azure managed identity configuration."""
6309
+
6310
+ credential_name: Optional[str] = None
6311
+ """Required. The name of an existing credential or long-lived cloud credential to validate."""
6312
+
6313
+ purpose: Optional[CredentialPurpose] = None
6314
+ """The purpose of the credential. This should only be used when the credential is specified."""
6315
+
6316
+ def as_dict(self) -> dict:
6317
+ """Serializes the ValidateCredentialRequest into a dictionary suitable for use as a JSON request body."""
6318
+ body = {}
6319
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
6320
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
6321
+ if self.credential_name is not None: body['credential_name'] = self.credential_name
6322
+ if self.purpose is not None: body['purpose'] = self.purpose.value
6323
+ return body
6324
+
6325
+ @classmethod
6326
+ def from_dict(cls, d: Dict[str, any]) -> ValidateCredentialRequest:
6327
+ """Deserializes the ValidateCredentialRequest from a dictionary."""
6328
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
6329
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
6330
+ credential_name=d.get('credential_name', None),
6331
+ purpose=_enum(d, 'purpose', CredentialPurpose))
6332
+
6333
+
6334
+ @dataclass
6335
+ class ValidateCredentialResponse:
6336
+ results: Optional[List[CredentialValidationResult]] = None
6337
+ """The results of the validation check."""
6338
+
6339
+ def as_dict(self) -> dict:
6340
+ """Serializes the ValidateCredentialResponse into a dictionary suitable for use as a JSON request body."""
6341
+ body = {}
6342
+ if self.results: body['results'] = [v.as_dict() for v in self.results]
6343
+ return body
6344
+
6345
+ @classmethod
6346
+ def from_dict(cls, d: Dict[str, any]) -> ValidateCredentialResponse:
6347
+ """Deserializes the ValidateCredentialResponse from a dictionary."""
6348
+ return cls(results=_repeated_dict(d, 'results', CredentialValidationResult))
6349
+
6350
+
6351
+ class ValidateCredentialResult(Enum):
6352
+ """A enum represents the result of the file operation"""
6353
+
6354
+ FAIL = 'FAIL'
6355
+ PASS = 'PASS'
6356
+ SKIP = 'SKIP'
6357
+
6358
+
5902
6359
  @dataclass
5903
6360
  class ValidateStorageCredential:
5904
6361
  aws_iam_role: Optional[AwsIamRoleRequest] = None
@@ -6935,6 +7392,258 @@ class ConnectionsAPI:
6935
7392
  return ConnectionInfo.from_dict(res)
6936
7393
 
6937
7394
 
7395
+ class CredentialsAPI:
7396
+ """A credential represents an authentication and authorization mechanism for accessing services on your cloud
7397
+ tenant. Each credential is subject to Unity Catalog access-control policies that control which users and
7398
+ groups can access the credential.
7399
+
7400
+ To create credentials, you must be a Databricks account admin or have the `CREATE SERVICE CREDENTIAL
7401
+ privilege. The user who creates the credential can delegate ownership to another user or group to manage
7402
+ permissions on it"""
7403
+
7404
+ def __init__(self, api_client):
7405
+ self._api = api_client
7406
+
7407
+ def create_credential(self,
7408
+ *,
7409
+ aws_iam_role: Optional[AwsIamRole] = None,
7410
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7411
+ comment: Optional[str] = None,
7412
+ name: Optional[str] = None,
7413
+ purpose: Optional[CredentialPurpose] = None,
7414
+ skip_validation: Optional[bool] = None) -> CredentialInfo:
7415
+ """Create a credential.
7416
+
7417
+ Creates a new credential.
7418
+
7419
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7420
+ The AWS IAM role configuration
7421
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7422
+ The Azure managed identity configuration.
7423
+ :param comment: str (optional)
7424
+ Comment associated with the credential.
7425
+ :param name: str (optional)
7426
+ The credential name. The name must be unique among storage and service credentials within the
7427
+ metastore.
7428
+ :param purpose: :class:`CredentialPurpose` (optional)
7429
+ Indicates the purpose of the credential.
7430
+ :param skip_validation: bool (optional)
7431
+ Optional. Supplying true to this argument skips validation of the created set of credentials.
7432
+
7433
+ :returns: :class:`CredentialInfo`
7434
+ """
7435
+ body = {}
7436
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7437
+ if azure_managed_identity is not None:
7438
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7439
+ if comment is not None: body['comment'] = comment
7440
+ if name is not None: body['name'] = name
7441
+ if purpose is not None: body['purpose'] = purpose.value
7442
+ if skip_validation is not None: body['skip_validation'] = skip_validation
7443
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7444
+
7445
+ res = self._api.do('POST', '/api/2.1/unity-catalog/credentials', body=body, headers=headers)
7446
+ return CredentialInfo.from_dict(res)
7447
+
7448
+ def delete_credential(self, name_arg: str, *, force: Optional[bool] = None):
7449
+ """Delete a credential.
7450
+
7451
+ Deletes a credential from the metastore. The caller must be an owner of the credential.
7452
+
7453
+ :param name_arg: str
7454
+ Name of the credential.
7455
+ :param force: bool (optional)
7456
+ Force deletion even if there are dependent services.
7457
+
7458
+
7459
+ """
7460
+
7461
+ query = {}
7462
+ if force is not None: query['force'] = force
7463
+ headers = {'Accept': 'application/json', }
7464
+
7465
+ self._api.do('DELETE', f'/api/2.1/unity-catalog/credentials/{name_arg}', query=query, headers=headers)
7466
+
7467
+ def generate_temporary_service_credential(
7468
+ self,
7469
+ *,
7470
+ azure_options: Optional[GenerateTemporaryServiceCredentialAzureOptions] = None,
7471
+ credential_name: Optional[str] = None) -> TemporaryCredentials:
7472
+ """Generate a temporary service credential.
7473
+
7474
+ Returns a set of temporary credentials generated using the specified service credential. The caller
7475
+ must be a metastore admin or have the metastore privilege **ACCESS** on the service credential.
7476
+
7477
+ :param azure_options: :class:`GenerateTemporaryServiceCredentialAzureOptions` (optional)
7478
+ Options to customize the requested temporary credential
7479
+ :param credential_name: str (optional)
7480
+ The name of the service credential used to generate a temporary credential
7481
+
7482
+ :returns: :class:`TemporaryCredentials`
7483
+ """
7484
+ body = {}
7485
+ if azure_options is not None: body['azure_options'] = azure_options.as_dict()
7486
+ if credential_name is not None: body['credential_name'] = credential_name
7487
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7488
+
7489
+ res = self._api.do('POST',
7490
+ '/api/2.1/unity-catalog/temporary-service-credentials',
7491
+ body=body,
7492
+ headers=headers)
7493
+ return TemporaryCredentials.from_dict(res)
7494
+
7495
+ def get_credential(self, name_arg: str) -> CredentialInfo:
7496
+ """Get a credential.
7497
+
7498
+ Gets a credential from the metastore. The caller must be a metastore admin, the owner of the
7499
+ credential, or have any permission on the credential.
7500
+
7501
+ :param name_arg: str
7502
+ Name of the credential.
7503
+
7504
+ :returns: :class:`CredentialInfo`
7505
+ """
7506
+
7507
+ headers = {'Accept': 'application/json', }
7508
+
7509
+ res = self._api.do('GET', f'/api/2.1/unity-catalog/credentials/{name_arg}', headers=headers)
7510
+ return CredentialInfo.from_dict(res)
7511
+
7512
+ def list_credentials(self,
7513
+ *,
7514
+ max_results: Optional[int] = None,
7515
+ page_token: Optional[str] = None,
7516
+ purpose: Optional[CredentialPurpose] = None) -> Iterator[CredentialInfo]:
7517
+ """List credentials.
7518
+
7519
+ Gets an array of credentials (as __CredentialInfo__ objects).
7520
+
7521
+ The array is limited to only the credentials that the caller has permission to access. If the caller
7522
+ is a metastore admin, retrieval of credentials is unrestricted. There is no guarantee of a specific
7523
+ ordering of the elements in the array.
7524
+
7525
+ :param max_results: int (optional)
7526
+ Maximum number of credentials to return. - If not set, the default max page size is used. - When set
7527
+ to a value greater than 0, the page length is the minimum of this value and a server-configured
7528
+ value. - When set to 0, the page length is set to a server-configured value (recommended). - When
7529
+ set to a value less than 0, an invalid parameter error is returned.
7530
+ :param page_token: str (optional)
7531
+ Opaque token to retrieve the next page of results.
7532
+ :param purpose: :class:`CredentialPurpose` (optional)
7533
+ Return only credentials for the specified purpose.
7534
+
7535
+ :returns: Iterator over :class:`CredentialInfo`
7536
+ """
7537
+
7538
+ query = {}
7539
+ if max_results is not None: query['max_results'] = max_results
7540
+ if page_token is not None: query['page_token'] = page_token
7541
+ if purpose is not None: query['purpose'] = purpose.value
7542
+ headers = {'Accept': 'application/json', }
7543
+
7544
+ while True:
7545
+ json = self._api.do('GET', '/api/2.1/unity-catalog/credentials', query=query, headers=headers)
7546
+ if 'credentials' in json:
7547
+ for v in json['credentials']:
7548
+ yield CredentialInfo.from_dict(v)
7549
+ if 'next_page_token' not in json or not json['next_page_token']:
7550
+ return
7551
+ query['page_token'] = json['next_page_token']
7552
+
7553
+ def update_credential(self,
7554
+ name_arg: str,
7555
+ *,
7556
+ aws_iam_role: Optional[AwsIamRole] = None,
7557
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7558
+ comment: Optional[str] = None,
7559
+ force: Optional[bool] = None,
7560
+ isolation_mode: Optional[IsolationMode] = None,
7561
+ new_name: Optional[str] = None,
7562
+ owner: Optional[str] = None,
7563
+ skip_validation: Optional[bool] = None) -> CredentialInfo:
7564
+ """Update a credential.
7565
+
7566
+ Updates a credential on the metastore.
7567
+
7568
+ The caller must be the owner of the credential or a metastore admin or have the `MANAGE` permission.
7569
+ If the caller is a metastore admin, only the __owner__ field can be changed.
7570
+
7571
+ :param name_arg: str
7572
+ Name of the credential.
7573
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7574
+ The AWS IAM role configuration
7575
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7576
+ The Azure managed identity configuration.
7577
+ :param comment: str (optional)
7578
+ Comment associated with the credential.
7579
+ :param force: bool (optional)
7580
+ Force update even if there are dependent services.
7581
+ :param isolation_mode: :class:`IsolationMode` (optional)
7582
+ Whether the current securable is accessible from all workspaces or a specific set of workspaces.
7583
+ :param new_name: str (optional)
7584
+ New name of credential.
7585
+ :param owner: str (optional)
7586
+ Username of current owner of credential.
7587
+ :param skip_validation: bool (optional)
7588
+ Supply true to this argument to skip validation of the updated credential.
7589
+
7590
+ :returns: :class:`CredentialInfo`
7591
+ """
7592
+ body = {}
7593
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7594
+ if azure_managed_identity is not None:
7595
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7596
+ if comment is not None: body['comment'] = comment
7597
+ if force is not None: body['force'] = force
7598
+ if isolation_mode is not None: body['isolation_mode'] = isolation_mode.value
7599
+ if new_name is not None: body['new_name'] = new_name
7600
+ if owner is not None: body['owner'] = owner
7601
+ if skip_validation is not None: body['skip_validation'] = skip_validation
7602
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7603
+
7604
+ res = self._api.do('PATCH',
7605
+ f'/api/2.1/unity-catalog/credentials/{name_arg}',
7606
+ body=body,
7607
+ headers=headers)
7608
+ return CredentialInfo.from_dict(res)
7609
+
7610
+ def validate_credential(self,
7611
+ *,
7612
+ aws_iam_role: Optional[AwsIamRole] = None,
7613
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7614
+ credential_name: Optional[str] = None,
7615
+ purpose: Optional[CredentialPurpose] = None) -> ValidateCredentialResponse:
7616
+ """Validate a credential.
7617
+
7618
+ Validates a credential.
7619
+
7620
+ Either the __credential_name__ or the cloud-specific credential must be provided.
7621
+
7622
+ The caller must be a metastore admin or the credential owner.
7623
+
7624
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7625
+ The AWS IAM role configuration
7626
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7627
+ The Azure managed identity configuration.
7628
+ :param credential_name: str (optional)
7629
+ Required. The name of an existing credential or long-lived cloud credential to validate.
7630
+ :param purpose: :class:`CredentialPurpose` (optional)
7631
+ The purpose of the credential. This should only be used when the credential is specified.
7632
+
7633
+ :returns: :class:`ValidateCredentialResponse`
7634
+ """
7635
+ body = {}
7636
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7637
+ if azure_managed_identity is not None:
7638
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7639
+ if credential_name is not None: body['credential_name'] = credential_name
7640
+ if purpose is not None: body['purpose'] = purpose.value
7641
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7642
+
7643
+ res = self._api.do('POST', '/api/2.1/unity-catalog/validate-credentials', body=body, headers=headers)
7644
+ return ValidateCredentialResponse.from_dict(res)
7645
+
7646
+
6938
7647
  class ExternalLocationsAPI:
6939
7648
  """An external location is an object that combines a cloud storage path with a storage credential that
6940
7649
  authorizes access to the cloud storage path. Each external location is subject to Unity Catalog
@@ -7134,7 +7843,6 @@ class ExternalLocationsAPI:
7134
7843
  :param force: bool (optional)
7135
7844
  Force update even if changing url invalidates dependent external tables or mounts.
7136
7845
  :param isolation_mode: :class:`IsolationMode` (optional)
7137
- Whether the current securable is accessible from all workspaces or a specific set of workspaces.
7138
7846
  :param new_name: str (optional)
7139
7847
  New name for the external location.
7140
7848
  :param owner: str (optional)
@@ -7890,25 +8598,61 @@ class OnlineTablesAPI:
7890
8598
  def __init__(self, api_client):
7891
8599
  self._api = api_client
7892
8600
 
7893
- def create(self, *, name: Optional[str] = None, spec: Optional[OnlineTableSpec] = None) -> OnlineTable:
8601
+ def wait_get_online_table_active(self,
8602
+ name: str,
8603
+ timeout=timedelta(minutes=20),
8604
+ callback: Optional[Callable[[OnlineTable], None]] = None) -> OnlineTable:
8605
+ deadline = time.time() + timeout.total_seconds()
8606
+ target_states = (ProvisioningInfoState.ACTIVE, )
8607
+ failure_states = (ProvisioningInfoState.FAILED, )
8608
+ status_message = 'polling...'
8609
+ attempt = 1
8610
+ while time.time() < deadline:
8611
+ poll = self.get(name=name)
8612
+ status = poll.unity_catalog_provisioning_state
8613
+ status_message = f'current status: {status}'
8614
+ if status in target_states:
8615
+ return poll
8616
+ if callback:
8617
+ callback(poll)
8618
+ if status in failure_states:
8619
+ msg = f'failed to reach ACTIVE, got {status}: {status_message}'
8620
+ raise OperationFailed(msg)
8621
+ prefix = f"name={name}"
8622
+ sleep = attempt
8623
+ if sleep > 10:
8624
+ # sleep 10s max per attempt
8625
+ sleep = 10
8626
+ _LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
8627
+ time.sleep(sleep + random.random())
8628
+ attempt += 1
8629
+ raise TimeoutError(f'timed out after {timeout}: {status_message}')
8630
+
8631
+ def create(self, *, table: Optional[OnlineTable] = None) -> Wait[OnlineTable]:
7894
8632
  """Create an Online Table.
7895
8633
 
7896
8634
  Create a new Online Table.
7897
8635
 
7898
- :param name: str (optional)
7899
- Full three-part (catalog, schema, table) name of the table.
7900
- :param spec: :class:`OnlineTableSpec` (optional)
7901
- Specification of the online table.
8636
+ :param table: :class:`OnlineTable` (optional)
8637
+ Online Table information.
7902
8638
 
7903
- :returns: :class:`OnlineTable`
8639
+ :returns:
8640
+ Long-running operation waiter for :class:`OnlineTable`.
8641
+ See :method:wait_get_online_table_active for more details.
7904
8642
  """
7905
- body = {}
7906
- if name is not None: body['name'] = name
7907
- if spec is not None: body['spec'] = spec.as_dict()
8643
+ body = table
7908
8644
  headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7909
8645
 
7910
- res = self._api.do('POST', '/api/2.0/online-tables', body=body, headers=headers)
7911
- return OnlineTable.from_dict(res)
8646
+ op_response = self._api.do('POST', '/api/2.0/online-tables', body=body, headers=headers)
8647
+ return Wait(self.wait_get_online_table_active,
8648
+ response=OnlineTable.from_dict(op_response),
8649
+ name=op_response['name'])
8650
+
8651
+ def create_and_wait(self,
8652
+ *,
8653
+ table: Optional[OnlineTable] = None,
8654
+ timeout=timedelta(minutes=20)) -> OnlineTable:
8655
+ return self.create(table=table).result(timeout=timeout)
7912
8656
 
7913
8657
  def delete(self, name: str):
7914
8658
  """Delete an Online Table.
@@ -9019,7 +9763,6 @@ class StorageCredentialsAPI:
9019
9763
  :param force: bool (optional)
9020
9764
  Force update even if there are dependent external locations or external tables.
9021
9765
  :param isolation_mode: :class:`IsolationMode` (optional)
9022
- Whether the current securable is accessible from all workspaces or a specific set of workspaces.
9023
9766
  :param new_name: str (optional)
9024
9767
  New name for the storage credential.
9025
9768
  :param owner: str (optional)