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

Files changed (31) hide show
  1. databricks/sdk/__init__.py +38 -9
  2. databricks/sdk/service/aibuilder.py +0 -163
  3. databricks/sdk/service/apps.py +53 -49
  4. databricks/sdk/service/billing.py +62 -223
  5. databricks/sdk/service/catalog.py +3052 -3707
  6. databricks/sdk/service/cleanrooms.py +5 -54
  7. databricks/sdk/service/compute.py +579 -2715
  8. databricks/sdk/service/dashboards.py +108 -317
  9. databricks/sdk/service/database.py +603 -122
  10. databricks/sdk/service/files.py +2 -218
  11. databricks/sdk/service/iam.py +19 -298
  12. databricks/sdk/service/jobs.py +77 -1263
  13. databricks/sdk/service/marketplace.py +3 -575
  14. databricks/sdk/service/ml.py +816 -2734
  15. databricks/sdk/service/oauth2.py +122 -238
  16. databricks/sdk/service/pipelines.py +133 -724
  17. databricks/sdk/service/provisioning.py +36 -757
  18. databricks/sdk/service/qualitymonitorv2.py +0 -18
  19. databricks/sdk/service/serving.py +37 -583
  20. databricks/sdk/service/settings.py +282 -1768
  21. databricks/sdk/service/sharing.py +6 -478
  22. databricks/sdk/service/sql.py +129 -1696
  23. databricks/sdk/service/vectorsearch.py +0 -410
  24. databricks/sdk/service/workspace.py +252 -727
  25. databricks/sdk/version.py +1 -1
  26. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/METADATA +1 -1
  27. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/RECORD +31 -31
  28. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/WHEEL +0 -0
  29. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/licenses/LICENSE +0 -0
  30. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/licenses/NOTICE +0 -0
  31. {databricks_sdk-0.57.0.dist-info → databricks_sdk-0.59.0.dist-info}/top_level.txt +0 -0
@@ -113,24 +113,67 @@ class DatabaseInstance:
113
113
  capacity: Optional[str] = None
114
114
  """The sku of the instance. Valid values are "CU_1", "CU_2", "CU_4", "CU_8"."""
115
115
 
116
+ child_instance_refs: Optional[List[DatabaseInstanceRef]] = None
117
+ """The refs of the child instances. This is only available if the instance is parent instance."""
118
+
116
119
  creation_time: Optional[str] = None
117
120
  """The timestamp when the instance was created."""
118
121
 
119
122
  creator: Optional[str] = None
120
123
  """The email of the creator of the instance."""
121
124
 
125
+ effective_enable_readable_secondaries: Optional[bool] = None
126
+ """xref AIP-129. `enable_readable_secondaries` is owned by the client, while
127
+ `effective_enable_readable_secondaries` is owned by the server. `enable_readable_secondaries`
128
+ will only be set in Create/Update response messages if and only if the user provides the field
129
+ via the request. `effective_enable_readable_secondaries` on the other hand will always bet set
130
+ in all response messages (Create/Update/Get/List)."""
131
+
132
+ effective_node_count: Optional[int] = None
133
+ """xref AIP-129. `node_count` is owned by the client, while `effective_node_count` is owned by the
134
+ server. `node_count` will only be set in Create/Update response messages if and only if the user
135
+ provides the field via the request. `effective_node_count` on the other hand will always bet set
136
+ in all response messages (Create/Update/Get/List)."""
137
+
138
+ effective_retention_window_in_days: Optional[int] = None
139
+ """xref AIP-129. `retention_window_in_days` is owned by the client, while
140
+ `effective_retention_window_in_days` is owned by the server. `retention_window_in_days` will
141
+ only be set in Create/Update response messages if and only if the user provides the field via
142
+ the request. `effective_retention_window_in_days` on the other hand will always bet set in all
143
+ response messages (Create/Update/Get/List)."""
144
+
122
145
  effective_stopped: Optional[bool] = None
123
146
  """xref AIP-129. `stopped` is owned by the client, while `effective_stopped` is owned by the
124
147
  server. `stopped` will only be set in Create/Update response messages if and only if the user
125
148
  provides the field via the request. `effective_stopped` on the other hand will always bet set in
126
149
  all response messages (Create/Update/Get/List)."""
127
150
 
151
+ enable_readable_secondaries: Optional[bool] = None
152
+ """Whether to enable secondaries to serve read-only traffic. Defaults to false."""
153
+
154
+ node_count: Optional[int] = None
155
+ """The number of nodes in the instance, composed of 1 primary and 0 or more secondaries. Defaults
156
+ to 1 primary and 0 secondaries."""
157
+
158
+ parent_instance_ref: Optional[DatabaseInstanceRef] = None
159
+ """The ref of the parent instance. This is only available if the instance is child instance. Input:
160
+ For specifying the parent instance to create a child instance. Optional. Output: Only populated
161
+ if provided as input to create a child instance."""
162
+
128
163
  pg_version: Optional[str] = None
129
164
  """The version of Postgres running on the instance."""
130
165
 
166
+ read_only_dns: Optional[str] = None
167
+ """The DNS endpoint to connect to the instance for read only access. This is only available if
168
+ enable_readable_secondaries is true."""
169
+
131
170
  read_write_dns: Optional[str] = None
132
171
  """The DNS endpoint to connect to the instance for read+write access."""
133
172
 
173
+ retention_window_in_days: Optional[int] = None
174
+ """The retention window for the instance. This is the time window in days for which the historical
175
+ data is retained. The default value is 7 days. Valid values are 2 to 35 days."""
176
+
134
177
  state: Optional[DatabaseInstanceState] = None
135
178
  """The current state of the instance."""
136
179
 
@@ -145,18 +188,36 @@ class DatabaseInstance:
145
188
  body = {}
146
189
  if self.capacity is not None:
147
190
  body["capacity"] = self.capacity
191
+ if self.child_instance_refs:
192
+ body["child_instance_refs"] = [v.as_dict() for v in self.child_instance_refs]
148
193
  if self.creation_time is not None:
149
194
  body["creation_time"] = self.creation_time
150
195
  if self.creator is not None:
151
196
  body["creator"] = self.creator
197
+ if self.effective_enable_readable_secondaries is not None:
198
+ body["effective_enable_readable_secondaries"] = self.effective_enable_readable_secondaries
199
+ if self.effective_node_count is not None:
200
+ body["effective_node_count"] = self.effective_node_count
201
+ if self.effective_retention_window_in_days is not None:
202
+ body["effective_retention_window_in_days"] = self.effective_retention_window_in_days
152
203
  if self.effective_stopped is not None:
153
204
  body["effective_stopped"] = self.effective_stopped
205
+ if self.enable_readable_secondaries is not None:
206
+ body["enable_readable_secondaries"] = self.enable_readable_secondaries
154
207
  if self.name is not None:
155
208
  body["name"] = self.name
209
+ if self.node_count is not None:
210
+ body["node_count"] = self.node_count
211
+ if self.parent_instance_ref:
212
+ body["parent_instance_ref"] = self.parent_instance_ref.as_dict()
156
213
  if self.pg_version is not None:
157
214
  body["pg_version"] = self.pg_version
215
+ if self.read_only_dns is not None:
216
+ body["read_only_dns"] = self.read_only_dns
158
217
  if self.read_write_dns is not None:
159
218
  body["read_write_dns"] = self.read_write_dns
219
+ if self.retention_window_in_days is not None:
220
+ body["retention_window_in_days"] = self.retention_window_in_days
160
221
  if self.state is not None:
161
222
  body["state"] = self.state.value
162
223
  if self.stopped is not None:
@@ -170,18 +231,36 @@ class DatabaseInstance:
170
231
  body = {}
171
232
  if self.capacity is not None:
172
233
  body["capacity"] = self.capacity
234
+ if self.child_instance_refs:
235
+ body["child_instance_refs"] = self.child_instance_refs
173
236
  if self.creation_time is not None:
174
237
  body["creation_time"] = self.creation_time
175
238
  if self.creator is not None:
176
239
  body["creator"] = self.creator
240
+ if self.effective_enable_readable_secondaries is not None:
241
+ body["effective_enable_readable_secondaries"] = self.effective_enable_readable_secondaries
242
+ if self.effective_node_count is not None:
243
+ body["effective_node_count"] = self.effective_node_count
244
+ if self.effective_retention_window_in_days is not None:
245
+ body["effective_retention_window_in_days"] = self.effective_retention_window_in_days
177
246
  if self.effective_stopped is not None:
178
247
  body["effective_stopped"] = self.effective_stopped
248
+ if self.enable_readable_secondaries is not None:
249
+ body["enable_readable_secondaries"] = self.enable_readable_secondaries
179
250
  if self.name is not None:
180
251
  body["name"] = self.name
252
+ if self.node_count is not None:
253
+ body["node_count"] = self.node_count
254
+ if self.parent_instance_ref:
255
+ body["parent_instance_ref"] = self.parent_instance_ref
181
256
  if self.pg_version is not None:
182
257
  body["pg_version"] = self.pg_version
258
+ if self.read_only_dns is not None:
259
+ body["read_only_dns"] = self.read_only_dns
183
260
  if self.read_write_dns is not None:
184
261
  body["read_write_dns"] = self.read_write_dns
262
+ if self.retention_window_in_days is not None:
263
+ body["retention_window_in_days"] = self.retention_window_in_days
185
264
  if self.state is not None:
186
265
  body["state"] = self.state
187
266
  if self.stopped is not None:
@@ -195,18 +274,216 @@ class DatabaseInstance:
195
274
  """Deserializes the DatabaseInstance from a dictionary."""
196
275
  return cls(
197
276
  capacity=d.get("capacity", None),
277
+ child_instance_refs=_repeated_dict(d, "child_instance_refs", DatabaseInstanceRef),
198
278
  creation_time=d.get("creation_time", None),
199
279
  creator=d.get("creator", None),
280
+ effective_enable_readable_secondaries=d.get("effective_enable_readable_secondaries", None),
281
+ effective_node_count=d.get("effective_node_count", None),
282
+ effective_retention_window_in_days=d.get("effective_retention_window_in_days", None),
200
283
  effective_stopped=d.get("effective_stopped", None),
284
+ enable_readable_secondaries=d.get("enable_readable_secondaries", None),
201
285
  name=d.get("name", None),
286
+ node_count=d.get("node_count", None),
287
+ parent_instance_ref=_from_dict(d, "parent_instance_ref", DatabaseInstanceRef),
202
288
  pg_version=d.get("pg_version", None),
289
+ read_only_dns=d.get("read_only_dns", None),
203
290
  read_write_dns=d.get("read_write_dns", None),
291
+ retention_window_in_days=d.get("retention_window_in_days", None),
204
292
  state=_enum(d, "state", DatabaseInstanceState),
205
293
  stopped=d.get("stopped", None),
206
294
  uid=d.get("uid", None),
207
295
  )
208
296
 
209
297
 
298
+ @dataclass
299
+ class DatabaseInstanceRef:
300
+ """DatabaseInstanceRef is a reference to a database instance. It is used in the DatabaseInstance
301
+ object to refer to the parent instance of an instance and to refer the child instances of an
302
+ instance. To specify as a parent instance during creation of an instance, the lsn and
303
+ branch_time fields are optional. If not specified, the child instance will be created from the
304
+ latest lsn of the parent. If both lsn and branch_time are specified, the lsn will be used to
305
+ create the child instance."""
306
+
307
+ branch_time: Optional[str] = None
308
+ """Branch time of the ref database instance. For a parent ref instance, this is the point in time
309
+ on the parent instance from which the instance was created. For a child ref instance, this is
310
+ the point in time on the instance from which the child instance was created. Input: For
311
+ specifying the point in time to create a child instance. Optional. Output: Only populated if
312
+ provided as input to create a child instance."""
313
+
314
+ effective_lsn: Optional[str] = None
315
+ """xref AIP-129. `lsn` is owned by the client, while `effective_lsn` is owned by the server. `lsn`
316
+ will only be set in Create/Update response messages if and only if the user provides the field
317
+ via the request. `effective_lsn` on the other hand will always bet set in all response messages
318
+ (Create/Update/Get/List). For a parent ref instance, this is the LSN on the parent instance from
319
+ which the instance was created. For a child ref instance, this is the LSN on the instance from
320
+ which the child instance was created."""
321
+
322
+ lsn: Optional[str] = None
323
+ """User-specified WAL LSN of the ref database instance.
324
+
325
+ Input: For specifying the WAL LSN to create a child instance. Optional. Output: Only populated
326
+ if provided as input to create a child instance."""
327
+
328
+ name: Optional[str] = None
329
+ """Name of the ref database instance."""
330
+
331
+ uid: Optional[str] = None
332
+ """Id of the ref database instance."""
333
+
334
+ def as_dict(self) -> dict:
335
+ """Serializes the DatabaseInstanceRef into a dictionary suitable for use as a JSON request body."""
336
+ body = {}
337
+ if self.branch_time is not None:
338
+ body["branch_time"] = self.branch_time
339
+ if self.effective_lsn is not None:
340
+ body["effective_lsn"] = self.effective_lsn
341
+ if self.lsn is not None:
342
+ body["lsn"] = self.lsn
343
+ if self.name is not None:
344
+ body["name"] = self.name
345
+ if self.uid is not None:
346
+ body["uid"] = self.uid
347
+ return body
348
+
349
+ def as_shallow_dict(self) -> dict:
350
+ """Serializes the DatabaseInstanceRef into a shallow dictionary of its immediate attributes."""
351
+ body = {}
352
+ if self.branch_time is not None:
353
+ body["branch_time"] = self.branch_time
354
+ if self.effective_lsn is not None:
355
+ body["effective_lsn"] = self.effective_lsn
356
+ if self.lsn is not None:
357
+ body["lsn"] = self.lsn
358
+ if self.name is not None:
359
+ body["name"] = self.name
360
+ if self.uid is not None:
361
+ body["uid"] = self.uid
362
+ return body
363
+
364
+ @classmethod
365
+ def from_dict(cls, d: Dict[str, Any]) -> DatabaseInstanceRef:
366
+ """Deserializes the DatabaseInstanceRef from a dictionary."""
367
+ return cls(
368
+ branch_time=d.get("branch_time", None),
369
+ effective_lsn=d.get("effective_lsn", None),
370
+ lsn=d.get("lsn", None),
371
+ name=d.get("name", None),
372
+ uid=d.get("uid", None),
373
+ )
374
+
375
+
376
+ @dataclass
377
+ class DatabaseInstanceRole:
378
+ """A DatabaseInstanceRole represents a Postgres role in a database instance."""
379
+
380
+ attributes: Optional[DatabaseInstanceRoleAttributes] = None
381
+ """API-exposed Postgres role attributes"""
382
+
383
+ identity_type: Optional[DatabaseInstanceRoleIdentityType] = None
384
+ """The type of the role."""
385
+
386
+ membership_role: Optional[DatabaseInstanceRoleMembershipRole] = None
387
+ """An enum value for a standard role that this role is a member of."""
388
+
389
+ name: Optional[str] = None
390
+ """The name of the role. This is the unique identifier for the role in an instance."""
391
+
392
+ def as_dict(self) -> dict:
393
+ """Serializes the DatabaseInstanceRole into a dictionary suitable for use as a JSON request body."""
394
+ body = {}
395
+ if self.attributes:
396
+ body["attributes"] = self.attributes.as_dict()
397
+ if self.identity_type is not None:
398
+ body["identity_type"] = self.identity_type.value
399
+ if self.membership_role is not None:
400
+ body["membership_role"] = self.membership_role.value
401
+ if self.name is not None:
402
+ body["name"] = self.name
403
+ return body
404
+
405
+ def as_shallow_dict(self) -> dict:
406
+ """Serializes the DatabaseInstanceRole into a shallow dictionary of its immediate attributes."""
407
+ body = {}
408
+ if self.attributes:
409
+ body["attributes"] = self.attributes
410
+ if self.identity_type is not None:
411
+ body["identity_type"] = self.identity_type
412
+ if self.membership_role is not None:
413
+ body["membership_role"] = self.membership_role
414
+ if self.name is not None:
415
+ body["name"] = self.name
416
+ return body
417
+
418
+ @classmethod
419
+ def from_dict(cls, d: Dict[str, Any]) -> DatabaseInstanceRole:
420
+ """Deserializes the DatabaseInstanceRole from a dictionary."""
421
+ return cls(
422
+ attributes=_from_dict(d, "attributes", DatabaseInstanceRoleAttributes),
423
+ identity_type=_enum(d, "identity_type", DatabaseInstanceRoleIdentityType),
424
+ membership_role=_enum(d, "membership_role", DatabaseInstanceRoleMembershipRole),
425
+ name=d.get("name", None),
426
+ )
427
+
428
+
429
+ @dataclass
430
+ class DatabaseInstanceRoleAttributes:
431
+ """Attributes that can be granted to a Postgres role. We are only implementing a subset for now,
432
+ see xref: https://www.postgresql.org/docs/16/sql-createrole.html The values follow Postgres
433
+ keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical
434
+ underscores between words. We were requested to make this a nested object/struct representation
435
+ since these are knobs from an external spec."""
436
+
437
+ bypassrls: Optional[bool] = None
438
+
439
+ createdb: Optional[bool] = None
440
+
441
+ createrole: Optional[bool] = None
442
+
443
+ def as_dict(self) -> dict:
444
+ """Serializes the DatabaseInstanceRoleAttributes into a dictionary suitable for use as a JSON request body."""
445
+ body = {}
446
+ if self.bypassrls is not None:
447
+ body["bypassrls"] = self.bypassrls
448
+ if self.createdb is not None:
449
+ body["createdb"] = self.createdb
450
+ if self.createrole is not None:
451
+ body["createrole"] = self.createrole
452
+ return body
453
+
454
+ def as_shallow_dict(self) -> dict:
455
+ """Serializes the DatabaseInstanceRoleAttributes into a shallow dictionary of its immediate attributes."""
456
+ body = {}
457
+ if self.bypassrls is not None:
458
+ body["bypassrls"] = self.bypassrls
459
+ if self.createdb is not None:
460
+ body["createdb"] = self.createdb
461
+ if self.createrole is not None:
462
+ body["createrole"] = self.createrole
463
+ return body
464
+
465
+ @classmethod
466
+ def from_dict(cls, d: Dict[str, Any]) -> DatabaseInstanceRoleAttributes:
467
+ """Deserializes the DatabaseInstanceRoleAttributes from a dictionary."""
468
+ return cls(
469
+ bypassrls=d.get("bypassrls", None), createdb=d.get("createdb", None), createrole=d.get("createrole", None)
470
+ )
471
+
472
+
473
+ class DatabaseInstanceRoleIdentityType(Enum):
474
+
475
+ GROUP = "GROUP"
476
+ PG_ONLY = "PG_ONLY"
477
+ SERVICE_PRINCIPAL = "SERVICE_PRINCIPAL"
478
+ USER = "USER"
479
+
480
+
481
+ class DatabaseInstanceRoleMembershipRole(Enum):
482
+ """Roles that the DatabaseInstanceRole can be a member of."""
483
+
484
+ DATABRICKS_SUPERUSER = "DATABRICKS_SUPERUSER"
485
+
486
+
210
487
  class DatabaseInstanceState(Enum):
211
488
 
212
489
  AVAILABLE = "AVAILABLE"
@@ -231,18 +508,15 @@ class DatabaseTable:
231
508
  MUST match that of the registered catalog (or the request will be rejected)."""
232
509
 
233
510
  logical_database_name: Optional[str] = None
234
- """Target Postgres database object (logical database) name for this table. This field is optional
235
- in all scenarios.
511
+ """Target Postgres database object (logical database) name for this table.
236
512
 
237
513
  When creating a table in a registered Postgres catalog, the target Postgres database name is
238
514
  inferred to be that of the registered catalog. If this field is specified in this scenario, the
239
515
  Postgres database name MUST match that of the registered catalog (or the request will be
240
516
  rejected).
241
517
 
242
- When creating a table in a standard catalog, the target database name is inferred to be that of
243
- the standard catalog. In this scenario, specifying this field will allow targeting an arbitrary
244
- postgres database. Note that this has implications for the `create_database_objects_is_missing`
245
- field in `spec`."""
518
+ When creating a table in a standard catalog, this field is required. In this scenario,
519
+ specifying this field will allow targeting an arbitrary postgres database."""
246
520
 
247
521
  def as_dict(self) -> dict:
248
522
  """Serializes the DatabaseTable into a dictionary suitable for use as a JSON request body."""
@@ -277,108 +551,74 @@ class DatabaseTable:
277
551
 
278
552
 
279
553
  @dataclass
280
- class DeleteDatabaseCatalogResponse:
281
- def as_dict(self) -> dict:
282
- """Serializes the DeleteDatabaseCatalogResponse into a dictionary suitable for use as a JSON request body."""
283
- body = {}
284
- return body
285
-
286
- def as_shallow_dict(self) -> dict:
287
- """Serializes the DeleteDatabaseCatalogResponse into a shallow dictionary of its immediate attributes."""
288
- body = {}
289
- return body
290
-
291
- @classmethod
292
- def from_dict(cls, d: Dict[str, Any]) -> DeleteDatabaseCatalogResponse:
293
- """Deserializes the DeleteDatabaseCatalogResponse from a dictionary."""
294
- return cls()
554
+ class DeltaTableSyncInfo:
555
+ delta_commit_timestamp: Optional[str] = None
556
+ """The timestamp when the above Delta version was committed in the source Delta table. Note: This
557
+ is the Delta commit time, not the time the data was written to the synced table."""
295
558
 
559
+ delta_commit_version: Optional[int] = None
560
+ """The Delta Lake commit version that was last successfully synced."""
296
561
 
297
- @dataclass
298
- class DeleteDatabaseInstanceResponse:
299
562
  def as_dict(self) -> dict:
300
- """Serializes the DeleteDatabaseInstanceResponse into a dictionary suitable for use as a JSON request body."""
563
+ """Serializes the DeltaTableSyncInfo into a dictionary suitable for use as a JSON request body."""
301
564
  body = {}
565
+ if self.delta_commit_timestamp is not None:
566
+ body["delta_commit_timestamp"] = self.delta_commit_timestamp
567
+ if self.delta_commit_version is not None:
568
+ body["delta_commit_version"] = self.delta_commit_version
302
569
  return body
303
570
 
304
571
  def as_shallow_dict(self) -> dict:
305
- """Serializes the DeleteDatabaseInstanceResponse into a shallow dictionary of its immediate attributes."""
572
+ """Serializes the DeltaTableSyncInfo into a shallow dictionary of its immediate attributes."""
306
573
  body = {}
574
+ if self.delta_commit_timestamp is not None:
575
+ body["delta_commit_timestamp"] = self.delta_commit_timestamp
576
+ if self.delta_commit_version is not None:
577
+ body["delta_commit_version"] = self.delta_commit_version
307
578
  return body
308
579
 
309
580
  @classmethod
310
- def from_dict(cls, d: Dict[str, Any]) -> DeleteDatabaseInstanceResponse:
311
- """Deserializes the DeleteDatabaseInstanceResponse from a dictionary."""
312
- return cls()
313
-
314
-
315
- @dataclass
316
- class DeleteDatabaseTableResponse:
317
- def as_dict(self) -> dict:
318
- """Serializes the DeleteDatabaseTableResponse into a dictionary suitable for use as a JSON request body."""
319
- body = {}
320
- return body
321
-
322
- def as_shallow_dict(self) -> dict:
323
- """Serializes the DeleteDatabaseTableResponse into a shallow dictionary of its immediate attributes."""
324
- body = {}
325
- return body
326
-
327
- @classmethod
328
- def from_dict(cls, d: Dict[str, Any]) -> DeleteDatabaseTableResponse:
329
- """Deserializes the DeleteDatabaseTableResponse from a dictionary."""
330
- return cls()
331
-
332
-
333
- @dataclass
334
- class DeleteSyncedDatabaseTableResponse:
335
- def as_dict(self) -> dict:
336
- """Serializes the DeleteSyncedDatabaseTableResponse into a dictionary suitable for use as a JSON request body."""
337
- body = {}
338
- return body
339
-
340
- def as_shallow_dict(self) -> dict:
341
- """Serializes the DeleteSyncedDatabaseTableResponse into a shallow dictionary of its immediate attributes."""
342
- body = {}
343
- return body
344
-
345
- @classmethod
346
- def from_dict(cls, d: Dict[str, Any]) -> DeleteSyncedDatabaseTableResponse:
347
- """Deserializes the DeleteSyncedDatabaseTableResponse from a dictionary."""
348
- return cls()
581
+ def from_dict(cls, d: Dict[str, Any]) -> DeltaTableSyncInfo:
582
+ """Deserializes the DeltaTableSyncInfo from a dictionary."""
583
+ return cls(
584
+ delta_commit_timestamp=d.get("delta_commit_timestamp", None),
585
+ delta_commit_version=d.get("delta_commit_version", None),
586
+ )
349
587
 
350
588
 
351
589
  @dataclass
352
- class GenerateDatabaseCredentialRequest:
353
- """Generates a credential that can be used to access database instances"""
354
-
355
- instance_names: Optional[List[str]] = None
356
- """Instances to which the token will be scoped."""
590
+ class ListDatabaseInstanceRolesResponse:
591
+ database_instance_roles: Optional[List[DatabaseInstanceRole]] = None
592
+ """List of database instance roles."""
357
593
 
358
- request_id: Optional[str] = None
594
+ next_page_token: Optional[str] = None
595
+ """Pagination token to request the next page of instances."""
359
596
 
360
597
  def as_dict(self) -> dict:
361
- """Serializes the GenerateDatabaseCredentialRequest into a dictionary suitable for use as a JSON request body."""
598
+ """Serializes the ListDatabaseInstanceRolesResponse into a dictionary suitable for use as a JSON request body."""
362
599
  body = {}
363
- if self.instance_names:
364
- body["instance_names"] = [v for v in self.instance_names]
365
- if self.request_id is not None:
366
- body["request_id"] = self.request_id
600
+ if self.database_instance_roles:
601
+ body["database_instance_roles"] = [v.as_dict() for v in self.database_instance_roles]
602
+ if self.next_page_token is not None:
603
+ body["next_page_token"] = self.next_page_token
367
604
  return body
368
605
 
369
606
  def as_shallow_dict(self) -> dict:
370
- """Serializes the GenerateDatabaseCredentialRequest into a shallow dictionary of its immediate attributes."""
607
+ """Serializes the ListDatabaseInstanceRolesResponse into a shallow dictionary of its immediate attributes."""
371
608
  body = {}
372
- if self.instance_names:
373
- body["instance_names"] = self.instance_names
374
- if self.request_id is not None:
375
- body["request_id"] = self.request_id
609
+ if self.database_instance_roles:
610
+ body["database_instance_roles"] = self.database_instance_roles
611
+ if self.next_page_token is not None:
612
+ body["next_page_token"] = self.next_page_token
376
613
  return body
377
614
 
378
615
  @classmethod
379
- def from_dict(cls, d: Dict[str, Any]) -> GenerateDatabaseCredentialRequest:
380
- """Deserializes the GenerateDatabaseCredentialRequest from a dictionary."""
381
- return cls(instance_names=d.get("instance_names", None), request_id=d.get("request_id", None))
616
+ def from_dict(cls, d: Dict[str, Any]) -> ListDatabaseInstanceRolesResponse:
617
+ """Deserializes the ListDatabaseInstanceRolesResponse from a dictionary."""
618
+ return cls(
619
+ database_instance_roles=_repeated_dict(d, "database_instance_roles", DatabaseInstanceRole),
620
+ next_page_token=d.get("next_page_token", None),
621
+ )
382
622
 
383
623
 
384
624
  @dataclass
@@ -422,11 +662,15 @@ class NewPipelineSpec:
422
662
  fields of pipeline are still inferred by table def internally"""
423
663
 
424
664
  storage_catalog: Optional[str] = None
425
- """UC catalog for the pipeline to store intermediate files (checkpoints, event logs etc). This
665
+ """This field needs to be specified if the destination catalog is a managed postgres catalog.
666
+
667
+ UC catalog for the pipeline to store intermediate files (checkpoints, event logs etc). This
426
668
  needs to be a standard catalog where the user has permissions to create Delta tables."""
427
669
 
428
670
  storage_schema: Optional[str] = None
429
- """UC schema for the pipeline to store intermediate files (checkpoints, event logs etc). This needs
671
+ """This field needs to be specified if the destination catalog is a managed postgres catalog.
672
+
673
+ UC schema for the pipeline to store intermediate files (checkpoints, event logs etc). This needs
430
674
  to be in the standard catalog where the user has permissions to create Delta tables."""
431
675
 
432
676
  def as_dict(self) -> dict:
@@ -463,6 +707,77 @@ class ProvisioningInfoState(Enum):
463
707
  UPDATING = "UPDATING"
464
708
 
465
709
 
710
+ @dataclass
711
+ class RequestedClaims:
712
+ permission_set: Optional[RequestedClaimsPermissionSet] = None
713
+
714
+ resources: Optional[List[RequestedResource]] = None
715
+
716
+ def as_dict(self) -> dict:
717
+ """Serializes the RequestedClaims into a dictionary suitable for use as a JSON request body."""
718
+ body = {}
719
+ if self.permission_set is not None:
720
+ body["permission_set"] = self.permission_set.value
721
+ if self.resources:
722
+ body["resources"] = [v.as_dict() for v in self.resources]
723
+ return body
724
+
725
+ def as_shallow_dict(self) -> dict:
726
+ """Serializes the RequestedClaims into a shallow dictionary of its immediate attributes."""
727
+ body = {}
728
+ if self.permission_set is not None:
729
+ body["permission_set"] = self.permission_set
730
+ if self.resources:
731
+ body["resources"] = self.resources
732
+ return body
733
+
734
+ @classmethod
735
+ def from_dict(cls, d: Dict[str, Any]) -> RequestedClaims:
736
+ """Deserializes the RequestedClaims from a dictionary."""
737
+ return cls(
738
+ permission_set=_enum(d, "permission_set", RequestedClaimsPermissionSet),
739
+ resources=_repeated_dict(d, "resources", RequestedResource),
740
+ )
741
+
742
+
743
+ class RequestedClaimsPermissionSet(Enum):
744
+ """Might add WRITE in the future"""
745
+
746
+ READ_ONLY = "READ_ONLY"
747
+
748
+
749
+ @dataclass
750
+ class RequestedResource:
751
+ table_name: Optional[str] = None
752
+
753
+ unspecified_resource_name: Optional[str] = None
754
+
755
+ def as_dict(self) -> dict:
756
+ """Serializes the RequestedResource into a dictionary suitable for use as a JSON request body."""
757
+ body = {}
758
+ if self.table_name is not None:
759
+ body["table_name"] = self.table_name
760
+ if self.unspecified_resource_name is not None:
761
+ body["unspecified_resource_name"] = self.unspecified_resource_name
762
+ return body
763
+
764
+ def as_shallow_dict(self) -> dict:
765
+ """Serializes the RequestedResource into a shallow dictionary of its immediate attributes."""
766
+ body = {}
767
+ if self.table_name is not None:
768
+ body["table_name"] = self.table_name
769
+ if self.unspecified_resource_name is not None:
770
+ body["unspecified_resource_name"] = self.unspecified_resource_name
771
+ return body
772
+
773
+ @classmethod
774
+ def from_dict(cls, d: Dict[str, Any]) -> RequestedResource:
775
+ """Deserializes the RequestedResource from a dictionary."""
776
+ return cls(
777
+ table_name=d.get("table_name", None), unspecified_resource_name=d.get("unspecified_resource_name", None)
778
+ )
779
+
780
+
466
781
  @dataclass
467
782
  class SyncedDatabaseTable:
468
783
  """Next field marker: 12"""
@@ -481,20 +796,18 @@ class SyncedDatabaseTable:
481
796
  rejected)."""
482
797
 
483
798
  logical_database_name: Optional[str] = None
484
- """Target Postgres database object (logical database) name for this table. This field is optional
485
- in all scenarios.
799
+ """Target Postgres database object (logical database) name for this table.
486
800
 
487
801
  When creating a synced table in a registered Postgres catalog, the target Postgres database name
488
802
  is inferred to be that of the registered catalog. If this field is specified in this scenario,
489
803
  the Postgres database name MUST match that of the registered catalog (or the request will be
490
804
  rejected).
491
805
 
492
- When creating a synced table in a standard catalog, the target database name is inferred to be
493
- that of the standard catalog. In this scenario, specifying this field will allow targeting an
494
- arbitrary postgres database."""
806
+ When creating a synced table in a standard catalog, this field is required. In this scenario,
807
+ specifying this field will allow targeting an arbitrary postgres database. Note that this has
808
+ implications for the `create_database_objects_is_missing` field in `spec`."""
495
809
 
496
810
  spec: Optional[SyncedTableSpec] = None
497
- """Specification of a synced database table."""
498
811
 
499
812
  unity_catalog_provisioning_state: Optional[ProvisioningInfoState] = None
500
813
  """The provisioning state of the synced table entity in Unity Catalog. This is distinct from the
@@ -557,12 +870,11 @@ class SyncedTableContinuousUpdateStatus:
557
870
  """Progress of the initial data synchronization."""
558
871
 
559
872
  last_processed_commit_version: Optional[int] = None
560
- """The last source table Delta version that was synced to the synced table. Note that this Delta
561
- version may not be completely synced to the synced table yet."""
873
+ """The last source table Delta version that was successfully synced to the synced table."""
562
874
 
563
875
  timestamp: Optional[str] = None
564
- """The timestamp of the last time any data was synchronized from the source table to the synced
565
- table."""
876
+ """The end timestamp of the last time any data was synchronized from the source table to the synced
877
+ table. This is when the data is available in the synced table."""
566
878
 
567
879
  def as_dict(self) -> dict:
568
880
  """Serializes the SyncedTableContinuousUpdateStatus into a dictionary suitable for use as a JSON request body."""
@@ -602,12 +914,12 @@ class SyncedTableFailedStatus:
602
914
  SYNCED_PIPELINE_FAILED state."""
603
915
 
604
916
  last_processed_commit_version: Optional[int] = None
605
- """The last source table Delta version that was synced to the synced table. Note that this Delta
606
- version may only be partially synced to the synced table. Only populated if the table is still
607
- synced and available for serving."""
917
+ """The last source table Delta version that was successfully synced to the synced table. The last
918
+ source table Delta version that was synced to the synced table. Only populated if the table is
919
+ still synced and available for serving."""
608
920
 
609
921
  timestamp: Optional[str] = None
610
- """The timestamp of the last time any data was synchronized from the source table to the synced
922
+ """The end timestamp of the last time any data was synchronized from the source table to the synced
611
923
  table. Only populated if the table is still synced and available for serving."""
612
924
 
613
925
  def as_dict(self) -> dict:
@@ -699,6 +1011,51 @@ class SyncedTablePipelineProgress:
699
1011
  )
700
1012
 
701
1013
 
1014
+ @dataclass
1015
+ class SyncedTablePosition:
1016
+ delta_table_sync_info: Optional[DeltaTableSyncInfo] = None
1017
+
1018
+ sync_end_timestamp: Optional[str] = None
1019
+ """The end timestamp of the most recent successful synchronization. This is the time when the data
1020
+ is available in the synced table."""
1021
+
1022
+ sync_start_timestamp: Optional[str] = None
1023
+ """The starting timestamp of the most recent successful synchronization from the source table to
1024
+ the destination (synced) table. Note this is the starting timestamp of the sync operation, not
1025
+ the end time. E.g., for a batch, this is the time when the sync operation started."""
1026
+
1027
+ def as_dict(self) -> dict:
1028
+ """Serializes the SyncedTablePosition into a dictionary suitable for use as a JSON request body."""
1029
+ body = {}
1030
+ if self.delta_table_sync_info:
1031
+ body["delta_table_sync_info"] = self.delta_table_sync_info.as_dict()
1032
+ if self.sync_end_timestamp is not None:
1033
+ body["sync_end_timestamp"] = self.sync_end_timestamp
1034
+ if self.sync_start_timestamp is not None:
1035
+ body["sync_start_timestamp"] = self.sync_start_timestamp
1036
+ return body
1037
+
1038
+ def as_shallow_dict(self) -> dict:
1039
+ """Serializes the SyncedTablePosition into a shallow dictionary of its immediate attributes."""
1040
+ body = {}
1041
+ if self.delta_table_sync_info:
1042
+ body["delta_table_sync_info"] = self.delta_table_sync_info
1043
+ if self.sync_end_timestamp is not None:
1044
+ body["sync_end_timestamp"] = self.sync_end_timestamp
1045
+ if self.sync_start_timestamp is not None:
1046
+ body["sync_start_timestamp"] = self.sync_start_timestamp
1047
+ return body
1048
+
1049
+ @classmethod
1050
+ def from_dict(cls, d: Dict[str, Any]) -> SyncedTablePosition:
1051
+ """Deserializes the SyncedTablePosition from a dictionary."""
1052
+ return cls(
1053
+ delta_table_sync_info=_from_dict(d, "delta_table_sync_info", DeltaTableSyncInfo),
1054
+ sync_end_timestamp=d.get("sync_end_timestamp", None),
1055
+ sync_start_timestamp=d.get("sync_start_timestamp", None),
1056
+ )
1057
+
1058
+
702
1059
  @dataclass
703
1060
  class SyncedTableProvisioningStatus:
704
1061
  """Detailed status of a synced table. Shown if the synced table is in the
@@ -746,13 +1103,20 @@ class SyncedTableSpec:
746
1103
  do not already exist."""
747
1104
 
748
1105
  existing_pipeline_id: Optional[str] = None
749
- """User-specified ID of a pre-existing pipeline to bin pack. This field is optional, and should be
750
- empty if new_pipeline_spec is set. This field will only be set by the server in response
751
- messages if it is specified in the request. The SyncedTableStatus message will always contain
752
- the effective pipeline ID (either client provided or server generated), however."""
1106
+ """At most one of existing_pipeline_id and new_pipeline_spec should be defined.
1107
+
1108
+ If existing_pipeline_id is defined, the synced table will be bin packed into the existing
1109
+ pipeline referenced. This avoids creating a new pipeline and allows sharing existing compute. In
1110
+ this case, the scheduling_policy of this synced table must match the scheduling policy of the
1111
+ existing pipeline."""
753
1112
 
754
1113
  new_pipeline_spec: Optional[NewPipelineSpec] = None
755
- """Spec of new pipeline. Should be empty if pipeline_id / existing_pipeline_id is set"""
1114
+ """At most one of existing_pipeline_id and new_pipeline_spec should be defined.
1115
+
1116
+ If new_pipeline_spec is defined, a new pipeline is created for this synced table. The location
1117
+ pointed to is used to store intermediate files (checkpoints, event logs etc). The caller must
1118
+ have write permissions to create Delta tables in the specified catalog and schema. Again, note
1119
+ this requires write permissions, whereas the source table only requires read permissions."""
756
1120
 
757
1121
  primary_key_columns: Optional[List[str]] = None
758
1122
  """Primary Key columns to be used for data insert/update in the destination."""
@@ -839,15 +1203,24 @@ class SyncedTableStatus:
839
1203
  """Status of a synced table."""
840
1204
 
841
1205
  continuous_update_status: Optional[SyncedTableContinuousUpdateStatus] = None
842
- """Detailed status of a synced table. Shown if the synced table is in the SYNCED_CONTINUOUS_UPDATE
843
- or the SYNCED_UPDATING_PIPELINE_RESOURCES state."""
844
1206
 
845
1207
  detailed_state: Optional[SyncedTableState] = None
846
1208
  """The state of the synced table."""
847
1209
 
848
1210
  failed_status: Optional[SyncedTableFailedStatus] = None
849
- """Detailed status of a synced table. Shown if the synced table is in the OFFLINE_FAILED or the
850
- SYNCED_PIPELINE_FAILED state."""
1211
+
1212
+ last_sync: Optional[SyncedTablePosition] = None
1213
+ """Summary of the last successful synchronization from source to destination.
1214
+
1215
+ Will always be present if there has been a successful sync. Even if the most recent syncs have
1216
+ failed.
1217
+
1218
+ Limitation: The only exception is if the synced table is doing a FULL REFRESH, then the last
1219
+ sync information will not be available until the full refresh is complete. This limitation will
1220
+ be addressed in a future version.
1221
+
1222
+ This top-level field is a convenience for consumers who want easy access to last sync
1223
+ information without having to traverse detailed_status."""
851
1224
 
852
1225
  message: Optional[str] = None
853
1226
  """A text description of the current state of the synced table."""
@@ -857,12 +1230,8 @@ class SyncedTableStatus:
857
1230
  of bin packing), or generated by the server (when creating a new pipeline)."""
858
1231
 
859
1232
  provisioning_status: Optional[SyncedTableProvisioningStatus] = None
860
- """Detailed status of a synced table. Shown if the synced table is in the
861
- PROVISIONING_PIPELINE_RESOURCES or the PROVISIONING_INITIAL_SNAPSHOT state."""
862
1233
 
863
1234
  triggered_update_status: Optional[SyncedTableTriggeredUpdateStatus] = None
864
- """Detailed status of a synced table. Shown if the synced table is in the SYNCED_TRIGGERED_UPDATE
865
- or the SYNCED_NO_PENDING_UPDATE state."""
866
1235
 
867
1236
  def as_dict(self) -> dict:
868
1237
  """Serializes the SyncedTableStatus into a dictionary suitable for use as a JSON request body."""
@@ -873,6 +1242,8 @@ class SyncedTableStatus:
873
1242
  body["detailed_state"] = self.detailed_state.value
874
1243
  if self.failed_status:
875
1244
  body["failed_status"] = self.failed_status.as_dict()
1245
+ if self.last_sync:
1246
+ body["last_sync"] = self.last_sync.as_dict()
876
1247
  if self.message is not None:
877
1248
  body["message"] = self.message
878
1249
  if self.pipeline_id is not None:
@@ -892,6 +1263,8 @@ class SyncedTableStatus:
892
1263
  body["detailed_state"] = self.detailed_state
893
1264
  if self.failed_status:
894
1265
  body["failed_status"] = self.failed_status
1266
+ if self.last_sync:
1267
+ body["last_sync"] = self.last_sync
895
1268
  if self.message is not None:
896
1269
  body["message"] = self.message
897
1270
  if self.pipeline_id is not None:
@@ -909,6 +1282,7 @@ class SyncedTableStatus:
909
1282
  continuous_update_status=_from_dict(d, "continuous_update_status", SyncedTableContinuousUpdateStatus),
910
1283
  detailed_state=_enum(d, "detailed_state", SyncedTableState),
911
1284
  failed_status=_from_dict(d, "failed_status", SyncedTableFailedStatus),
1285
+ last_sync=_from_dict(d, "last_sync", SyncedTablePosition),
912
1286
  message=d.get("message", None),
913
1287
  pipeline_id=d.get("pipeline_id", None),
914
1288
  provisioning_status=_from_dict(d, "provisioning_status", SyncedTableProvisioningStatus),
@@ -922,12 +1296,11 @@ class SyncedTableTriggeredUpdateStatus:
922
1296
  or the SYNCED_NO_PENDING_UPDATE state."""
923
1297
 
924
1298
  last_processed_commit_version: Optional[int] = None
925
- """The last source table Delta version that was synced to the synced table. Note that this Delta
926
- version may not be completely synced to the synced table yet."""
1299
+ """The last source table Delta version that was successfully synced to the synced table."""
927
1300
 
928
1301
  timestamp: Optional[str] = None
929
- """The timestamp of the last time any data was synchronized from the source table to the synced
930
- table."""
1302
+ """The end timestamp of the last time any data was synchronized from the source table to the synced
1303
+ table. This is when the data is available in the synced table."""
931
1304
 
932
1305
  triggered_update_progress: Optional[SyncedTablePipelineProgress] = None
933
1306
  """Progress of the active data synchronization pipeline."""
@@ -990,7 +1363,7 @@ class DatabaseAPI:
990
1363
  """Create a Database Instance.
991
1364
 
992
1365
  :param database_instance: :class:`DatabaseInstance`
993
- A DatabaseInstance represents a logical Postgres instance, comprised of both compute and storage.
1366
+ Instance to create.
994
1367
 
995
1368
  :returns: :class:`DatabaseInstance`
996
1369
  """
@@ -1003,11 +1376,30 @@ class DatabaseAPI:
1003
1376
  res = self._api.do("POST", "/api/2.0/database/instances", body=body, headers=headers)
1004
1377
  return DatabaseInstance.from_dict(res)
1005
1378
 
1379
+ def create_database_instance_role(
1380
+ self, instance_name: str, database_instance_role: DatabaseInstanceRole
1381
+ ) -> DatabaseInstanceRole:
1382
+ """Create a role for a Database Instance.
1383
+
1384
+ :param instance_name: str
1385
+ :param database_instance_role: :class:`DatabaseInstanceRole`
1386
+
1387
+ :returns: :class:`DatabaseInstanceRole`
1388
+ """
1389
+ body = database_instance_role.as_dict()
1390
+ headers = {
1391
+ "Accept": "application/json",
1392
+ "Content-Type": "application/json",
1393
+ }
1394
+
1395
+ res = self._api.do("POST", f"/api/2.0/database/instances/{instance_name}/roles", body=body, headers=headers)
1396
+ return DatabaseInstanceRole.from_dict(res)
1397
+
1006
1398
  def create_database_table(self, table: DatabaseTable) -> DatabaseTable:
1007
- """Create a Database Table.
1399
+ """Create a Database Table. Useful for registering pre-existing PG tables in UC. See
1400
+ CreateSyncedDatabaseTable for creating synced tables in PG from a source table in UC.
1008
1401
 
1009
1402
  :param table: :class:`DatabaseTable`
1010
- Next field marker: 13
1011
1403
 
1012
1404
  :returns: :class:`DatabaseTable`
1013
1405
  """
@@ -1024,7 +1416,6 @@ class DatabaseAPI:
1024
1416
  """Create a Synced Database Table.
1025
1417
 
1026
1418
  :param synced_table: :class:`SyncedDatabaseTable`
1027
- Next field marker: 12
1028
1419
 
1029
1420
  :returns: :class:`SyncedDatabaseTable`
1030
1421
  """
@@ -1081,6 +1472,38 @@ class DatabaseAPI:
1081
1472
 
1082
1473
  self._api.do("DELETE", f"/api/2.0/database/instances/{name}", query=query, headers=headers)
1083
1474
 
1475
+ def delete_database_instance_role(
1476
+ self,
1477
+ instance_name: str,
1478
+ name: str,
1479
+ *,
1480
+ allow_missing: Optional[bool] = None,
1481
+ reassign_owned_to: Optional[str] = None,
1482
+ ):
1483
+ """Deletes a role for a Database Instance.
1484
+
1485
+ :param instance_name: str
1486
+ :param name: str
1487
+ :param allow_missing: bool (optional)
1488
+ This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option
1489
+ :param reassign_owned_to: str (optional)
1490
+
1491
+
1492
+ """
1493
+
1494
+ query = {}
1495
+ if allow_missing is not None:
1496
+ query["allow_missing"] = allow_missing
1497
+ if reassign_owned_to is not None:
1498
+ query["reassign_owned_to"] = reassign_owned_to
1499
+ headers = {
1500
+ "Accept": "application/json",
1501
+ }
1502
+
1503
+ self._api.do(
1504
+ "DELETE", f"/api/2.0/database/instances/{instance_name}/roles/{name}", query=query, headers=headers
1505
+ )
1506
+
1084
1507
  def delete_database_table(self, name: str):
1085
1508
  """Delete a Database Table.
1086
1509
 
@@ -1129,10 +1552,17 @@ class DatabaseAPI:
1129
1552
  return DatabaseInstance.from_dict(res)
1130
1553
 
1131
1554
  def generate_database_credential(
1132
- self, *, instance_names: Optional[List[str]] = None, request_id: Optional[str] = None
1555
+ self,
1556
+ *,
1557
+ claims: Optional[List[RequestedClaims]] = None,
1558
+ instance_names: Optional[List[str]] = None,
1559
+ request_id: Optional[str] = None,
1133
1560
  ) -> DatabaseCredential:
1134
1561
  """Generates a credential that can be used to access database instances.
1135
1562
 
1563
+ :param claims: List[:class:`RequestedClaims`] (optional)
1564
+ The returned token will be scoped to the union of instance_names and instances containing the
1565
+ specified UC tables, so instance_names is allowed to be empty.
1136
1566
  :param instance_names: List[str] (optional)
1137
1567
  Instances to which the token will be scoped.
1138
1568
  :param request_id: str (optional)
@@ -1140,6 +1570,8 @@ class DatabaseAPI:
1140
1570
  :returns: :class:`DatabaseCredential`
1141
1571
  """
1142
1572
  body = {}
1573
+ if claims is not None:
1574
+ body["claims"] = [v.as_dict() for v in claims]
1143
1575
  if instance_names is not None:
1144
1576
  body["instance_names"] = [v for v in instance_names]
1145
1577
  if request_id is not None:
@@ -1183,6 +1615,22 @@ class DatabaseAPI:
1183
1615
  res = self._api.do("GET", f"/api/2.0/database/instances/{name}", headers=headers)
1184
1616
  return DatabaseInstance.from_dict(res)
1185
1617
 
1618
+ def get_database_instance_role(self, instance_name: str, name: str) -> DatabaseInstanceRole:
1619
+ """Gets a role for a Database Instance.
1620
+
1621
+ :param instance_name: str
1622
+ :param name: str
1623
+
1624
+ :returns: :class:`DatabaseInstanceRole`
1625
+ """
1626
+
1627
+ headers = {
1628
+ "Accept": "application/json",
1629
+ }
1630
+
1631
+ res = self._api.do("GET", f"/api/2.0/database/instances/{instance_name}/roles/{name}", headers=headers)
1632
+ return DatabaseInstanceRole.from_dict(res)
1633
+
1186
1634
  def get_database_table(self, name: str) -> DatabaseTable:
1187
1635
  """Get a Database Table.
1188
1636
 
@@ -1213,6 +1661,40 @@ class DatabaseAPI:
1213
1661
  res = self._api.do("GET", f"/api/2.0/database/synced_tables/{name}", headers=headers)
1214
1662
  return SyncedDatabaseTable.from_dict(res)
1215
1663
 
1664
+ def list_database_instance_roles(
1665
+ self, instance_name: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
1666
+ ) -> Iterator[DatabaseInstanceRole]:
1667
+ """START OF PG ROLE APIs Section
1668
+
1669
+ :param instance_name: str
1670
+ :param page_size: int (optional)
1671
+ Upper bound for items returned.
1672
+ :param page_token: str (optional)
1673
+ Pagination token to go to the next page of Database Instances. Requests first page if absent.
1674
+
1675
+ :returns: Iterator over :class:`DatabaseInstanceRole`
1676
+ """
1677
+
1678
+ query = {}
1679
+ if page_size is not None:
1680
+ query["page_size"] = page_size
1681
+ if page_token is not None:
1682
+ query["page_token"] = page_token
1683
+ headers = {
1684
+ "Accept": "application/json",
1685
+ }
1686
+
1687
+ while True:
1688
+ json = self._api.do(
1689
+ "GET", f"/api/2.0/database/instances/{instance_name}/roles", query=query, headers=headers
1690
+ )
1691
+ if "database_instance_roles" in json:
1692
+ for v in json["database_instance_roles"]:
1693
+ yield DatabaseInstanceRole.from_dict(v)
1694
+ if "next_page_token" not in json or not json["next_page_token"]:
1695
+ return
1696
+ query["page_token"] = json["next_page_token"]
1697
+
1216
1698
  def list_database_instances(
1217
1699
  self, *, page_size: Optional[int] = None, page_token: Optional[str] = None
1218
1700
  ) -> Iterator[DatabaseInstance]:
@@ -1252,7 +1734,6 @@ class DatabaseAPI:
1252
1734
  :param name: str
1253
1735
  The name of the instance. This is the unique identifier for the instance.
1254
1736
  :param database_instance: :class:`DatabaseInstance`
1255
- A DatabaseInstance represents a logical Postgres instance, comprised of both compute and storage.
1256
1737
  :param update_mask: str
1257
1738
  The list of fields to update.
1258
1739