diff --git a/releasenotes/notes/add-cluster-instances-to-osc-429eeb91d86da663.yaml b/releasenotes/notes/add-cluster-instances-to-osc-429eeb91d86da663.yaml new file mode 100644 index 00000000..05637a0e --- /dev/null +++ b/releasenotes/notes/add-cluster-instances-to-osc-429eeb91d86da663.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The command ``trove cluster-instances`` is now available to use in + the python-openstackclient CLI as ``openstack database cluster + list instances``. diff --git a/setup.cfg b/setup.cfg index bc0c80f2..e9c4f210 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,6 +38,7 @@ openstack.database.v1 = database_cluster_create = troveclient.osc.v1.database_clusters:CreateDatabaseCluster database_cluster_delete = troveclient.osc.v1.database_clusters:DeleteDatabaseCluster database_cluster_list = troveclient.osc.v1.database_clusters:ListDatabaseClusters + database_cluster_list_instances = troveclient.osc.v1.database_clusters:ListDatabaseClusterInstances database_cluster_reset_status = troveclient.osc.v1.database_clusters:ResetDatabaseClusterStatus database_cluster_show = troveclient.osc.v1.database_clusters:ShowDatabaseCluster database_configuration_attach = troveclient.osc.v1.database_configurations:AttachDatabaseConfiguration diff --git a/troveclient/osc/v1/database_clusters.py b/troveclient/osc/v1/database_clusters.py index f4723313..77733d3d 100644 --- a/troveclient/osc/v1/database_clusters.py +++ b/troveclient/osc/v1/database_clusters.py @@ -205,3 +205,31 @@ class ResetDatabaseClusterStatus(command.Command): cluster = utils.find_resource(database_clusters, parsed_args.cluster) database_clusters.reset_status(cluster) + + +class ListDatabaseClusterInstances(command.Lister): + + _description = _("Lists all instances of a cluster.") + columns = ['ID', 'Name', 'Flavor ID', 'Size', 'Status'] + + def get_parser(self, prog_name): + parser = (super(ListDatabaseClusterInstances, self) + .get_parser(prog_name)) + parser.add_argument( + 'cluster', + metavar='', + help=_('ID or name of the cluster.')) + return parser + + def take_action(self, parsed_args): + database_clusters = self.app.client_manager.database.clusters + cluster = utils.find_resource(database_clusters, parsed_args.cluster) + instances = cluster._info['instances'] + for instance in instances: + instance['flavor_id'] = instance['flavor']['id'] + if instance.get('volume'): + instance['size'] = instance['volume']['size'] + + instances = [utils.get_dict_properties(inst, self.columns) + for inst in instances] + return self.columns, instances diff --git a/troveclient/tests/fakes.py b/troveclient/tests/fakes.py index 708dedfd..48557b2b 100644 --- a/troveclient/tests/fakes.py +++ b/troveclient/tests/fakes.py @@ -347,8 +347,42 @@ class FakeHTTPClient(base_client.HTTPClient): "id": "cls-1234"}]}) def get_clusters_cls_1234(self, **kw): - r = {'cluster': self.get_clusters()[2]['clusters'][0]} - return (200, {}, r) + # NOTE(zhaochao): getting a cluster will load instances + # informations while getting the list of clusters won't, + # so we cannot just reuse the reponse of getting clusters + # for getting a cluster. + # The following response body is almost identical to the + # result of get_clusters, except the additional 'status' + # and 'volume' items, so all existing unitests accessing + # this piece of fake response will continue to work + # without any modification. + return (200, {}, {'cluster': { + "instances": [ + { + "type": "member", + "id": "member-1", + "ip": ["10.0.0.3"], + "flavor": {"id": "02"}, + "name": "test-clstr-member-1", + "status": "ACTIVE", + "volume": {"size": 2} + }, + { + "type": "member", + "id": "member-2", + "ip": ["10.0.0.4"], + "flavor": {"id": "2"}, + "name": "test-clstr-member-2", + "status": "ACTIVE", + "volume": {"size": 2} + }], + "updated": "2015-05-02T11:06:19", + "task": {"description": "No tasks for the cluster.", "id": 1, + "name": "NONE"}, + "name": "test-clstr", + "created": "2015-05-02T10:37:04", + "datastore": {"version": "7.1", "type": "vertica"}, + "id": "cls-1234"}}) def delete_instances_1234(self, **kw): return (202, {}, None) diff --git a/troveclient/tests/osc/v1/fakes.py b/troveclient/tests/osc/v1/fakes.py index e6f97f0f..cfaf2f2f 100644 --- a/troveclient/tests/osc/v1/fakes.py +++ b/troveclient/tests/osc/v1/fakes.py @@ -48,9 +48,11 @@ class FakeBackups(object): class FakeClusters(object): fake_clusters = fakes.FakeHTTPClient().get_clusters()[2]['clusters'] + fake_cluster = (fakes.FakeHTTPClient() + .get_clusters_cls_1234()[2]['cluster']) def get_clusters_cls_1234(self): - return clusters.Cluster(None, self.fake_clusters[0]) + return clusters.Cluster(None, self.fake_cluster) class FakeConfigurations(object): diff --git a/troveclient/tests/osc/v1/test_database_clusters.py b/troveclient/tests/osc/v1/test_database_clusters.py index 751b8478..4d0bab47 100644 --- a/troveclient/tests/osc/v1/test_database_clusters.py +++ b/troveclient/tests/osc/v1/test_database_clusters.py @@ -166,3 +166,25 @@ class TestDatabaseClusterResetStatus(TestClusters): result = self.cmd.take_action(parsed_args) self.cluster_client.reset_status.assert_called_with('cluster1') self.assertIsNone(result) + + +class TestClusterListInstances(TestClusters): + + columns = (database_clusters + .ListDatabaseClusterInstances.columns) + values = [('member-1', 'test-clstr-member-1', '02', 2, 'ACTIVE'), + ('member-2', 'test-clstr-member-2', '2', 2, 'ACTIVE')] + + def setUp(self): + super(TestClusterListInstances, self).setUp() + self.cmd = (database_clusters + .ListDatabaseClusterInstances(self.app, None)) + self.data = self.fake_clusters.get_clusters_cls_1234() + self.cluster_client.get.return_value = self.data + + def test_cluster_list_instances(self): + args = ['cls-1234'] + parsed_args = self.check_parser(self.cmd, args, []) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.columns, columns) + self.assertEqual(self.values, data)