databricks-sdk 0.36.0__py3-none-any.whl → 0.38.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: str
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
@@ -416,6 +508,8 @@ class AzureManagedIdentityResponse:
416
508
 
417
509
  @dataclass
418
510
  class AzureServicePrincipal:
511
+ """The Azure service principal configuration."""
512
+
419
513
  directory_id: str
420
514
  """The directory ID corresponding to the Azure Active Directory (AAD) tenant of the application."""
421
515
 
@@ -793,6 +887,7 @@ class ColumnTypeName(Enum):
793
887
  TIMESTAMP = 'TIMESTAMP'
794
888
  TIMESTAMP_NTZ = 'TIMESTAMP_NTZ'
795
889
  USER_DEFINED_TYPE = 'USER_DEFINED_TYPE'
890
+ VARIANT = 'VARIANT'
796
891
 
797
892
 
798
893
  @dataclass
@@ -1066,6 +1161,66 @@ class CreateConnection:
1066
1161
  read_only=d.get('read_only', None))
1067
1162
 
1068
1163
 
1164
+ @dataclass
1165
+ class CreateCredentialRequest:
1166
+ name: str
1167
+ """The credential name. The name must be unique among storage and service credentials within the
1168
+ metastore."""
1169
+
1170
+ aws_iam_role: Optional[AwsIamRole] = None
1171
+ """The AWS IAM role configuration"""
1172
+
1173
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
1174
+ """The Azure managed identity configuration."""
1175
+
1176
+ azure_service_principal: Optional[AzureServicePrincipal] = None
1177
+ """The Azure service principal configuration."""
1178
+
1179
+ comment: Optional[str] = None
1180
+ """Comment associated with the credential."""
1181
+
1182
+ gcp_service_account_key: Optional[GcpServiceAccountKey] = None
1183
+
1184
+ purpose: Optional[CredentialPurpose] = None
1185
+ """Indicates the purpose of the credential."""
1186
+
1187
+ read_only: Optional[bool] = None
1188
+ """Whether the credential is usable only for read operations. Only applicable when purpose is
1189
+ **STORAGE**."""
1190
+
1191
+ skip_validation: Optional[bool] = None
1192
+ """Optional. Supplying true to this argument skips validation of the created set of credentials."""
1193
+
1194
+ def as_dict(self) -> dict:
1195
+ """Serializes the CreateCredentialRequest into a dictionary suitable for use as a JSON request body."""
1196
+ body = {}
1197
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
1198
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
1199
+ if self.azure_service_principal:
1200
+ body['azure_service_principal'] = self.azure_service_principal.as_dict()
1201
+ if self.comment is not None: body['comment'] = self.comment
1202
+ if self.gcp_service_account_key:
1203
+ body['gcp_service_account_key'] = self.gcp_service_account_key.as_dict()
1204
+ if self.name is not None: body['name'] = self.name
1205
+ if self.purpose is not None: body['purpose'] = self.purpose.value
1206
+ if self.read_only is not None: body['read_only'] = self.read_only
1207
+ if self.skip_validation is not None: body['skip_validation'] = self.skip_validation
1208
+ return body
1209
+
1210
+ @classmethod
1211
+ def from_dict(cls, d: Dict[str, any]) -> CreateCredentialRequest:
1212
+ """Deserializes the CreateCredentialRequest from a dictionary."""
1213
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
1214
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
1215
+ azure_service_principal=_from_dict(d, 'azure_service_principal', AzureServicePrincipal),
1216
+ comment=d.get('comment', None),
1217
+ gcp_service_account_key=_from_dict(d, 'gcp_service_account_key', GcpServiceAccountKey),
1218
+ name=d.get('name', None),
1219
+ purpose=_enum(d, 'purpose', CredentialPurpose),
1220
+ read_only=d.get('read_only', None),
1221
+ skip_validation=d.get('skip_validation', None))
1222
+
1223
+
1069
1224
  @dataclass
1070
1225
  class CreateExternalLocation:
1071
1226
  name: str
@@ -1278,7 +1433,7 @@ class CreateFunctionRoutineBody(Enum):
1278
1433
 
1279
1434
 
1280
1435
  class CreateFunctionSecurityType(Enum):
1281
- """Function security type."""
1436
+ """The security type of the function."""
1282
1437
 
1283
1438
  DEFINER = 'DEFINER'
1284
1439
 
@@ -1439,29 +1594,6 @@ class CreateMonitor:
1439
1594
  warehouse_id=d.get('warehouse_id', None))
1440
1595
 
1441
1596
 
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
1597
  @dataclass
1466
1598
  class CreateRegisteredModelRequest:
1467
1599
  catalog_name: str
@@ -1675,6 +1807,114 @@ class CreateVolumeRequestContent:
1675
1807
  volume_type=_enum(d, 'volume_type', VolumeType))
1676
1808
 
1677
1809
 
1810
+ @dataclass
1811
+ class CredentialInfo:
1812
+ aws_iam_role: Optional[AwsIamRole] = None
1813
+ """The AWS IAM role configuration"""
1814
+
1815
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
1816
+ """The Azure managed identity configuration."""
1817
+
1818
+ azure_service_principal: Optional[AzureServicePrincipal] = None
1819
+ """The Azure service principal configuration."""
1820
+
1821
+ comment: Optional[str] = None
1822
+ """Comment associated with the credential."""
1823
+
1824
+ created_at: Optional[int] = None
1825
+ """Time at which this credential was created, in epoch milliseconds."""
1826
+
1827
+ created_by: Optional[str] = None
1828
+ """Username of credential creator."""
1829
+
1830
+ full_name: Optional[str] = None
1831
+ """The full name of the credential."""
1832
+
1833
+ id: Optional[str] = None
1834
+ """The unique identifier of the credential."""
1835
+
1836
+ isolation_mode: Optional[IsolationMode] = None
1837
+ """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
1838
+
1839
+ metastore_id: Optional[str] = None
1840
+ """Unique identifier of the parent metastore."""
1841
+
1842
+ name: Optional[str] = None
1843
+ """The credential name. The name must be unique among storage and service credentials within the
1844
+ metastore."""
1845
+
1846
+ owner: Optional[str] = None
1847
+ """Username of current owner of credential."""
1848
+
1849
+ purpose: Optional[CredentialPurpose] = None
1850
+ """Indicates the purpose of the credential."""
1851
+
1852
+ read_only: Optional[bool] = None
1853
+ """Whether the credential is usable only for read operations. Only applicable when purpose is
1854
+ **STORAGE**."""
1855
+
1856
+ updated_at: Optional[int] = None
1857
+ """Time at which this credential was last modified, in epoch milliseconds."""
1858
+
1859
+ updated_by: Optional[str] = None
1860
+ """Username of user who last modified the credential."""
1861
+
1862
+ used_for_managed_storage: Optional[bool] = None
1863
+ """Whether this credential is the current metastore's root storage credential. Only applicable when
1864
+ purpose is **STORAGE**."""
1865
+
1866
+ def as_dict(self) -> dict:
1867
+ """Serializes the CredentialInfo into a dictionary suitable for use as a JSON request body."""
1868
+ body = {}
1869
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
1870
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
1871
+ if self.azure_service_principal:
1872
+ body['azure_service_principal'] = self.azure_service_principal.as_dict()
1873
+ if self.comment is not None: body['comment'] = self.comment
1874
+ if self.created_at is not None: body['created_at'] = self.created_at
1875
+ if self.created_by is not None: body['created_by'] = self.created_by
1876
+ if self.full_name is not None: body['full_name'] = self.full_name
1877
+ if self.id is not None: body['id'] = self.id
1878
+ if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
1879
+ if self.metastore_id is not None: body['metastore_id'] = self.metastore_id
1880
+ if self.name is not None: body['name'] = self.name
1881
+ if self.owner is not None: body['owner'] = self.owner
1882
+ if self.purpose is not None: body['purpose'] = self.purpose.value
1883
+ if self.read_only is not None: body['read_only'] = self.read_only
1884
+ if self.updated_at is not None: body['updated_at'] = self.updated_at
1885
+ if self.updated_by is not None: body['updated_by'] = self.updated_by
1886
+ if self.used_for_managed_storage is not None:
1887
+ body['used_for_managed_storage'] = self.used_for_managed_storage
1888
+ return body
1889
+
1890
+ @classmethod
1891
+ def from_dict(cls, d: Dict[str, any]) -> CredentialInfo:
1892
+ """Deserializes the CredentialInfo from a dictionary."""
1893
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
1894
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
1895
+ azure_service_principal=_from_dict(d, 'azure_service_principal', AzureServicePrincipal),
1896
+ comment=d.get('comment', None),
1897
+ created_at=d.get('created_at', None),
1898
+ created_by=d.get('created_by', None),
1899
+ full_name=d.get('full_name', None),
1900
+ id=d.get('id', None),
1901
+ isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
1902
+ metastore_id=d.get('metastore_id', None),
1903
+ name=d.get('name', None),
1904
+ owner=d.get('owner', None),
1905
+ purpose=_enum(d, 'purpose', CredentialPurpose),
1906
+ read_only=d.get('read_only', None),
1907
+ updated_at=d.get('updated_at', None),
1908
+ updated_by=d.get('updated_by', None),
1909
+ used_for_managed_storage=d.get('used_for_managed_storage', None))
1910
+
1911
+
1912
+ class CredentialPurpose(Enum):
1913
+
1914
+ SERVICE = 'SERVICE'
1915
+ STORAGE = 'STORAGE'
1916
+
1917
+
1678
1918
  class CredentialType(Enum):
1679
1919
  """The type of credential."""
1680
1920
 
@@ -1682,6 +1922,27 @@ class CredentialType(Enum):
1682
1922
  USERNAME_PASSWORD = 'USERNAME_PASSWORD'
1683
1923
 
1684
1924
 
1925
+ @dataclass
1926
+ class CredentialValidationResult:
1927
+ message: Optional[str] = None
1928
+ """Error message would exist when the result does not equal to **PASS**."""
1929
+
1930
+ result: Optional[ValidateCredentialResult] = None
1931
+ """The results of the tested operation."""
1932
+
1933
+ def as_dict(self) -> dict:
1934
+ """Serializes the CredentialValidationResult into a dictionary suitable for use as a JSON request body."""
1935
+ body = {}
1936
+ if self.message is not None: body['message'] = self.message
1937
+ if self.result is not None: body['result'] = self.result.value
1938
+ return body
1939
+
1940
+ @classmethod
1941
+ def from_dict(cls, d: Dict[str, any]) -> CredentialValidationResult:
1942
+ """Deserializes the CredentialValidationResult from a dictionary."""
1943
+ return cls(message=d.get('message', None), result=_enum(d, 'result', ValidateCredentialResult))
1944
+
1945
+
1685
1946
  @dataclass
1686
1947
  class CurrentWorkspaceBindings:
1687
1948
  """Currently assigned workspaces"""
@@ -1778,6 +2039,20 @@ class DeleteAliasResponse:
1778
2039
  return cls()
1779
2040
 
1780
2041
 
2042
+ @dataclass
2043
+ class DeleteCredentialResponse:
2044
+
2045
+ def as_dict(self) -> dict:
2046
+ """Serializes the DeleteCredentialResponse into a dictionary suitable for use as a JSON request body."""
2047
+ body = {}
2048
+ return body
2049
+
2050
+ @classmethod
2051
+ def from_dict(cls, d: Dict[str, any]) -> DeleteCredentialResponse:
2052
+ """Deserializes the DeleteCredentialResponse from a dictionary."""
2053
+ return cls()
2054
+
2055
+
1781
2056
  @dataclass
1782
2057
  class DeleteResponse:
1783
2058
 
@@ -2052,7 +2327,6 @@ class ExternalLocationInfo:
2052
2327
  sufficient."""
2053
2328
 
2054
2329
  isolation_mode: Optional[IsolationMode] = None
2055
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
2056
2330
 
2057
2331
  metastore_id: Optional[str] = None
2058
2332
  """Unique identifier of metastore hosting the external location."""
@@ -2382,7 +2656,7 @@ class FunctionInfoRoutineBody(Enum):
2382
2656
 
2383
2657
 
2384
2658
  class FunctionInfoSecurityType(Enum):
2385
- """Function security type."""
2659
+ """The security type of the function."""
2386
2660
 
2387
2661
  DEFINER = 'DEFINER'
2388
2662
 
@@ -2516,6 +2790,79 @@ class GcpOauthToken:
2516
2790
  return cls(oauth_token=d.get('oauth_token', None))
2517
2791
 
2518
2792
 
2793
+ @dataclass
2794
+ class GcpServiceAccountKey:
2795
+ """GCP long-lived credential. GCP Service Account."""
2796
+
2797
+ email: Optional[str] = None
2798
+ """The email of the service account."""
2799
+
2800
+ private_key: Optional[str] = None
2801
+ """The service account's RSA private key."""
2802
+
2803
+ private_key_id: Optional[str] = None
2804
+ """The ID of the service account's private key."""
2805
+
2806
+ def as_dict(self) -> dict:
2807
+ """Serializes the GcpServiceAccountKey into a dictionary suitable for use as a JSON request body."""
2808
+ body = {}
2809
+ if self.email is not None: body['email'] = self.email
2810
+ if self.private_key is not None: body['private_key'] = self.private_key
2811
+ if self.private_key_id is not None: body['private_key_id'] = self.private_key_id
2812
+ return body
2813
+
2814
+ @classmethod
2815
+ def from_dict(cls, d: Dict[str, any]) -> GcpServiceAccountKey:
2816
+ """Deserializes the GcpServiceAccountKey from a dictionary."""
2817
+ return cls(email=d.get('email', None),
2818
+ private_key=d.get('private_key', None),
2819
+ private_key_id=d.get('private_key_id', None))
2820
+
2821
+
2822
+ @dataclass
2823
+ class GenerateTemporaryServiceCredentialAzureOptions:
2824
+ """Options to customize the requested temporary credential"""
2825
+
2826
+ resources: Optional[List[str]] = None
2827
+ """The resources to which the temporary Azure credential should apply. These resources are the
2828
+ scopes that are passed to the token provider (see
2829
+ https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential?view=azure-python)"""
2830
+
2831
+ def as_dict(self) -> dict:
2832
+ """Serializes the GenerateTemporaryServiceCredentialAzureOptions into a dictionary suitable for use as a JSON request body."""
2833
+ body = {}
2834
+ if self.resources: body['resources'] = [v for v in self.resources]
2835
+ return body
2836
+
2837
+ @classmethod
2838
+ def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryServiceCredentialAzureOptions:
2839
+ """Deserializes the GenerateTemporaryServiceCredentialAzureOptions from a dictionary."""
2840
+ return cls(resources=d.get('resources', None))
2841
+
2842
+
2843
+ @dataclass
2844
+ class GenerateTemporaryServiceCredentialRequest:
2845
+ credential_name: str
2846
+ """The name of the service credential used to generate a temporary credential"""
2847
+
2848
+ azure_options: Optional[GenerateTemporaryServiceCredentialAzureOptions] = None
2849
+ """Options to customize the requested temporary credential"""
2850
+
2851
+ def as_dict(self) -> dict:
2852
+ """Serializes the GenerateTemporaryServiceCredentialRequest into a dictionary suitable for use as a JSON request body."""
2853
+ body = {}
2854
+ if self.azure_options: body['azure_options'] = self.azure_options.as_dict()
2855
+ if self.credential_name is not None: body['credential_name'] = self.credential_name
2856
+ return body
2857
+
2858
+ @classmethod
2859
+ def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryServiceCredentialRequest:
2860
+ """Deserializes the GenerateTemporaryServiceCredentialRequest from a dictionary."""
2861
+ return cls(azure_options=_from_dict(d, 'azure_options',
2862
+ GenerateTemporaryServiceCredentialAzureOptions),
2863
+ credential_name=d.get('credential_name', None))
2864
+
2865
+
2519
2866
  @dataclass
2520
2867
  class GenerateTemporaryTableCredentialRequest:
2521
2868
  operation: Optional[TableOperation] = None
@@ -2545,6 +2892,11 @@ class GenerateTemporaryTableCredentialResponse:
2545
2892
  """AWS temporary credentials for API authentication. Read more at
2546
2893
  https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html."""
2547
2894
 
2895
+ azure_aad: Optional[AzureActiveDirectoryToken] = None
2896
+ """Azure Active Directory token, essentially the Oauth token for Azure Service Principal or Managed
2897
+ Identity. Read more at
2898
+ https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token"""
2899
+
2548
2900
  azure_user_delegation_sas: Optional[AzureUserDelegationSas] = None
2549
2901
  """Azure temporary credentials for API authentication. Read more at
2550
2902
  https://docs.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas"""
@@ -2568,6 +2920,7 @@ class GenerateTemporaryTableCredentialResponse:
2568
2920
  """Serializes the GenerateTemporaryTableCredentialResponse into a dictionary suitable for use as a JSON request body."""
2569
2921
  body = {}
2570
2922
  if self.aws_temp_credentials: body['aws_temp_credentials'] = self.aws_temp_credentials.as_dict()
2923
+ if self.azure_aad: body['azure_aad'] = self.azure_aad.as_dict()
2571
2924
  if self.azure_user_delegation_sas:
2572
2925
  body['azure_user_delegation_sas'] = self.azure_user_delegation_sas.as_dict()
2573
2926
  if self.expiration_time is not None: body['expiration_time'] = self.expiration_time
@@ -2580,6 +2933,7 @@ class GenerateTemporaryTableCredentialResponse:
2580
2933
  def from_dict(cls, d: Dict[str, any]) -> GenerateTemporaryTableCredentialResponse:
2581
2934
  """Deserializes the GenerateTemporaryTableCredentialResponse from a dictionary."""
2582
2935
  return cls(aws_temp_credentials=_from_dict(d, 'aws_temp_credentials', AwsCredentials),
2936
+ azure_aad=_from_dict(d, 'azure_aad', AzureActiveDirectoryToken),
2583
2937
  azure_user_delegation_sas=_from_dict(d, 'azure_user_delegation_sas',
2584
2938
  AzureUserDelegationSas),
2585
2939
  expiration_time=d.get('expiration_time', None),
@@ -2592,6 +2946,7 @@ class GetBindingsSecurableType(Enum):
2592
2946
 
2593
2947
  CATALOG = 'catalog'
2594
2948
  EXTERNAL_LOCATION = 'external_location'
2949
+ SERVICE_CREDENTIAL = 'service_credential'
2595
2950
  STORAGE_CREDENTIAL = 'storage_credential'
2596
2951
 
2597
2952
 
@@ -2738,7 +3093,6 @@ class GetQuotaResponse:
2738
3093
 
2739
3094
 
2740
3095
  class IsolationMode(Enum):
2741
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
2742
3096
 
2743
3097
  ISOLATION_MODE_ISOLATED = 'ISOLATION_MODE_ISOLATED'
2744
3098
  ISOLATION_MODE_OPEN = 'ISOLATION_MODE_OPEN'
@@ -2826,6 +3180,28 @@ class ListConnectionsResponse:
2826
3180
  next_page_token=d.get('next_page_token', None))
2827
3181
 
2828
3182
 
3183
+ @dataclass
3184
+ class ListCredentialsResponse:
3185
+ credentials: Optional[List[CredentialInfo]] = None
3186
+
3187
+ next_page_token: Optional[str] = None
3188
+ """Opaque token to retrieve the next page of results. Absent if there are no more pages.
3189
+ __page_token__ should be set to this value for the next request (for the next page of results)."""
3190
+
3191
+ def as_dict(self) -> dict:
3192
+ """Serializes the ListCredentialsResponse into a dictionary suitable for use as a JSON request body."""
3193
+ body = {}
3194
+ if self.credentials: body['credentials'] = [v.as_dict() for v in self.credentials]
3195
+ if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
3196
+ return body
3197
+
3198
+ @classmethod
3199
+ def from_dict(cls, d: Dict[str, any]) -> ListCredentialsResponse:
3200
+ """Deserializes the ListCredentialsResponse from a dictionary."""
3201
+ return cls(credentials=_repeated_dict(d, 'credentials', CredentialInfo),
3202
+ next_page_token=d.get('next_page_token', None))
3203
+
3204
+
2829
3205
  @dataclass
2830
3206
  class ListExternalLocationsResponse:
2831
3207
  external_locations: Optional[List[ExternalLocationInfo]] = None
@@ -4619,6 +4995,7 @@ class SecurableType(Enum):
4619
4995
 
4620
4996
  CATALOG = 'catalog'
4621
4997
  CONNECTION = 'connection'
4998
+ CREDENTIAL = 'credential'
4622
4999
  EXTERNAL_LOCATION = 'external_location'
4623
5000
  FUNCTION = 'function'
4624
5001
  METASTORE = 'metastore'
@@ -4738,11 +5115,13 @@ class StorageCredentialInfo:
4738
5115
  databricks_gcp_service_account: Optional[DatabricksGcpServiceAccountResponse] = None
4739
5116
  """The Databricks managed GCP service account configuration."""
4740
5117
 
5118
+ full_name: Optional[str] = None
5119
+ """The full name of the credential."""
5120
+
4741
5121
  id: Optional[str] = None
4742
5122
  """The unique identifier of the credential."""
4743
5123
 
4744
5124
  isolation_mode: Optional[IsolationMode] = None
4745
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
4746
5125
 
4747
5126
  metastore_id: Optional[str] = None
4748
5127
  """Unique identifier of parent metastore."""
@@ -4778,6 +5157,7 @@ class StorageCredentialInfo:
4778
5157
  if self.created_by is not None: body['created_by'] = self.created_by
4779
5158
  if self.databricks_gcp_service_account:
4780
5159
  body['databricks_gcp_service_account'] = self.databricks_gcp_service_account.as_dict()
5160
+ if self.full_name is not None: body['full_name'] = self.full_name
4781
5161
  if self.id is not None: body['id'] = self.id
4782
5162
  if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
4783
5163
  if self.metastore_id is not None: body['metastore_id'] = self.metastore_id
@@ -4803,6 +5183,7 @@ class StorageCredentialInfo:
4803
5183
  created_by=d.get('created_by', None),
4804
5184
  databricks_gcp_service_account=_from_dict(d, 'databricks_gcp_service_account',
4805
5185
  DatabricksGcpServiceAccountResponse),
5186
+ full_name=d.get('full_name', None),
4806
5187
  id=d.get('id', None),
4807
5188
  isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
4808
5189
  metastore_id=d.get('metastore_id', None),
@@ -5158,6 +5539,37 @@ class TableType(Enum):
5158
5539
  VIEW = 'VIEW'
5159
5540
 
5160
5541
 
5542
+ @dataclass
5543
+ class TemporaryCredentials:
5544
+ aws_temp_credentials: Optional[AwsCredentials] = None
5545
+ """AWS temporary credentials for API authentication. Read more at
5546
+ https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html."""
5547
+
5548
+ azure_aad: Optional[AzureActiveDirectoryToken] = None
5549
+ """Azure Active Directory token, essentially the Oauth token for Azure Service Principal or Managed
5550
+ Identity. Read more at
5551
+ https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token"""
5552
+
5553
+ expiration_time: Optional[int] = None
5554
+ """Server time when the credential will expire, in epoch milliseconds. The API client is advised to
5555
+ cache the credential given this expiration time."""
5556
+
5557
+ def as_dict(self) -> dict:
5558
+ """Serializes the TemporaryCredentials into a dictionary suitable for use as a JSON request body."""
5559
+ body = {}
5560
+ if self.aws_temp_credentials: body['aws_temp_credentials'] = self.aws_temp_credentials.as_dict()
5561
+ if self.azure_aad: body['azure_aad'] = self.azure_aad.as_dict()
5562
+ if self.expiration_time is not None: body['expiration_time'] = self.expiration_time
5563
+ return body
5564
+
5565
+ @classmethod
5566
+ def from_dict(cls, d: Dict[str, any]) -> TemporaryCredentials:
5567
+ """Deserializes the TemporaryCredentials from a dictionary."""
5568
+ return cls(aws_temp_credentials=_from_dict(d, 'aws_temp_credentials', AwsCredentials),
5569
+ azure_aad=_from_dict(d, 'azure_aad', AzureActiveDirectoryToken),
5570
+ expiration_time=d.get('expiration_time', None))
5571
+
5572
+
5161
5573
  @dataclass
5162
5574
  class TriggeredUpdateStatus:
5163
5575
  """Detailed status of an online table. Shown if the online table is in the ONLINE_TRIGGERED_UPDATE
@@ -5224,6 +5636,7 @@ class UpdateBindingsSecurableType(Enum):
5224
5636
 
5225
5637
  CATALOG = 'catalog'
5226
5638
  EXTERNAL_LOCATION = 'external_location'
5639
+ SERVICE_CREDENTIAL = 'service_credential'
5227
5640
  STORAGE_CREDENTIAL = 'storage_credential'
5228
5641
 
5229
5642
 
@@ -5308,6 +5721,76 @@ class UpdateConnection:
5308
5721
  owner=d.get('owner', None))
5309
5722
 
5310
5723
 
5724
+ @dataclass
5725
+ class UpdateCredentialRequest:
5726
+ aws_iam_role: Optional[AwsIamRole] = None
5727
+ """The AWS IAM role configuration"""
5728
+
5729
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
5730
+ """The Azure managed identity configuration."""
5731
+
5732
+ azure_service_principal: Optional[AzureServicePrincipal] = None
5733
+ """The Azure service principal configuration."""
5734
+
5735
+ comment: Optional[str] = None
5736
+ """Comment associated with the credential."""
5737
+
5738
+ force: Optional[bool] = None
5739
+ """Force an update even if there are dependent services (when purpose is **SERVICE**) or dependent
5740
+ external locations and external tables (when purpose is **STORAGE**)."""
5741
+
5742
+ isolation_mode: Optional[IsolationMode] = None
5743
+ """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5744
+
5745
+ name_arg: Optional[str] = None
5746
+ """Name of the credential."""
5747
+
5748
+ new_name: Optional[str] = None
5749
+ """New name of credential."""
5750
+
5751
+ owner: Optional[str] = None
5752
+ """Username of current owner of credential."""
5753
+
5754
+ read_only: Optional[bool] = None
5755
+ """Whether the credential is usable only for read operations. Only applicable when purpose is
5756
+ **STORAGE**."""
5757
+
5758
+ skip_validation: Optional[bool] = None
5759
+ """Supply true to this argument to skip validation of the updated credential."""
5760
+
5761
+ def as_dict(self) -> dict:
5762
+ """Serializes the UpdateCredentialRequest into a dictionary suitable for use as a JSON request body."""
5763
+ body = {}
5764
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
5765
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
5766
+ if self.azure_service_principal:
5767
+ body['azure_service_principal'] = self.azure_service_principal.as_dict()
5768
+ if self.comment is not None: body['comment'] = self.comment
5769
+ if self.force is not None: body['force'] = self.force
5770
+ if self.isolation_mode is not None: body['isolation_mode'] = self.isolation_mode.value
5771
+ if self.name_arg is not None: body['name_arg'] = self.name_arg
5772
+ if self.new_name is not None: body['new_name'] = self.new_name
5773
+ if self.owner is not None: body['owner'] = self.owner
5774
+ if self.read_only is not None: body['read_only'] = self.read_only
5775
+ if self.skip_validation is not None: body['skip_validation'] = self.skip_validation
5776
+ return body
5777
+
5778
+ @classmethod
5779
+ def from_dict(cls, d: Dict[str, any]) -> UpdateCredentialRequest:
5780
+ """Deserializes the UpdateCredentialRequest from a dictionary."""
5781
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
5782
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
5783
+ azure_service_principal=_from_dict(d, 'azure_service_principal', AzureServicePrincipal),
5784
+ comment=d.get('comment', None),
5785
+ force=d.get('force', None),
5786
+ isolation_mode=_enum(d, 'isolation_mode', IsolationMode),
5787
+ name_arg=d.get('name_arg', None),
5788
+ new_name=d.get('new_name', None),
5789
+ owner=d.get('owner', None),
5790
+ read_only=d.get('read_only', None),
5791
+ skip_validation=d.get('skip_validation', None))
5792
+
5793
+
5311
5794
  @dataclass
5312
5795
  class UpdateExternalLocation:
5313
5796
  access_point: Optional[str] = None
@@ -5331,7 +5814,6 @@ class UpdateExternalLocation:
5331
5814
  """Force update even if changing url invalidates dependent external tables or mounts."""
5332
5815
 
5333
5816
  isolation_mode: Optional[IsolationMode] = None
5334
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5335
5817
 
5336
5818
  name: Optional[str] = None
5337
5819
  """Name of the external location."""
@@ -5751,7 +6233,6 @@ class UpdateStorageCredential:
5751
6233
  """Force update even if there are dependent external locations or external tables."""
5752
6234
 
5753
6235
  isolation_mode: Optional[IsolationMode] = None
5754
- """Whether the current securable is accessible from all workspaces or a specific set of workspaces."""
5755
6236
 
5756
6237
  name: Optional[str] = None
5757
6238
  """Name of the storage credential."""
@@ -5899,6 +6380,87 @@ class UpdateWorkspaceBindingsParameters:
5899
6380
  securable_type=_enum(d, 'securable_type', UpdateBindingsSecurableType))
5900
6381
 
5901
6382
 
6383
+ @dataclass
6384
+ class ValidateCredentialRequest:
6385
+ aws_iam_role: Optional[AwsIamRole] = None
6386
+ """The AWS IAM role configuration"""
6387
+
6388
+ azure_managed_identity: Optional[AzureManagedIdentity] = None
6389
+ """The Azure managed identity configuration."""
6390
+
6391
+ credential_name: Optional[str] = None
6392
+ """Required. The name of an existing credential or long-lived cloud credential to validate."""
6393
+
6394
+ external_location_name: Optional[str] = None
6395
+ """The name of an existing external location to validate. Only applicable for storage credentials
6396
+ (purpose is **STORAGE**.)"""
6397
+
6398
+ purpose: Optional[CredentialPurpose] = None
6399
+ """The purpose of the credential. This should only be used when the credential is specified."""
6400
+
6401
+ read_only: Optional[bool] = None
6402
+ """Whether the credential is only usable for read operations. Only applicable for storage
6403
+ credentials (purpose is **STORAGE**.)"""
6404
+
6405
+ url: Optional[str] = None
6406
+ """The external location url to validate. Only applicable when purpose is **STORAGE**."""
6407
+
6408
+ def as_dict(self) -> dict:
6409
+ """Serializes the ValidateCredentialRequest into a dictionary suitable for use as a JSON request body."""
6410
+ body = {}
6411
+ if self.aws_iam_role: body['aws_iam_role'] = self.aws_iam_role.as_dict()
6412
+ if self.azure_managed_identity: body['azure_managed_identity'] = self.azure_managed_identity.as_dict()
6413
+ if self.credential_name is not None: body['credential_name'] = self.credential_name
6414
+ if self.external_location_name is not None:
6415
+ body['external_location_name'] = self.external_location_name
6416
+ if self.purpose is not None: body['purpose'] = self.purpose.value
6417
+ if self.read_only is not None: body['read_only'] = self.read_only
6418
+ if self.url is not None: body['url'] = self.url
6419
+ return body
6420
+
6421
+ @classmethod
6422
+ def from_dict(cls, d: Dict[str, any]) -> ValidateCredentialRequest:
6423
+ """Deserializes the ValidateCredentialRequest from a dictionary."""
6424
+ return cls(aws_iam_role=_from_dict(d, 'aws_iam_role', AwsIamRole),
6425
+ azure_managed_identity=_from_dict(d, 'azure_managed_identity', AzureManagedIdentity),
6426
+ credential_name=d.get('credential_name', None),
6427
+ external_location_name=d.get('external_location_name', None),
6428
+ purpose=_enum(d, 'purpose', CredentialPurpose),
6429
+ read_only=d.get('read_only', None),
6430
+ url=d.get('url', None))
6431
+
6432
+
6433
+ @dataclass
6434
+ class ValidateCredentialResponse:
6435
+ is_dir: Optional[bool] = None
6436
+ """Whether the tested location is a directory in cloud storage. Only applicable for when purpose is
6437
+ **STORAGE**."""
6438
+
6439
+ results: Optional[List[CredentialValidationResult]] = None
6440
+ """The results of the validation check."""
6441
+
6442
+ def as_dict(self) -> dict:
6443
+ """Serializes the ValidateCredentialResponse into a dictionary suitable for use as a JSON request body."""
6444
+ body = {}
6445
+ if self.is_dir is not None: body['isDir'] = self.is_dir
6446
+ if self.results: body['results'] = [v.as_dict() for v in self.results]
6447
+ return body
6448
+
6449
+ @classmethod
6450
+ def from_dict(cls, d: Dict[str, any]) -> ValidateCredentialResponse:
6451
+ """Deserializes the ValidateCredentialResponse from a dictionary."""
6452
+ return cls(is_dir=d.get('isDir', None),
6453
+ results=_repeated_dict(d, 'results', CredentialValidationResult))
6454
+
6455
+
6456
+ class ValidateCredentialResult(Enum):
6457
+ """A enum represents the result of the file operation"""
6458
+
6459
+ FAIL = 'FAIL'
6460
+ PASS = 'PASS'
6461
+ SKIP = 'SKIP'
6462
+
6463
+
5902
6464
  @dataclass
5903
6465
  class ValidateStorageCredential:
5904
6466
  aws_iam_role: Optional[AwsIamRoleRequest] = None
@@ -6935,6 +7497,312 @@ class ConnectionsAPI:
6935
7497
  return ConnectionInfo.from_dict(res)
6936
7498
 
6937
7499
 
7500
+ class CredentialsAPI:
7501
+ """A credential represents an authentication and authorization mechanism for accessing services on your cloud
7502
+ tenant. Each credential is subject to Unity Catalog access-control policies that control which users and
7503
+ groups can access the credential.
7504
+
7505
+ To create credentials, you must be a Databricks account admin or have the `CREATE SERVICE CREDENTIAL
7506
+ privilege. The user who creates the credential can delegate ownership to another user or group to manage
7507
+ permissions on it"""
7508
+
7509
+ def __init__(self, api_client):
7510
+ self._api = api_client
7511
+
7512
+ def create_credential(self,
7513
+ name: str,
7514
+ *,
7515
+ aws_iam_role: Optional[AwsIamRole] = None,
7516
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7517
+ azure_service_principal: Optional[AzureServicePrincipal] = None,
7518
+ comment: Optional[str] = None,
7519
+ gcp_service_account_key: Optional[GcpServiceAccountKey] = None,
7520
+ purpose: Optional[CredentialPurpose] = None,
7521
+ read_only: Optional[bool] = None,
7522
+ skip_validation: Optional[bool] = None) -> CredentialInfo:
7523
+ """Create a credential.
7524
+
7525
+ Creates a new credential. The type of credential to be created is determined by the **purpose** field,
7526
+ which should be either **SERVICE** or **STORAGE**.
7527
+
7528
+ The caller must be a metastore admin or have the metastore privilege **CREATE_STORAGE_CREDENTIAL** for
7529
+ storage credentials, or **CREATE_SERVICE_CREDENTIAL** for service credentials.
7530
+
7531
+ :param name: str
7532
+ The credential name. The name must be unique among storage and service credentials within the
7533
+ metastore.
7534
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7535
+ The AWS IAM role configuration
7536
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7537
+ The Azure managed identity configuration.
7538
+ :param azure_service_principal: :class:`AzureServicePrincipal` (optional)
7539
+ The Azure service principal configuration.
7540
+ :param comment: str (optional)
7541
+ Comment associated with the credential.
7542
+ :param gcp_service_account_key: :class:`GcpServiceAccountKey` (optional)
7543
+ :param purpose: :class:`CredentialPurpose` (optional)
7544
+ Indicates the purpose of the credential.
7545
+ :param read_only: bool (optional)
7546
+ Whether the credential is usable only for read operations. Only applicable when purpose is
7547
+ **STORAGE**.
7548
+ :param skip_validation: bool (optional)
7549
+ Optional. Supplying true to this argument skips validation of the created set of credentials.
7550
+
7551
+ :returns: :class:`CredentialInfo`
7552
+ """
7553
+ body = {}
7554
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7555
+ if azure_managed_identity is not None:
7556
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7557
+ if azure_service_principal is not None:
7558
+ body['azure_service_principal'] = azure_service_principal.as_dict()
7559
+ if comment is not None: body['comment'] = comment
7560
+ if gcp_service_account_key is not None:
7561
+ body['gcp_service_account_key'] = gcp_service_account_key.as_dict()
7562
+ if name is not None: body['name'] = name
7563
+ if purpose is not None: body['purpose'] = purpose.value
7564
+ if read_only is not None: body['read_only'] = read_only
7565
+ if skip_validation is not None: body['skip_validation'] = skip_validation
7566
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7567
+
7568
+ res = self._api.do('POST', '/api/2.1/unity-catalog/credentials', body=body, headers=headers)
7569
+ return CredentialInfo.from_dict(res)
7570
+
7571
+ def delete_credential(self, name_arg: str, *, force: Optional[bool] = None):
7572
+ """Delete a credential.
7573
+
7574
+ Deletes a service or storage credential from the metastore. The caller must be an owner of the
7575
+ credential.
7576
+
7577
+ :param name_arg: str
7578
+ Name of the credential.
7579
+ :param force: bool (optional)
7580
+ Force an update even if there are dependent services (when purpose is **SERVICE**) or dependent
7581
+ external locations and external tables (when purpose is **STORAGE**).
7582
+
7583
+
7584
+ """
7585
+
7586
+ query = {}
7587
+ if force is not None: query['force'] = force
7588
+ headers = {'Accept': 'application/json', }
7589
+
7590
+ self._api.do('DELETE', f'/api/2.1/unity-catalog/credentials/{name_arg}', query=query, headers=headers)
7591
+
7592
+ def generate_temporary_service_credential(
7593
+ self,
7594
+ credential_name: str,
7595
+ *,
7596
+ azure_options: Optional[GenerateTemporaryServiceCredentialAzureOptions] = None
7597
+ ) -> TemporaryCredentials:
7598
+ """Generate a temporary service credential.
7599
+
7600
+ Returns a set of temporary credentials generated using the specified service credential. The caller
7601
+ must be a metastore admin or have the metastore privilege **ACCESS** on the service credential.
7602
+
7603
+ :param credential_name: str
7604
+ The name of the service credential used to generate a temporary credential
7605
+ :param azure_options: :class:`GenerateTemporaryServiceCredentialAzureOptions` (optional)
7606
+ Options to customize the requested temporary credential
7607
+
7608
+ :returns: :class:`TemporaryCredentials`
7609
+ """
7610
+ body = {}
7611
+ if azure_options is not None: body['azure_options'] = azure_options.as_dict()
7612
+ if credential_name is not None: body['credential_name'] = credential_name
7613
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7614
+
7615
+ res = self._api.do('POST',
7616
+ '/api/2.1/unity-catalog/temporary-service-credentials',
7617
+ body=body,
7618
+ headers=headers)
7619
+ return TemporaryCredentials.from_dict(res)
7620
+
7621
+ def get_credential(self, name_arg: str) -> CredentialInfo:
7622
+ """Get a credential.
7623
+
7624
+ Gets a service or storage credential from the metastore. The caller must be a metastore admin, the
7625
+ owner of the credential, or have any permission on the credential.
7626
+
7627
+ :param name_arg: str
7628
+ Name of the credential.
7629
+
7630
+ :returns: :class:`CredentialInfo`
7631
+ """
7632
+
7633
+ headers = {'Accept': 'application/json', }
7634
+
7635
+ res = self._api.do('GET', f'/api/2.1/unity-catalog/credentials/{name_arg}', headers=headers)
7636
+ return CredentialInfo.from_dict(res)
7637
+
7638
+ def list_credentials(self,
7639
+ *,
7640
+ max_results: Optional[int] = None,
7641
+ page_token: Optional[str] = None,
7642
+ purpose: Optional[CredentialPurpose] = None) -> Iterator[CredentialInfo]:
7643
+ """List credentials.
7644
+
7645
+ Gets an array of credentials (as __CredentialInfo__ objects).
7646
+
7647
+ The array is limited to only the credentials that the caller has permission to access. If the caller
7648
+ is a metastore admin, retrieval of credentials is unrestricted. There is no guarantee of a specific
7649
+ ordering of the elements in the array.
7650
+
7651
+ :param max_results: int (optional)
7652
+ Maximum number of credentials to return. - If not set, the default max page size is used. - When set
7653
+ to a value greater than 0, the page length is the minimum of this value and a server-configured
7654
+ value. - When set to 0, the page length is set to a server-configured value (recommended). - When
7655
+ set to a value less than 0, an invalid parameter error is returned.
7656
+ :param page_token: str (optional)
7657
+ Opaque token to retrieve the next page of results.
7658
+ :param purpose: :class:`CredentialPurpose` (optional)
7659
+ Return only credentials for the specified purpose.
7660
+
7661
+ :returns: Iterator over :class:`CredentialInfo`
7662
+ """
7663
+
7664
+ query = {}
7665
+ if max_results is not None: query['max_results'] = max_results
7666
+ if page_token is not None: query['page_token'] = page_token
7667
+ if purpose is not None: query['purpose'] = purpose.value
7668
+ headers = {'Accept': 'application/json', }
7669
+
7670
+ while True:
7671
+ json = self._api.do('GET', '/api/2.1/unity-catalog/credentials', query=query, headers=headers)
7672
+ if 'credentials' in json:
7673
+ for v in json['credentials']:
7674
+ yield CredentialInfo.from_dict(v)
7675
+ if 'next_page_token' not in json or not json['next_page_token']:
7676
+ return
7677
+ query['page_token'] = json['next_page_token']
7678
+
7679
+ def update_credential(self,
7680
+ name_arg: str,
7681
+ *,
7682
+ aws_iam_role: Optional[AwsIamRole] = None,
7683
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7684
+ azure_service_principal: Optional[AzureServicePrincipal] = None,
7685
+ comment: Optional[str] = None,
7686
+ force: Optional[bool] = None,
7687
+ isolation_mode: Optional[IsolationMode] = None,
7688
+ new_name: Optional[str] = None,
7689
+ owner: Optional[str] = None,
7690
+ read_only: Optional[bool] = None,
7691
+ skip_validation: Optional[bool] = None) -> CredentialInfo:
7692
+ """Update a credential.
7693
+
7694
+ Updates a service or storage credential on the metastore.
7695
+
7696
+ The caller must be the owner of the credential or a metastore admin or have the `MANAGE` permission.
7697
+ If the caller is a metastore admin, only the __owner__ field can be changed.
7698
+
7699
+ :param name_arg: str
7700
+ Name of the credential.
7701
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7702
+ The AWS IAM role configuration
7703
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7704
+ The Azure managed identity configuration.
7705
+ :param azure_service_principal: :class:`AzureServicePrincipal` (optional)
7706
+ The Azure service principal configuration.
7707
+ :param comment: str (optional)
7708
+ Comment associated with the credential.
7709
+ :param force: bool (optional)
7710
+ Force an update even if there are dependent services (when purpose is **SERVICE**) or dependent
7711
+ external locations and external tables (when purpose is **STORAGE**).
7712
+ :param isolation_mode: :class:`IsolationMode` (optional)
7713
+ Whether the current securable is accessible from all workspaces or a specific set of workspaces.
7714
+ :param new_name: str (optional)
7715
+ New name of credential.
7716
+ :param owner: str (optional)
7717
+ Username of current owner of credential.
7718
+ :param read_only: bool (optional)
7719
+ Whether the credential is usable only for read operations. Only applicable when purpose is
7720
+ **STORAGE**.
7721
+ :param skip_validation: bool (optional)
7722
+ Supply true to this argument to skip validation of the updated credential.
7723
+
7724
+ :returns: :class:`CredentialInfo`
7725
+ """
7726
+ body = {}
7727
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7728
+ if azure_managed_identity is not None:
7729
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7730
+ if azure_service_principal is not None:
7731
+ body['azure_service_principal'] = azure_service_principal.as_dict()
7732
+ if comment is not None: body['comment'] = comment
7733
+ if force is not None: body['force'] = force
7734
+ if isolation_mode is not None: body['isolation_mode'] = isolation_mode.value
7735
+ if new_name is not None: body['new_name'] = new_name
7736
+ if owner is not None: body['owner'] = owner
7737
+ if read_only is not None: body['read_only'] = read_only
7738
+ if skip_validation is not None: body['skip_validation'] = skip_validation
7739
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7740
+
7741
+ res = self._api.do('PATCH',
7742
+ f'/api/2.1/unity-catalog/credentials/{name_arg}',
7743
+ body=body,
7744
+ headers=headers)
7745
+ return CredentialInfo.from_dict(res)
7746
+
7747
+ def validate_credential(self,
7748
+ *,
7749
+ aws_iam_role: Optional[AwsIamRole] = None,
7750
+ azure_managed_identity: Optional[AzureManagedIdentity] = None,
7751
+ credential_name: Optional[str] = None,
7752
+ external_location_name: Optional[str] = None,
7753
+ purpose: Optional[CredentialPurpose] = None,
7754
+ read_only: Optional[bool] = None,
7755
+ url: Optional[str] = None) -> ValidateCredentialResponse:
7756
+ """Validate a credential.
7757
+
7758
+ Validates a credential.
7759
+
7760
+ For service credentials (purpose is **SERVICE**), either the __credential_name__ or the cloud-specific
7761
+ credential must be provided.
7762
+
7763
+ For storage credentials (purpose is **STORAGE**), at least one of __external_location_name__ and
7764
+ __url__ need to be provided. If only one of them is provided, it will be used for validation. And if
7765
+ both are provided, the __url__ will be used for validation, and __external_location_name__ will be
7766
+ ignored when checking overlapping urls. Either the __credential_name__ or the cloud-specific
7767
+ credential must be provided.
7768
+
7769
+ The caller must be a metastore admin or the credential owner or have the required permission on the
7770
+ metastore and the credential (e.g., **CREATE_EXTERNAL_LOCATION** when purpose is **STORAGE**).
7771
+
7772
+ :param aws_iam_role: :class:`AwsIamRole` (optional)
7773
+ The AWS IAM role configuration
7774
+ :param azure_managed_identity: :class:`AzureManagedIdentity` (optional)
7775
+ The Azure managed identity configuration.
7776
+ :param credential_name: str (optional)
7777
+ Required. The name of an existing credential or long-lived cloud credential to validate.
7778
+ :param external_location_name: str (optional)
7779
+ The name of an existing external location to validate. Only applicable for storage credentials
7780
+ (purpose is **STORAGE**.)
7781
+ :param purpose: :class:`CredentialPurpose` (optional)
7782
+ The purpose of the credential. This should only be used when the credential is specified.
7783
+ :param read_only: bool (optional)
7784
+ Whether the credential is only usable for read operations. Only applicable for storage credentials
7785
+ (purpose is **STORAGE**.)
7786
+ :param url: str (optional)
7787
+ The external location url to validate. Only applicable when purpose is **STORAGE**.
7788
+
7789
+ :returns: :class:`ValidateCredentialResponse`
7790
+ """
7791
+ body = {}
7792
+ if aws_iam_role is not None: body['aws_iam_role'] = aws_iam_role.as_dict()
7793
+ if azure_managed_identity is not None:
7794
+ body['azure_managed_identity'] = azure_managed_identity.as_dict()
7795
+ if credential_name is not None: body['credential_name'] = credential_name
7796
+ if external_location_name is not None: body['external_location_name'] = external_location_name
7797
+ if purpose is not None: body['purpose'] = purpose.value
7798
+ if read_only is not None: body['read_only'] = read_only
7799
+ if url is not None: body['url'] = url
7800
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7801
+
7802
+ res = self._api.do('POST', '/api/2.1/unity-catalog/validate-credentials', body=body, headers=headers)
7803
+ return ValidateCredentialResponse.from_dict(res)
7804
+
7805
+
6938
7806
  class ExternalLocationsAPI:
6939
7807
  """An external location is an object that combines a cloud storage path with a storage credential that
6940
7808
  authorizes access to the cloud storage path. Each external location is subject to Unity Catalog
@@ -7134,7 +8002,6 @@ class ExternalLocationsAPI:
7134
8002
  :param force: bool (optional)
7135
8003
  Force update even if changing url invalidates dependent external tables or mounts.
7136
8004
  :param isolation_mode: :class:`IsolationMode` (optional)
7137
- Whether the current securable is accessible from all workspaces or a specific set of workspaces.
7138
8005
  :param new_name: str (optional)
7139
8006
  New name for the external location.
7140
8007
  :param owner: str (optional)
@@ -7890,25 +8757,61 @@ class OnlineTablesAPI:
7890
8757
  def __init__(self, api_client):
7891
8758
  self._api = api_client
7892
8759
 
7893
- def create(self, *, name: Optional[str] = None, spec: Optional[OnlineTableSpec] = None) -> OnlineTable:
8760
+ def wait_get_online_table_active(self,
8761
+ name: str,
8762
+ timeout=timedelta(minutes=20),
8763
+ callback: Optional[Callable[[OnlineTable], None]] = None) -> OnlineTable:
8764
+ deadline = time.time() + timeout.total_seconds()
8765
+ target_states = (ProvisioningInfoState.ACTIVE, )
8766
+ failure_states = (ProvisioningInfoState.FAILED, )
8767
+ status_message = 'polling...'
8768
+ attempt = 1
8769
+ while time.time() < deadline:
8770
+ poll = self.get(name=name)
8771
+ status = poll.unity_catalog_provisioning_state
8772
+ status_message = f'current status: {status}'
8773
+ if status in target_states:
8774
+ return poll
8775
+ if callback:
8776
+ callback(poll)
8777
+ if status in failure_states:
8778
+ msg = f'failed to reach ACTIVE, got {status}: {status_message}'
8779
+ raise OperationFailed(msg)
8780
+ prefix = f"name={name}"
8781
+ sleep = attempt
8782
+ if sleep > 10:
8783
+ # sleep 10s max per attempt
8784
+ sleep = 10
8785
+ _LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
8786
+ time.sleep(sleep + random.random())
8787
+ attempt += 1
8788
+ raise TimeoutError(f'timed out after {timeout}: {status_message}')
8789
+
8790
+ def create(self, *, table: Optional[OnlineTable] = None) -> Wait[OnlineTable]:
7894
8791
  """Create an Online Table.
7895
8792
 
7896
8793
  Create a new Online Table.
7897
8794
 
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.
8795
+ :param table: :class:`OnlineTable` (optional)
8796
+ Online Table information.
7902
8797
 
7903
- :returns: :class:`OnlineTable`
8798
+ :returns:
8799
+ Long-running operation waiter for :class:`OnlineTable`.
8800
+ See :method:wait_get_online_table_active for more details.
7904
8801
  """
7905
- body = {}
7906
- if name is not None: body['name'] = name
7907
- if spec is not None: body['spec'] = spec.as_dict()
8802
+ body = table.as_dict()
7908
8803
  headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
7909
8804
 
7910
- res = self._api.do('POST', '/api/2.0/online-tables', body=body, headers=headers)
7911
- return OnlineTable.from_dict(res)
8805
+ op_response = self._api.do('POST', '/api/2.0/online-tables', body=body, headers=headers)
8806
+ return Wait(self.wait_get_online_table_active,
8807
+ response=OnlineTable.from_dict(op_response),
8808
+ name=op_response['name'])
8809
+
8810
+ def create_and_wait(self,
8811
+ *,
8812
+ table: Optional[OnlineTable] = None,
8813
+ timeout=timedelta(minutes=20)) -> OnlineTable:
8814
+ return self.create(table=table).result(timeout=timeout)
7912
8815
 
7913
8816
  def delete(self, name: str):
7914
8817
  """Delete an Online Table.
@@ -9019,7 +9922,6 @@ class StorageCredentialsAPI:
9019
9922
  :param force: bool (optional)
9020
9923
  Force update even if there are dependent external locations or external tables.
9021
9924
  :param isolation_mode: :class:`IsolationMode` (optional)
9022
- Whether the current securable is accessible from all workspaces or a specific set of workspaces.
9023
9925
  :param new_name: str (optional)
9024
9926
  New name for the storage credential.
9025
9927
  :param owner: str (optional)
@@ -9385,6 +10287,7 @@ class TablesAPI:
9385
10287
  max_results: Optional[int] = None,
9386
10288
  omit_columns: Optional[bool] = None,
9387
10289
  omit_properties: Optional[bool] = None,
10290
+ omit_username: Optional[bool] = None,
9388
10291
  page_token: Optional[str] = None) -> Iterator[TableInfo]:
9389
10292
  """List tables.
9390
10293
 
@@ -9414,6 +10317,9 @@ class TablesAPI:
9414
10317
  Whether to omit the columns of the table from the response or not.
9415
10318
  :param omit_properties: bool (optional)
9416
10319
  Whether to omit the properties of the table from the response or not.
10320
+ :param omit_username: bool (optional)
10321
+ Whether to omit the username of the table (e.g. owner, updated_by, created_by) from the response or
10322
+ not.
9417
10323
  :param page_token: str (optional)
9418
10324
  Opaque token to send for the next page of results (pagination).
9419
10325
 
@@ -9429,6 +10335,7 @@ class TablesAPI:
9429
10335
  if max_results is not None: query['max_results'] = max_results
9430
10336
  if omit_columns is not None: query['omit_columns'] = omit_columns
9431
10337
  if omit_properties is not None: query['omit_properties'] = omit_properties
10338
+ if omit_username is not None: query['omit_username'] = omit_username
9432
10339
  if page_token is not None: query['page_token'] = page_token
9433
10340
  if schema_name is not None: query['schema_name'] = schema_name
9434
10341
  headers = {'Accept': 'application/json', }