Skip to content

Commit 58e7d37

Browse files
gkevinzhengmutianf
andauthored
feat: Modernized Bigtable Admin Client featuring selective GAPIC generation (#1177)
* chore: Removed old admin_v2 GAPIC layer (#1111) * feat!: Generated Selective GAPIC layer for Admin API (#1112) * chore: Updated service YAML by making all methods in BigtableInstanceAdmin public (#1113) * refactor: Refactored classic client to use new Admin API (#1114) * refactor: Refactored classic client to use new Admin API * added newline after gapic_version files * fix: Made generate_consistency_token and check_consistency public (#1116) methods * feat: Consistency polling + restore table for sync client in admin (#1117) * feat: Prototyped handwritten layer * Added newlines * linting * Added docstrings for restore table and consistency token polling; removed gc_rule * docs: owlbot related changes (#1133) * docs: owlbot related changes * Addressed PR feedback + made changes to toc.yml for docs pipeline * Fixed type hint * linting + added validation for admin section * linting + added noqas to owlbot lines * tests: Tests for sync client + fixes + client library versioning (#1132) * tests: Tests for sync client + fixes + client library versioning * Removed raise exception * linting + name changes in tests + added test for timeout * linting * Fixed tests on Python 3.7 * feat: Proto-plus modifications for enforcing strict oneofs (#1126) * feat: Proto-plus modifications for enforcing strict oneofs * Added template directory + changed unit tests to pytest * Finished README * linting * Added source of truth comment * feat: Reworked the wait_for_consistency call (#1144) * feat: Reworked the wait_for_consistency call * linting * Update google/cloud/bigtable/admin_v2/overlay/services/bigtable_table_admin/client.py Co-authored-by: Mattie Fu <mattiefu@google.com> * Improved documentation * linting again * linting --------- Co-authored-by: Mattie Fu <mattiefu@google.com> * feat: Async consistency polling harness (#1142) * feat: Async consistency polling harness * Fixed AsyncMock issue in Python 3.7 * Reworked async_consistency and added async client to __init__.py * linting * addressed review feedback * linting * feat: Restore Table LRO rework + async restore table (#1148) * chore(tests): system tests for autogen API (#1151) * tests: system tests for autogen API * Fixed async system tests * addressed review feedback * Fixed system test failure at the end of a test run * Linting * more linting * chore: Moved Admin API from google.cloud.bigtable.admin_v2 back to google.cloud.bigtable_admin_v2 (#1153) * chore: Removed autogenerated files from the feature branch (#1170) * chore: Merged selective GAPIC autogenerated changes into feature branch (#1175) * chore: Merged selective GAPIC owlbot changes into feature branch * linting * changed comment text * Removed redundant items * Fixed owlbot infinitely appending text * Added comments + fixed indentation in Owlbot * Added anonymous credentials to client tests * Fixed project ID issue in system tests * Fixed docstrings and skipped system tests on emulator. --------- Co-authored-by: Mattie Fu <mattiefu@google.com>
1 parent 1a5b4b5 commit 58e7d37

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+5430
-1228
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Admin Client
2+
============
3+
.. toctree::
4+
:maxdepth: 2
5+
6+
services_
7+
types_
8+
9+
..
10+
This should be the only handwritten RST file in this directory.
11+
Everything else should be autogenerated.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BigtableInstanceAdmin
2+
---------------------------------------
3+
4+
.. automodule:: google.cloud.bigtable_admin_v2.services.bigtable_instance_admin
5+
:members:
6+
:inherited-members:
7+
8+
.. automodule:: google.cloud.bigtable_admin_v2.services.bigtable_instance_admin.pagers
9+
:members:
10+
:inherited-members:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BigtableTableAdmin
2+
------------------------------------
3+
4+
.. automodule:: google.cloud.bigtable_admin_v2.overlay.services.bigtable_table_admin
5+
:members:
6+
:inherited-members:
7+
8+
.. automodule:: google.cloud.bigtable_admin_v2.services.bigtable_table_admin.pagers
9+
:members:
10+
:inherited-members:

docs/admin_client/services_.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Services for Google Cloud Bigtable Admin v2 API
2+
===============================================
3+
.. toctree::
4+
:maxdepth: 2
5+
6+
bigtable_instance_admin
7+
bigtable_table_admin

docs/admin_client/types_.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Types for Google Cloud Bigtable Admin v2 API
2+
============================================
3+
4+
.. automodule:: google.cloud.bigtable_admin_v2.types
5+
:members:
6+
:show-inheritance:
7+
8+
.. automodule:: google.cloud.bigtable_admin_v2.overlay.types
9+
:members:
10+
:show-inheritance:

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Client Types
99

1010
data_client/data_client_usage
1111
classic_client/usage
12-
12+
admin_client/admin_client_usage
1313

1414
Changelog
1515
---------

docs/scripts/patch_devsite_toc.py

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"""
2121

2222

23+
import glob
2324
import yaml
2425
import os
2526
import shutil
@@ -153,6 +154,81 @@ def copy_markdown(self):
153154
f"_build/html/docfx_yaml",
154155
)
155156

157+
def validate_section(self, toc):
158+
# Make sure each rst file is listed in the toc.
159+
items_in_toc = [
160+
d["items"] for d in toc[0]["items"] if d["name"] == self.title and ".rst"
161+
][0]
162+
items_in_dir = [f for f in os.listdir(self.dir_name) if f.endswith(".rst")]
163+
# subtract 1 for index
164+
assert len(items_in_toc) == len(items_in_dir) - 1
165+
for file in items_in_dir:
166+
if file != self.index_file_name:
167+
base_name, _ = os.path.splitext(file)
168+
assert any(d["href"] == f"{base_name}.md" for d in items_in_toc)
169+
# make sure the markdown files are present in the docfx_yaml directory
170+
md_files = [d["href"] for d in items_in_toc]
171+
for file in md_files:
172+
assert os.path.exists(f"_build/html/docfx_yaml/{file}")
173+
174+
175+
class UIDFilteredTocSection(TocSection):
176+
def __init__(self, toc_file_path, section_name, title, uid_prefix):
177+
"""Creates a filtered section denoted by section_name in the toc_file_path to items with the given UID prefix.
178+
179+
The section is then renamed to the title.
180+
"""
181+
current_toc = yaml.safe_load(open(toc_file_path, "r"))
182+
self.uid_prefix = uid_prefix
183+
184+
# Since we are looking for a specific section_name there should only
185+
# be one match.
186+
section_items = [
187+
d for d in current_toc[0]["items"] if d["name"] == section_name
188+
][0]["items"]
189+
filtered_items = [d for d in section_items if d["uid"].startswith(uid_prefix)]
190+
self.items = filtered_items
191+
self.title = title
192+
193+
def copy_markdown(self):
194+
"""
195+
No-op because we are filtering on UIDs, not markdown files.
196+
"""
197+
pass
198+
199+
def validate_section(self, toc):
200+
uids_in_toc = set()
201+
202+
# A UID-filtered TOC tree looks like the following:
203+
# - items:
204+
# <optional> items: <more stuff>
205+
# name: <name>
206+
# uid: <fully qualified path to a class>
207+
#
208+
# Walk through the TOC tree to find all UIDs recursively.
209+
def find_uids_in_items(items):
210+
uids_in_toc.add(items["uid"])
211+
for subitem in items.get("items", []):
212+
find_uids_in_items(subitem)
213+
214+
items_in_toc = [d["items"] for d in toc[0]["items"] if d["name"] == self.title][
215+
0
216+
]
217+
for item in items_in_toc:
218+
find_uids_in_items(item)
219+
220+
# Now that we have all the UIDs, first match all of them
221+
# with corresponding .yml files.
222+
for uid in uids_in_toc:
223+
assert os.path.exists(f"_build/html/docfx_yaml/{uid}.yml")
224+
225+
# Also validate that every uid yml file that starts with the uid_prefix
226+
# exists in the section.
227+
for filename in glob.glob(
228+
f"{self.uid_prefix}*.yml", root_dir="_build/html/docfx_yaml"
229+
):
230+
assert filename[:-4] in uids_in_toc
231+
156232

157233
def validate_toc(toc_file_path, expected_section_list, added_sections):
158234
current_toc = yaml.safe_load(open(toc_file_path, "r"))
@@ -164,43 +240,27 @@ def validate_toc(toc_file_path, expected_section_list, added_sections):
164240
# make sure each customs ection is in the toc
165241
for section in added_sections:
166242
assert section.title in found_sections
167-
# make sure each rst file in each custom section dir is listed in the toc
168-
for section in added_sections:
169-
items_in_toc = [
170-
d["items"]
171-
for d in current_toc[0]["items"]
172-
if d["name"] == section.title and ".rst"
173-
][0]
174-
items_in_dir = [f for f in os.listdir(section.dir_name) if f.endswith(".rst")]
175-
# subtract 1 for index
176-
assert len(items_in_toc) == len(items_in_dir) - 1
177-
for file in items_in_dir:
178-
if file != section.index_file_name:
179-
base_name, _ = os.path.splitext(file)
180-
assert any(d["href"] == f"{base_name}.md" for d in items_in_toc)
181-
# make sure the markdown files are present in the docfx_yaml directory
182-
for section in added_sections:
183-
items_in_toc = [
184-
d["items"]
185-
for d in current_toc[0]["items"]
186-
if d["name"] == section.title and ".rst"
187-
][0]
188-
md_files = [d["href"] for d in items_in_toc]
189-
for file in md_files:
190-
assert os.path.exists(f"_build/html/docfx_yaml/{file}")
243+
section.validate_section(current_toc)
191244
print("Toc validation passed")
192245

193246

194247
if __name__ == "__main__":
195248
# Add secrtions for the async_data_client and classic_client directories
196249
toc_path = "_build/html/docfx_yaml/toc.yml"
250+
197251
custom_sections = [
198252
TocSection(dir_name="data_client", index_file_name="data_client_usage.rst"),
253+
UIDFilteredTocSection(
254+
toc_file_path=toc_path,
255+
section_name="Bigtable Admin V2",
256+
title="Admin Client",
257+
uid_prefix="google.cloud.bigtable_admin_v2",
258+
),
199259
TocSection(dir_name="classic_client", index_file_name="usage.rst"),
200260
]
201261
add_sections(toc_path, custom_sections)
202262
# Remove the Bigtable section, since it has duplicated data
203-
remove_sections(toc_path, ["Bigtable"])
263+
remove_sections(toc_path, ["Bigtable", "Bigtable Admin V2"])
204264
# run validation to make sure yaml is structured as we expect
205265
validate_toc(
206266
toc_file_path=toc_path,
@@ -210,6 +270,7 @@ def validate_toc(toc_file_path, expected_section_list, added_sections):
210270
"Changelog",
211271
"Multiprocessing",
212272
"Data Client",
273+
"Admin Client",
213274
"Classic Client",
214275
],
215276
added_sections=custom_sections,

google/cloud/bigtable/backup.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import re
1818

1919
from google.cloud._helpers import _datetime_to_pb_timestamp # type: ignore
20-
from google.cloud.bigtable_admin_v2 import BigtableTableAdminClient
20+
from google.cloud.bigtable_admin_v2 import BaseBigtableTableAdminClient
2121
from google.cloud.bigtable_admin_v2.types import table
2222
from google.cloud.bigtable.encryption_info import EncryptionInfo
2323
from google.cloud.bigtable.policy import Policy
@@ -106,7 +106,7 @@ def name(self):
106106
if not self._cluster:
107107
raise ValueError('"cluster" parameter must be set')
108108

109-
return BigtableTableAdminClient.backup_path(
109+
return BaseBigtableTableAdminClient.backup_path(
110110
project=self._instance._client.project,
111111
instance=self._instance.instance_id,
112112
cluster=self._cluster,
@@ -141,7 +141,7 @@ def parent(self):
141141
:returns: A full path to the parent cluster.
142142
"""
143143
if not self._parent and self._cluster:
144-
self._parent = BigtableTableAdminClient.cluster_path(
144+
self._parent = BaseBigtableTableAdminClient.cluster_path(
145145
project=self._instance._client.project,
146146
instance=self._instance.instance_id,
147147
cluster=self._cluster,
@@ -163,7 +163,7 @@ def source_table(self):
163163
:returns: The Table name.
164164
"""
165165
if not self._source_table and self.table_id:
166-
self._source_table = BigtableTableAdminClient.table_path(
166+
self._source_table = BaseBigtableTableAdminClient.table_path(
167167
project=self._instance._client.project,
168168
instance=self._instance.instance_id,
169169
table=self.table_id,
@@ -226,7 +226,7 @@ def size_bytes(self):
226226
def state(self):
227227
"""The current state of this Backup.
228228
229-
:rtype: :class:`~google.cloud.bigtable_admin_v2.gapic.enums.Backup.State`
229+
:rtype: :class:`~google.cloud.bigtable_admin_v2.types.table.Backup.State`
230230
:returns: The current state of this Backup.
231231
"""
232232
return self._state
@@ -305,8 +305,7 @@ def create(self, cluster_id=None):
305305
created Backup.
306306
307307
:rtype: :class:`~google.api_core.operation.Operation`
308-
:returns: :class:`~google.cloud.bigtable_admin_v2.types._OperationFuture`
309-
instance, to be used to poll the status of the 'create' request
308+
:returns: A future to be used to poll the status of the 'create' request
310309
:raises Conflict: if the Backup already exists
311310
:raises NotFound: if the Instance owning the Backup does not exist
312311
:raises BadRequest: if the `table` or `expire_time` values are invalid,
@@ -412,7 +411,7 @@ def restore(self, table_id, instance_id=None):
412411
:param instance_id: (Optional) The ID of the Instance to restore the
413412
backup into, if different from the current one.
414413
415-
:rtype: :class:`~google.cloud.bigtable_admin_v2.types._OperationFuture`
414+
:rtype: :class:`~google.api_core.operation.Operation`
416415
:returns: A future to be used to poll the status of the 'restore'
417416
request.
418417
@@ -426,14 +425,14 @@ def restore(self, table_id, instance_id=None):
426425
"""
427426
api = self._instance._client.table_admin_client
428427
if instance_id:
429-
parent = BigtableTableAdminClient.instance_path(
428+
parent = BaseBigtableTableAdminClient.instance_path(
430429
project=self._instance._client.project,
431430
instance=instance_id,
432431
)
433432
else:
434433
parent = self._instance.name
435434

436-
return api.restore_table(
435+
return api._restore_table(
437436
request={"parent": parent, "table_id": table_id, "backup": self.name}
438437
)
439438

google/cloud/bigtable/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,11 @@ def table_admin_client(self):
325325
raise ValueError("Client is not an admin client.")
326326

327327
transport = self._create_gapic_client_channel(
328-
bigtable_admin_v2.BigtableTableAdminClient,
328+
bigtable_admin_v2.BaseBigtableTableAdminClient,
329329
BigtableTableAdminGrpcTransport,
330330
)
331331
klass = _create_gapic_client(
332-
bigtable_admin_v2.BigtableTableAdminClient,
332+
bigtable_admin_v2.BaseBigtableTableAdminClient,
333333
client_options=self._admin_client_options,
334334
transport=transport,
335335
)

google/cloud/bigtable/table.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
from google.cloud.bigtable.row_set import RowRange
4848
from google.cloud.bigtable import enums
4949
from google.cloud.bigtable_v2.types import bigtable as data_messages_v2_pb2
50-
from google.cloud.bigtable_admin_v2 import BigtableTableAdminClient
50+
from google.cloud.bigtable_admin_v2 import BaseBigtableTableAdminClient
5151
from google.cloud.bigtable_admin_v2.types import table as admin_messages_v2_pb2
5252
from google.cloud.bigtable_admin_v2.types import (
5353
bigtable_table_admin as table_admin_messages_v2_pb2,
@@ -990,7 +990,7 @@ def list_backups(self, cluster_id=None, filter_=None, order_by=None, page_size=0
990990
if filter_:
991991
backups_filter = "({}) AND ({})".format(backups_filter, filter_)
992992

993-
parent = BigtableTableAdminClient.cluster_path(
993+
parent = BaseBigtableTableAdminClient.cluster_path(
994994
project=self._instance._client.project,
995995
instance=self._instance.instance_id,
996996
cluster=cluster_id,
@@ -1037,7 +1037,7 @@ def restore(self, new_table_id, cluster_id=None, backup_id=None, backup_name=Non
10371037
and `backup_id` parameters even of such specified.
10381038
10391039
:return: An instance of
1040-
:class:`~google.cloud.bigtable_admin_v2.types._OperationFuture`.
1040+
:class:`~google.api_core.operation.Operation`.
10411041
10421042
:raises: google.api_core.exceptions.AlreadyExists: If the table
10431043
already exists.
@@ -1049,13 +1049,13 @@ def restore(self, new_table_id, cluster_id=None, backup_id=None, backup_name=Non
10491049
"""
10501050
api = self._instance._client.table_admin_client
10511051
if not backup_name:
1052-
backup_name = BigtableTableAdminClient.backup_path(
1052+
backup_name = BaseBigtableTableAdminClient.backup_path(
10531053
project=self._instance._client.project,
10541054
instance=self._instance.instance_id,
10551055
cluster=cluster_id,
10561056
backup=backup_id,
10571057
)
1058-
return api.restore_table(
1058+
return api._restore_table(
10591059
request={
10601060
"parent": self._instance.name,
10611061
"table_id": new_table_id,

0 commit comments

Comments
 (0)