Skip to content

Commit 34c560e

Browse files
google-genai-botcopybara-github
authored andcommitted
feat(bigtable): add Bigtable cluster metadata tools
PiperOrigin-RevId: 878648015
1 parent d0825d8 commit 34c560e

File tree

5 files changed

+492
-118
lines changed

5 files changed

+492
-118
lines changed

contributing/samples/bigtable/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
credentials_config=credentials_config, bigtable_tool_settings=tool_settings
6363
)
6464

65-
_BIGTABLE_PROJECT_ID = "google.com:cloud-bigtable-dev"
66-
_BIGTABLE_INSTANCE_ID = "annenguyen-bus-instance"
65+
_BIGTABLE_PROJECT_ID = ""
66+
_BIGTABLE_INSTANCE_ID = ""
6767

6868

6969
def search_hotels_by_location(

src/google/adk/tools/bigtable/bigtable_toolset.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class BigtableToolset(BaseToolset):
4444
- bigtable_get_instance_info
4545
- bigtable_list_tables
4646
- bigtable_get_table_info
47+
- bigtable_list_clusters
48+
- bigtable_get_cluster_info
4749
- bigtable_execute_sql
4850
"""
4951

@@ -95,6 +97,8 @@ async def get_tools(
9597
metadata_tool.get_instance_info,
9698
metadata_tool.list_tables,
9799
metadata_tool.get_table_info,
100+
metadata_tool.list_clusters,
101+
metadata_tool.get_cluster_info,
98102
query_tool.execute_sql,
99103
]
100104
]

src/google/adk/tools/bigtable/metadata_tool.py

Lines changed: 259 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414

1515
from __future__ import annotations
1616

17+
import enum
1718
import logging
1819

1920
from google.auth.credentials import Credentials
21+
from google.cloud.bigtable import enums
2022

2123
from . import client
2224

25+
logger = logging.getLogger(f"google_adk.{__name__}")
26+
2327

2428
def list_instances(project_id: str, credentials: Credentials) -> dict:
2529
"""List Bigtable instance ids in a Google Cloud project.
@@ -29,7 +33,22 @@ def list_instances(project_id: str, credentials: Credentials) -> dict:
2933
credentials (Credentials): The credentials to use for the request.
3034
3135
Returns:
32-
dict: Dictionary with a list of the Bigtable instance ids present in the project.
36+
dict: Dictionary with a list of dictionaries, each representing a Bigtable instance.
37+
38+
Example:
39+
{
40+
"status": "SUCCESS",
41+
"results": [
42+
{
43+
"project_id": "test-project",
44+
"instance_id": "test-instance",
45+
"display_name": "Test Instance",
46+
"state": "READY",
47+
"type": "PRODUCTION",
48+
"labels": {"env": "test"},
49+
}
50+
],
51+
}
3352
"""
3453
try:
3554
bt_client = client.get_bigtable_admin_client(
@@ -41,12 +60,27 @@ def list_instances(project_id: str, credentials: Credentials) -> dict:
4160
"Failed to list instances from the following locations: %s",
4261
failed_locations_list,
4362
)
44-
instance_ids = [instance.instance_id for instance in instances_list]
45-
return {"status": "SUCCESS", "results": instance_ids}
63+
result = [
64+
{
65+
"project_id": project_id,
66+
"instance_id": instance.instance_id,
67+
"display_name": instance.display_name,
68+
"state": _enum_name_from_value(
69+
enums.Instance.State, instance.state, "UNKNOWN_STATE"
70+
),
71+
"type": _enum_name_from_value(
72+
enums.Instance.Type, instance.type_, "UNKNOWN_TYPE"
73+
),
74+
"labels": instance.labels,
75+
}
76+
for instance in instances_list
77+
]
78+
return {"status": "SUCCESS", "results": result}
4679
except Exception as ex:
80+
logger.exception("Bigtable metadata tool failed: %s", ex)
4781
return {
4882
"status": "ERROR",
49-
"error_details": str(ex),
83+
"error_details": repr(ex),
5084
}
5185

5286

@@ -69,52 +103,85 @@ def get_instance_info(
69103
)
70104
instance = bt_client.instance(instance_id)
71105
instance.reload()
72-
instance_info = {
73-
"project_id": project_id,
74-
"instance_id": instance.instance_id,
75-
"display_name": instance.display_name,
76-
"state": instance.state,
77-
"type": instance.type_,
78-
"labels": instance.labels,
106+
return {
107+
"status": "SUCCESS",
108+
"results": {
109+
"project_id": project_id,
110+
"instance_id": instance.instance_id,
111+
"display_name": instance.display_name,
112+
"state": _enum_name_from_value(
113+
enums.Instance.State, instance.state, "UNKNOWN_STATE"
114+
),
115+
"type": _enum_name_from_value(
116+
enums.Instance.Type, instance.type_, "UNKNOWN_TYPE"
117+
),
118+
"labels": instance.labels,
119+
},
79120
}
80-
return {"status": "SUCCESS", "results": instance_info}
81121
except Exception as ex:
122+
logger.exception("Bigtable metadata tool failed: %s", ex)
82123
return {
83124
"status": "ERROR",
84-
"error_details": str(ex),
125+
"error_details": repr(ex),
85126
}
86127

87128

88129
def list_tables(
89130
project_id: str, instance_id: str, credentials: Credentials
90131
) -> dict:
91-
"""List table ids in a Bigtable instance.
132+
"""List tables and their metadata in a Bigtable instance.
92133
93134
Args:
94135
project_id (str): The Google Cloud project id containing the instance.
95136
instance_id (str): The Bigtable instance id.
96137
credentials (Credentials): The credentials to use for the request.
97138
98139
Returns:
99-
dict: Dictionary with a list of the tables ids present in the instance.
140+
dict: A dictionary with status and results, where results is a list of
141+
table properties.
142+
143+
Example:
144+
{
145+
"status": "SUCCESS",
146+
"results": [
147+
{
148+
"project_id": "test-project",
149+
"instance_id": "test-instance",
150+
"table_id": "test-table",
151+
"table_name": "fake-table-name",
152+
}
153+
],
154+
}
100155
"""
101156
try:
102157
bt_client = client.get_bigtable_admin_client(
103158
project=project_id, credentials=credentials
104159
)
105160
instance = bt_client.instance(instance_id)
106161
tables = instance.list_tables()
107-
table_ids = [table.table_id for table in tables]
108-
return {"status": "SUCCESS", "results": table_ids}
162+
result = [
163+
{
164+
"project_id": project_id,
165+
"instance_id": instance_id,
166+
"table_id": table.table_id,
167+
"table_name": table.name,
168+
}
169+
for table in tables
170+
]
171+
return {"status": "SUCCESS", "results": result}
109172
except Exception as ex:
173+
logger.exception("Bigtable metadata tool failed: %s", ex)
110174
return {
111175
"status": "ERROR",
112-
"error_details": str(ex),
176+
"error_details": repr(ex),
113177
}
114178

115179

116180
def get_table_info(
117-
project_id: str, instance_id: str, table_id: str, credentials: Credentials
181+
project_id: str,
182+
instance_id: str,
183+
table_id: str,
184+
credentials: Credentials,
118185
) -> dict:
119186
"""Get metadata information about a Bigtable table.
120187
@@ -126,6 +193,17 @@ def get_table_info(
126193
127194
Returns:
128195
dict: Dictionary representing the properties of the table.
196+
197+
Example:
198+
{
199+
"status": "SUCCESS",
200+
"results": {
201+
"project_id": "test-project",
202+
"instance_id": "test-instance",
203+
"table_id": "test-table",
204+
"column_families": ["cf1", "cf2"],
205+
},
206+
}
129207
"""
130208
try:
131209
bt_client = client.get_bigtable_admin_client(
@@ -134,15 +212,170 @@ def get_table_info(
134212
instance = bt_client.instance(instance_id)
135213
table = instance.table(table_id)
136214
column_families = table.list_column_families()
137-
table_info = {
138-
"project_id": project_id,
139-
"instance_id": instance.instance_id,
140-
"table_id": table.table_id,
141-
"column_families": list(column_families.keys()),
215+
return {
216+
"status": "SUCCESS",
217+
"results": {
218+
"project_id": project_id,
219+
"instance_id": instance.instance_id,
220+
"table_id": table.table_id,
221+
"column_families": list(column_families.keys()),
222+
},
223+
}
224+
except Exception as ex:
225+
logger.exception("Bigtable metadata tool failed: %s", ex)
226+
return {
227+
"status": "ERROR",
228+
"error_details": repr(ex),
229+
}
230+
231+
232+
def _enum_name_from_value(
233+
enum_class: type[enum.Enum], value: int, prefix: str = "UNKNOWN"
234+
) -> str:
235+
for attr_name in dir(enum_class):
236+
if not attr_name.startswith("_"):
237+
if getattr(enum_class, attr_name) == value:
238+
return attr_name
239+
return f"{prefix}_{value}"
240+
241+
242+
def list_clusters(
243+
project_id: str, instance_id: str, credentials: Credentials
244+
) -> dict:
245+
"""List clusters and their metadata in a Bigtable instance.
246+
247+
Args:
248+
project_id (str): The Google Cloud project id containing the instance.
249+
instance_id (str): The Bigtable instance id.
250+
credentials (Credentials): The credentials to use for the request.
251+
252+
Returns:
253+
dict: Dictionary representing the properties of the cluster.
254+
255+
Example:
256+
{
257+
"status": "SUCCESS",
258+
"results": [
259+
{
260+
"project_id": "test-project",
261+
"instance_id": "test-instance",
262+
"cluster_id": "test-cluster",
263+
"cluster_name": "fake-cluster-name",
264+
"state": "READY",
265+
"serve_nodes": 3,
266+
"default_storage_type": "SSD",
267+
"location_id": "us-central1-a",
268+
}
269+
],
270+
}
271+
"""
272+
try:
273+
bt_client = client.get_bigtable_admin_client(
274+
project=project_id, credentials=credentials
275+
)
276+
instance = bt_client.instance(instance_id)
277+
instance.reload()
278+
clusters_list, failed_locations = instance.list_clusters()
279+
if failed_locations:
280+
logging.warning(
281+
"Failed to list clusters from the following locations: %s",
282+
failed_locations,
283+
)
284+
285+
result = [
286+
{
287+
"project_id": project_id,
288+
"instance_id": instance_id,
289+
"cluster_id": cluster.cluster_id,
290+
"cluster_name": cluster.name,
291+
"state": _enum_name_from_value(
292+
enums.Cluster.State, cluster.state, "UNKNOWN_STATE"
293+
),
294+
"serve_nodes": cluster.serve_nodes,
295+
"default_storage_type": _enum_name_from_value(
296+
enums.StorageType,
297+
cluster.default_storage_type,
298+
"UNKNOWN_STORAGE_TYPE",
299+
),
300+
"location_id": cluster.location_id,
301+
}
302+
for cluster in clusters_list
303+
]
304+
return {"status": "SUCCESS", "results": result}
305+
except Exception as ex:
306+
logger.exception("Bigtable metadata tool failed: %s", ex)
307+
return {
308+
"status": "ERROR",
309+
"error_details": repr(ex),
310+
}
311+
312+
313+
def get_cluster_info(
314+
project_id: str,
315+
instance_id: str,
316+
cluster_id: str,
317+
credentials: Credentials,
318+
) -> dict:
319+
"""Get detailed metadata information about a Bigtable cluster.
320+
321+
Args:
322+
project_id (str): The Google Cloud project id containing the instance.
323+
instance_id (str): The Bigtable instance id containing the cluster.
324+
cluster_id (str): The Bigtable cluster id.
325+
credentials (Credentials): The credentials to use for the request.
326+
327+
Returns:
328+
dict: Dictionary representing the properties of the cluster.
329+
330+
Example:
331+
{
332+
"status": "SUCCESS",
333+
"results": {
334+
"project_id": "test-project",
335+
"instance_id": "test-instance",
336+
"cluster_id": "test-cluster",
337+
"state": "READY",
338+
"serve_nodes": 3,
339+
"default_storage_type": "SSD",
340+
"location_id": "us-central1-a",
341+
"min_serve_nodes": 1,
342+
"max_serve_nodes": 10,
343+
"cpu_utilization_percent": 80,
344+
},
345+
}
346+
"""
347+
try:
348+
bt_client = client.get_bigtable_admin_client(
349+
project=project_id, credentials=credentials
350+
)
351+
instance = bt_client.instance(instance_id)
352+
instance.reload()
353+
cluster = instance.cluster(cluster_id)
354+
cluster.reload()
355+
return {
356+
"status": "SUCCESS",
357+
"results": {
358+
"project_id": project_id,
359+
"instance_id": instance_id,
360+
"cluster_id": cluster.cluster_id,
361+
"state": _enum_name_from_value(
362+
enums.Cluster.State, cluster.state, "UNKNOWN_STATE"
363+
),
364+
"serve_nodes": cluster.serve_nodes,
365+
"default_storage_type": _enum_name_from_value(
366+
enums.StorageType,
367+
cluster.default_storage_type,
368+
"UNKNOWN_STORAGE_TYPE",
369+
),
370+
"location_id": cluster.location_id,
371+
"min_serve_nodes": cluster.min_serve_nodes,
372+
"max_serve_nodes": cluster.max_serve_nodes,
373+
"cpu_utilization_percent": cluster.cpu_utilization_percent,
374+
},
142375
}
143-
return {"status": "SUCCESS", "results": table_info}
144376
except Exception as ex:
377+
logger.exception("Bigtable metadata tool failed: %s", ex)
145378
return {
146379
"status": "ERROR",
147-
"error_details": str(ex),
380+
"error_details": repr(ex),
148381
}

0 commit comments

Comments
 (0)