Add cluster-grow and cluster-shrink to OSC
This change adds database support to python-openstackclient
project for the cluster-grow and cluster-shrink commands.
The trove command cluster-grow is now:
    openstack database cluster grow
The trove command cluster-shrink is now:
    openstack database cluster shrink
Change-Id: I449e7f7d841ea266611ff79f8a41f6e730fced3c
Partially-Implements: blueprint trove-support-in-python-openstackclient
Signed-off-by: Zhao Chao <zhaochao1984@gmail.com>
			
			
This commit is contained in:
		@@ -0,0 +1,10 @@
 | 
			
		||||
---
 | 
			
		||||
features:
 | 
			
		||||
  - |
 | 
			
		||||
    The command ``trove cluster-grow`` is now available
 | 
			
		||||
    to use in the python-openstackclient CLI as ``openstack database
 | 
			
		||||
    cluster grow``
 | 
			
		||||
  - |
 | 
			
		||||
    The command ``trove cluster-shrink`` is now available
 | 
			
		||||
    to use in the python-openstackclient CLI as ``openstack database
 | 
			
		||||
    cluster shrink``
 | 
			
		||||
@@ -38,10 +38,12 @@ openstack.database.v1 =
 | 
			
		||||
    database_cluster_create = troveclient.osc.v1.database_clusters:CreateDatabaseCluster
 | 
			
		||||
    database_cluster_delete = troveclient.osc.v1.database_clusters:DeleteDatabaseCluster
 | 
			
		||||
    database_cluster_force_delete = troveclient.osc.v1.database_clusters:ForceDeleteDatabaseCluster
 | 
			
		||||
    database_cluster_grow = troveclient.osc.v1.database_clusters:GrowDatabaseCluster
 | 
			
		||||
    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_cluster_shrink = troveclient.osc.v1.database_clusters:ShrinkDatabaseCluster
 | 
			
		||||
    database_cluster_upgrade = troveclient.osc.v1.database_clusters:UpgradeDatabaseCluster
 | 
			
		||||
    database_configuration_attach = troveclient.osc.v1.database_configurations:AttachDatabaseConfiguration
 | 
			
		||||
    database_configuration_create = troveclient.osc.v1.database_configurations:CreateDatabaseConfiguration
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,8 @@ import six
 | 
			
		||||
 | 
			
		||||
from troveclient.i18n import _
 | 
			
		||||
from troveclient.v1.shell import _parse_instance_options
 | 
			
		||||
from troveclient.v1.shell import INSTANCE_HELP
 | 
			
		||||
from troveclient.v1.shell import INSTANCE_METAVAR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_attributes_for_print_detail(cluster):
 | 
			
		||||
@@ -149,21 +151,11 @@ class CreateDatabaseCluster(command.ShowOne):
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--instance',
 | 
			
		||||
            metavar='"opt=<value>[,opt=<value> ...] "',
 | 
			
		||||
            metavar=INSTANCE_METAVAR,
 | 
			
		||||
            action='append',
 | 
			
		||||
            dest='instances',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help=_("Add an instance to the cluster.  Specify multiple "
 | 
			
		||||
                   "times to create multiple instances.  "
 | 
			
		||||
                   "Valid options are: flavor=<flavor_name_or_id>, "
 | 
			
		||||
                   "volume=<disk_size_in_GB>, volume_type=<type>, "
 | 
			
		||||
                   "nic='<net-id=<net-uuid>, v4-fixed-ip=<ip-addr>, "
 | 
			
		||||
                   "port-id=<port-uuid>>' "
 | 
			
		||||
                   "(where net-id=network_id, "
 | 
			
		||||
                   "v4-fixed-ip=IPv4r_fixed_address, port-id=port_id), "
 | 
			
		||||
                   "availability_zone=<AZ_hint_for_Nova>, "
 | 
			
		||||
                   "module=<module_name_or_id>, type=<type_of_cluster_node>, "
 | 
			
		||||
                   "related_to=<related_attribute>."),
 | 
			
		||||
            help=INSTANCE_HELP,
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--locality',
 | 
			
		||||
@@ -284,3 +276,74 @@ class ForceDeleteDatabaseCluster(command.Command):
 | 
			
		||||
            msg = (_("Failed to delete cluster %(cluster)s: %(e)s")
 | 
			
		||||
                   % {'cluster': parsed_args.cluster, 'e': e})
 | 
			
		||||
            raise exceptions.CommandError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GrowDatabaseCluster(command.Command):
 | 
			
		||||
 | 
			
		||||
    _description = _("Adds more instances to a cluster.")
 | 
			
		||||
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(GrowDatabaseCluster, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--instance',
 | 
			
		||||
            metavar=INSTANCE_METAVAR,
 | 
			
		||||
            action='append',
 | 
			
		||||
            dest='instances',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help=INSTANCE_HELP
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            'cluster',
 | 
			
		||||
            metavar='<cluster>',
 | 
			
		||||
            help=_('ID or name of the cluster.')
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        database_client_manager = self.app.client_manager.database
 | 
			
		||||
 | 
			
		||||
        db_clusters = database_client_manager.clusters
 | 
			
		||||
        cluster = utils.find_resource(db_clusters,
 | 
			
		||||
                                      parsed_args.cluster)
 | 
			
		||||
 | 
			
		||||
        instances = _parse_instance_options(database_client_manager,
 | 
			
		||||
                                            parsed_args.instances,
 | 
			
		||||
                                            for_grow=True)
 | 
			
		||||
        db_clusters.grow(cluster, instances=instances)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ShrinkDatabaseCluster(command.Command):
 | 
			
		||||
 | 
			
		||||
    _description = _("Drops instances from a cluster.")
 | 
			
		||||
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ShrinkDatabaseCluster, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            'cluster',
 | 
			
		||||
            metavar='<cluster>',
 | 
			
		||||
            help=_('ID or name of the cluster.')
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            'instances',
 | 
			
		||||
            metavar='<instance>',
 | 
			
		||||
            nargs='+',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help=_("Drop instance(s) from the cluster. Specify "
 | 
			
		||||
                   "multiple ids to drop multiple instances.")
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        database_client_manager = self.app.client_manager.database
 | 
			
		||||
 | 
			
		||||
        db_clusters = database_client_manager.clusters
 | 
			
		||||
        cluster = utils.find_resource(db_clusters,
 | 
			
		||||
                                      parsed_args.cluster)
 | 
			
		||||
 | 
			
		||||
        db_instances = database_client_manager.instances
 | 
			
		||||
        instances = [
 | 
			
		||||
            {'id': utils.find_resource(db_instances,
 | 
			
		||||
                                       instance).id}
 | 
			
		||||
            for instance in parsed_args.instances
 | 
			
		||||
        ]
 | 
			
		||||
        db_clusters.shrink(cluster, instances)
 | 
			
		||||
 
 | 
			
		||||
@@ -51,10 +51,14 @@ class FakeClusters(object):
 | 
			
		||||
    fake_clusters = fakes.FakeHTTPClient().get_clusters()[2]['clusters']
 | 
			
		||||
    fake_cluster = (fakes.FakeHTTPClient()
 | 
			
		||||
                    .get_clusters_cls_1234()[2]['cluster'])
 | 
			
		||||
    fake_cluster_member = fake_cluster['instances'][1]
 | 
			
		||||
 | 
			
		||||
    def get_clusters_cls_1234(self):
 | 
			
		||||
        return clusters.Cluster(None, self.fake_cluster)
 | 
			
		||||
 | 
			
		||||
    def get_clusters_member_2(self):
 | 
			
		||||
        return instances.Instance(None, self.fake_cluster_member)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeConfigurations(object):
 | 
			
		||||
    fake_config = (fakes.FakeHTTPClient().get_configurations()
 | 
			
		||||
 
 | 
			
		||||
@@ -233,3 +233,51 @@ class TestDatabaseClusterForceDelete(TestClusters):
 | 
			
		||||
        self.assertRaises(exceptions.CommandError,
 | 
			
		||||
                          self.cmd.take_action,
 | 
			
		||||
                          parsed_args)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestDatabaseClusterGrow(TestClusters):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestDatabaseClusterGrow, self).setUp()
 | 
			
		||||
        self.cmd = database_clusters.GrowDatabaseCluster(self.app, None)
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(utils, 'find_resource')
 | 
			
		||||
    @mock.patch.object(database_clusters, '_parse_instance_options')
 | 
			
		||||
    def test_cluster_grow(self, mock_parse_instance_opts,
 | 
			
		||||
                          mock_find_resource):
 | 
			
		||||
        args = ['test-clstr',
 | 
			
		||||
                '--instance',
 | 
			
		||||
                'name=test-clstr-member-3,flavor=3']
 | 
			
		||||
        parsed_instance_opts = [
 | 
			
		||||
            {'name': 'test-clstr-member-3',
 | 
			
		||||
             'flavor': 3}
 | 
			
		||||
        ]
 | 
			
		||||
        mock_parse_instance_opts.return_value = parsed_instance_opts
 | 
			
		||||
        mock_find_resource.return_value = args[0]
 | 
			
		||||
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, args, [])
 | 
			
		||||
        result = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.cluster_client.grow.assert_called_with(
 | 
			
		||||
            'test-clstr',
 | 
			
		||||
            instances=parsed_instance_opts)
 | 
			
		||||
        self.assertIsNone(result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestDatabaseClusterShrink(TestClusters):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestDatabaseClusterShrink, self).setUp()
 | 
			
		||||
        self.cmd = database_clusters.ShrinkDatabaseCluster(self.app, None)
 | 
			
		||||
        self.cluster_member = self.fake_clusters.get_clusters_member_2()
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(utils, 'find_resource')
 | 
			
		||||
    def test_cluster_grow(self, mock_find_resource):
 | 
			
		||||
        args = ['test-clstr', 'test-clstr-member-2']
 | 
			
		||||
        mock_find_resource.side_effect = [
 | 
			
		||||
            args[0], self.cluster_member]
 | 
			
		||||
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, args, [])
 | 
			
		||||
        result = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.cluster_client.shrink.assert_called_with('test-clstr',
 | 
			
		||||
                                                      [{'id': 'member-2'}])
 | 
			
		||||
        self.assertIsNone(result)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user