Skip to content

Commit 9320a41

Browse files
AVaksmantseaver
authored andcommitted
Bigtable: add 'Client.list_clusters()' (googleapis#5715)
1 parent e71a6f3 commit 9320a41

File tree

4 files changed

+110
-1
lines changed

4 files changed

+110
-1
lines changed

bigtable/google/cloud/bigtable/client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636

3737
from google.cloud.bigtable import __version__
3838
from google.cloud.bigtable.instance import Instance
39+
from google.cloud.bigtable.cluster import Cluster
3940

4041
from google.cloud.client import ClientWithProject
4142

4243
from google.cloud.bigtable_admin_v2 import enums
44+
from google.cloud.bigtable.cluster import _CLUSTER_NAME_RE
4345

4446

4547
INSTANCE_TYPE_PRODUCTION = enums.Instance.Type.PRODUCTION
@@ -252,3 +254,25 @@ def list_instances(self):
252254
instances = [
253255
Instance.from_pb(instance, self) for instance in resp.instances]
254256
return instances, resp.failed_locations
257+
258+
def list_clusters(self):
259+
"""List the clusters in the project.
260+
261+
:rtype: tuple
262+
:returns:
263+
(clusters, failed_locations), where 'clusters' is list of
264+
:class:`google.cloud.bigtable.instance.Cluster`, and
265+
'failed_locations' is a list of strings representing
266+
locations which could not be resolved.
267+
"""
268+
resp = (self.instance_admin_client.list_clusters(
269+
self.instance_admin_client.instance_path(self.project, '-')))
270+
clusters = []
271+
instances = {}
272+
for cluster in resp.clusters:
273+
match_cluster_name = _CLUSTER_NAME_RE.match(cluster.name)
274+
instance_id = match_cluster_name.group('instance')
275+
if instance_id not in instances:
276+
instances[instance_id] = self.instance(instance_id)
277+
clusters.append(Cluster.from_pb(cluster, instances[instance_id]))
278+
return clusters, resp.failed_locations

bigtable/tests/system.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,14 @@ def test_create_instance_w_two_clusters(self):
261261
self.assertEqual(cluster_2.default_storage_type,
262262
alt_cluster_2.default_storage_type)
263263

264+
# Test list clusters in project via 'client.list_clusters'
265+
clusters, failed_locations = Config.CLIENT.list_clusters()
266+
self.assertFalse(failed_locations)
267+
found = set([cluster.name for cluster in clusters])
268+
self.assertTrue({alt_cluster_1.name,
269+
alt_cluster_2.name,
270+
Config.CLUSTER.name}.issubset(found))
271+
264272
def test_update_display_name_and_labels(self):
265273
OLD_DISPLAY_NAME = Config.INSTANCE.display_name
266274
NEW_DISPLAY_NAME = 'Foo Bar Baz'

bigtable/tests/unit/test_client.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,80 @@ def test_list_instances(self):
226226
self.assertTrue(instance_2._client is client)
227227

228228
self.assertEqual(failed_locations, [FAILED_LOCATION])
229+
230+
def test_list_clusters(self):
231+
from google.cloud.bigtable_admin_v2.gapic import (
232+
bigtable_instance_admin_client)
233+
from google.cloud.bigtable_admin_v2.proto import (
234+
bigtable_instance_admin_pb2 as messages_v2_pb2)
235+
from google.cloud.bigtable_admin_v2.proto import (
236+
instance_pb2 as data_v2_pb2)
237+
from google.cloud.bigtable.instance import Cluster
238+
239+
instance_api = (
240+
bigtable_instance_admin_client.BigtableInstanceAdminClient(
241+
mock.Mock()))
242+
credentials = _make_credentials()
243+
client = self._make_one(project=self.PROJECT, credentials=credentials,
244+
admin=True)
245+
246+
INSTANCE_ID1 = 'instance-id1'
247+
INSTANCE_ID2 = 'instance-id2'
248+
249+
failed_location = 'FAILED'
250+
cluster_id1 = '{}-cluster'.format(INSTANCE_ID1)
251+
cluster_id2 = '{}-cluster-1'.format(INSTANCE_ID2)
252+
cluster_id3 = '{}-cluster-2'.format(INSTANCE_ID2)
253+
cluster_name1 = (client.instance_admin_client.cluster_path(
254+
self.PROJECT, INSTANCE_ID1, cluster_id1))
255+
cluster_name2 = (client.instance_admin_client.cluster_path(
256+
self.PROJECT, INSTANCE_ID2, cluster_id2))
257+
cluster_name3 = (client.instance_admin_client.cluster_path(
258+
self.PROJECT, INSTANCE_ID2, cluster_id3))
259+
260+
# Create response_pb
261+
response_pb = messages_v2_pb2.ListClustersResponse(
262+
failed_locations=[
263+
failed_location
264+
],
265+
clusters=[
266+
data_v2_pb2.Cluster(
267+
name=cluster_name1,
268+
),
269+
data_v2_pb2.Cluster(
270+
name=cluster_name2,
271+
),
272+
data_v2_pb2.Cluster(
273+
name=cluster_name3,
274+
),
275+
276+
],
277+
)
278+
279+
# Patch the stub used by the API method.
280+
client._instance_admin_client = instance_api
281+
instance_stub = (
282+
client._instance_admin_client.bigtable_instance_admin_stub)
283+
instance_stub.ListClusters.side_effect = [response_pb]
284+
285+
# Perform the method and check the result.
286+
clusters, failed_locations = client.list_clusters()
287+
288+
cluster_1, cluster_2, cluster_3 = clusters
289+
290+
self.assertIsInstance(cluster_1, Cluster)
291+
self.assertEqual(cluster_1.name, cluster_name1)
292+
self.assertEqual(cluster_1._instance.instance_id,
293+
INSTANCE_ID1)
294+
295+
self.assertIsInstance(cluster_2, Cluster)
296+
self.assertEqual(cluster_2.name, cluster_name2)
297+
self.assertEqual(cluster_2._instance.instance_id,
298+
INSTANCE_ID2)
299+
300+
self.assertIsInstance(cluster_3, Cluster)
301+
self.assertEqual(cluster_3.name, cluster_name3)
302+
self.assertEqual(cluster_3._instance.instance_id,
303+
INSTANCE_ID2)
304+
305+
self.assertEqual(failed_locations, [failed_location])

bigtable/tests/unit/test_instance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def test_list_clusters(self):
166166

167167
failed_location = 'FAILED'
168168
cluster_id1 = 'cluster-id1'
169-
cluster_id2 = 'ckuster-id2'
169+
cluster_id2 = 'cluster-id2'
170170
cluster_name1 = (client.instance_admin_client.cluster_path(
171171
self.PROJECT, self.INSTANCE_ID, cluster_id1))
172172
cluster_name2 = (client.instance_admin_client.cluster_path(

0 commit comments

Comments
 (0)