From cfdf62a47031d6ad3a8bc88ea3c25c08e04865c8 Mon Sep 17 00:00:00 2001 From: tengqm Date: Fri, 30 Jun 2017 01:33:12 -0400 Subject: [PATCH] OSC command for node op and cluster op This patch adds OSC support to cluster op and cluster node op. Change-Id: I93ff66e3a4f29041196b8d1814b5e2cee833cb08 --- senlinclient/tests/unit/v1/test_cluster.py | 30 +++++++++++++++ senlinclient/tests/unit/v1/test_node.py | 30 +++++++++++++++ senlinclient/v1/cluster.py | 44 ++++++++++++++++++++++ senlinclient/v1/node.py | 44 ++++++++++++++++++++++ setup.cfg | 2 + 5 files changed, 150 insertions(+) diff --git a/senlinclient/tests/unit/v1/test_cluster.py b/senlinclient/tests/unit/v1/test_cluster.py index 6906234d..25d48649 100644 --- a/senlinclient/tests/unit/v1/test_cluster.py +++ b/senlinclient/tests/unit/v1/test_cluster.py @@ -810,6 +810,36 @@ class TestClusterRecover(TestCluster): self.assertIn('Cluster not found: cluster1', str(error)) +class TestClusterOp(TestCluster): + + response = {"action": "a3c6d04c-3fca-4e4a-b0b3-c0522ef711f1"} + + def setUp(self): + super(TestClusterOp, self).setUp() + self.cmd = osc_cluster.ClusterOp(self.app, None) + self.mock_client.perform_operation_on_cluster = mock.Mock( + return_value=self.response) + + def test_cluster_op(self): + arglist = ['--operation', 'dance', '--params', 'style=tango', + 'my_cluster'] + parsed_args = self.check_parser(self.cmd, arglist, []) + self.cmd.take_action(parsed_args) + self.mock_client.perform_operation_on_cluster.assert_called_once_with( + 'my_cluster', + 'dance', + style='tango') + + def test_cluster_op_not_found(self): + arglist = ['--operation', 'dance', 'cluster1'] + ex = sdk_exc.ResourceNotFound + self.mock_client.perform_operation_on_cluster.side_effect = ex + parsed_args = self.check_parser(self.cmd, arglist, []) + error = self.assertRaises(exc.CommandError, self.cmd.take_action, + parsed_args) + self.assertIn('Cluster not found: cluster1', str(error)) + + class TestClusterCollect(TestCluster): response = [ { diff --git a/senlinclient/tests/unit/v1/test_node.py b/senlinclient/tests/unit/v1/test_node.py index a07a984d..24335cc0 100644 --- a/senlinclient/tests/unit/v1/test_node.py +++ b/senlinclient/tests/unit/v1/test_node.py @@ -456,3 +456,33 @@ class TestNodeRecover(TestNode): error = self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) self.assertIn('Node not found: node1', str(error)) + + +class TestNodeOp(TestNode): + + response = {"action": "1db0f5c5-9183-4c47-9ef1-a5a97402a2c1"} + + def setUp(self): + super(TestNodeOp, self).setUp() + self.cmd = osc_node.NodeOp(self.app, None) + self.mock_client.perform_operation_on_node = mock.Mock( + return_value=self.response) + + def test_node_op(self): + arglist = ['--operation', 'dance', '--params', 'style=tango', + 'my_node'] + parsed_args = self.check_parser(self.cmd, arglist, []) + self.cmd.take_action(parsed_args) + self.mock_client.perform_operation_on_node.assert_called_once_with( + 'my_node', + 'dance', + style='tango') + + def test_node_op_not_found(self): + arglist = ['--operation', 'dance', 'node1'] + ex = sdk_exc.ResourceNotFound + self.mock_client.perform_operation_on_node.side_effect = ex + parsed_args = self.check_parser(self.cmd, arglist, []) + error = self.assertRaises(exc.CommandError, self.cmd.take_action, + parsed_args) + self.assertIn('Node not found: node1', str(error)) diff --git a/senlinclient/v1/cluster.py b/senlinclient/v1/cluster.py index 2ba97645..5b81e65e 100644 --- a/senlinclient/v1/cluster.py +++ b/senlinclient/v1/cluster.py @@ -919,6 +919,50 @@ class ClusterCollect(command.Lister): for a in attrs)) +class ClusterOp(command.Lister): + """Perform an operation on all nodes across a cluster.""" + log = logging.getLogger(__name__ + ".ClusterOp") + + def get_parser(self, prog_name): + parser = super(ClusterOp, self).get_parser(prog_name) + parser.add_argument( + '--operation', + metavar='', + required=True, + help=_('Operation to be performed on the cluster') + ) + parser.add_argument( + '--params', + metavar='', + help=_("Parameters to for the specified operation. " + "This can be specified multiple times, or once with " + "parameters separated by a semicolon."), + action='append' + ) + parser.add_argument( + 'cluster', + metavar='', + help=_('ID or name of cluster to operate on.') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + senlin_client = self.app.client_manager.clustering + cid = parsed_args.cluster + if parsed_args.params: + params = senlin_utils.format_parameters(parsed_args.params) + else: + params = {} + + try: + resp = senlin_client.perform_operation_on_cluster( + cid, parsed_args.operation, **params) + print('Request accepted by action: %s' % resp['action']) + except sdk_exc.ResourceNotFound: + raise exc.CommandError(_('Cluster not found: %s') % cid) + + class ClusterRun(command.Command): """Run scripts on cluster.""" log = logging.getLogger(__name__ + ".ClusterRun") diff --git a/senlinclient/v1/node.py b/senlinclient/v1/node.py index 9777d3a0..6c3eb235 100644 --- a/senlinclient/v1/node.py +++ b/senlinclient/v1/node.py @@ -396,3 +396,47 @@ class RecoverNode(command.Command): print('Node recover request on node %(nid)s is accepted by ' 'action %(action)s.' % {'nid': nid, 'action': resp['action']}) + + +class NodeOp(command.Lister): + """Perform an operation on a node.""" + log = logging.getLogger(__name__ + ".NodeOp") + + def get_parser(self, prog_name): + parser = super(NodeOp, self).get_parser(prog_name) + parser.add_argument( + '--operation', + metavar='', + required=True, + help=_('Operation to be performed on the node.') + ) + parser.add_argument( + '--params', + metavar='', + help=_("Parameters to for the specified operation. " + "This can be specified multiple times, or once with " + "parameters separated by a semicolon."), + action="append" + ) + parser.add_argument( + 'node', + metavar='', + help=_('ID or name the node operate on.') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + senlin_client = self.app.client_manager.clustering + nid = parsed_args.node + if parsed_args.params: + params = senlin_utils.format_parameters(parsed_args.params) + else: + params = {} + + try: + resp = senlin_client.perform_operation_on_node( + nid, parsed_args.operation, **params) + print('Request accepted by action: %s' % resp['action']) + except sdk_exc.ResourceNotFound: + raise exc.CommandError(_('Node not found: %s') % nid) diff --git a/setup.cfg b/setup.cfg index 24e19c80..c1e23ffe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ openstack.clustering.v1 = cluster_node_recover = senlinclient.v1.node:RecoverNode cluster_node_show = senlinclient.v1.node:ShowNode cluster_node_update = senlinclient.v1.node:UpdateNode + cluster_node_op = senlinclient.v1.node:NodeOp cluster_policy_attach = senlinclient.v1.cluster:ClusterPolicyAttach cluster_policy_binding_list = senlinclient.v1.cluster_policy:ClusterPolicyList cluster_policy_binding_show = senlinclient.v1.cluster_policy:ClusterPolicyShow @@ -85,6 +86,7 @@ openstack.clustering.v1 = cluster_collect = senlinclient.v1.cluster:ClusterCollect cluster_run = senlinclient.v1.cluster:ClusterRun cluster_service_list = senlinclient.v1.service:ListService + cluster_op = senlinclient.v1.cluster:ClusterOp [global] setup-hooks =