diff --git a/senlinclient/common/utils.py b/senlinclient/common/utils.py index 19e68439..2e003c61 100644 --- a/senlinclient/common/utils.py +++ b/senlinclient/common/utils.py @@ -187,6 +187,14 @@ def print_dict(d, formatters=None): print(encodeutils.safe_encode(content)) +def print_action_result(rid, res): + if res[0] == "OK": + output = _("accepted by action %s") % res[1] + else: + output = _("failed due to '%s'") % res[1] + print(_(" %(cid)s: %(output)s") % {"cid": rid, "output": output}) + + def format_parameters(params, parse_semicolon=True): """Reformat parameters into dict of format expected by the API.""" if not params: diff --git a/senlinclient/tests/unit/v1/test_cluster.py b/senlinclient/tests/unit/v1/test_cluster.py index 49c9ec93..b3ff6c63 100644 --- a/senlinclient/tests/unit/v1/test_cluster.py +++ b/senlinclient/tests/unit/v1/test_cluster.py @@ -330,7 +330,8 @@ class TestClusterDelete(TestCluster): def setUp(self): super(TestClusterDelete, self).setUp() self.cmd = osc_cluster.DeleteCluster(self.app, None) - self.mock_client.delete_cluster = mock.Mock() + mock_cluster = mock.Mock(location='abc/fake_action_id') + self.mock_client.delete_cluster = mock.Mock(return_value=mock_cluster) def test_cluster_delete(self): arglist = ['cluster1', 'cluster2', 'cluster3'] @@ -354,10 +355,12 @@ class TestClusterDelete(TestCluster): arglist = ['my_cluster'] self.mock_client.delete_cluster.side_effect = sdk_exc.ResourceNotFound parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Failed to delete 1 of the 1 specified cluster(s).', - str(error)) + + self.cmd.take_action(parsed_args) + + self.mock_client.delete_cluster.assert_has_calls( + [mock.call('my_cluster', False)] + ) def test_cluster_delete_one_found_one_not_found(self): arglist = ['cluster1', 'cluster2'] @@ -365,13 +368,12 @@ class TestClusterDelete(TestCluster): [None, sdk_exc.ResourceNotFound] ) parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, parsed_args) + + self.cmd.take_action(parsed_args) + self.mock_client.delete_cluster.assert_has_calls( [mock.call('cluster1', False), mock.call('cluster2', False)] ) - self.assertEqual('Failed to delete 1 of the 2 specified cluster(s).', - str(error)) @mock.patch('sys.stdin', spec=six.StringIO) def test_cluster_delete_prompt_yes(self, mock_stdin): diff --git a/senlinclient/tests/unit/v1/test_node.py b/senlinclient/tests/unit/v1/test_node.py index caef4374..516ee635 100644 --- a/senlinclient/tests/unit/v1/test_node.py +++ b/senlinclient/tests/unit/v1/test_node.py @@ -335,7 +335,8 @@ class TestNodeDelete(TestNode): def setUp(self): super(TestNodeDelete, self).setUp() self.cmd = osc_node.DeleteNode(self.app, None) - self.mock_client.delete_node = mock.Mock() + mock_node = mock.Mock(location='loc/fake_action_id') + self.mock_client.delete_node = mock.Mock(return_value=mock_node) def test_node_delete(self): arglist = ['node1', 'node2', 'node3'] @@ -359,10 +360,12 @@ class TestNodeDelete(TestNode): arglist = ['my_node'] self.mock_client.delete_node.side_effect = sdk_exc.ResourceNotFound parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Failed to delete 1 of the 1 specified node(s).', - str(error)) + + self.cmd.take_action(parsed_args) + + self.mock_client.delete_node.assert_has_calls( + [mock.call('my_node', False)] + ) def test_node_delete_one_found_one_not_found(self): arglist = ['node1', 'node2'] @@ -370,13 +373,12 @@ class TestNodeDelete(TestNode): [None, sdk_exc.ResourceNotFound] ) parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, parsed_args) + + self.cmd.take_action(parsed_args) + self.mock_client.delete_node.assert_has_calls( [mock.call('node1', False), mock.call('node2', False)] ) - self.assertEqual('Failed to delete 1 of the 2 specified node(s).', - str(error)) @mock.patch('sys.stdin', spec=six.StringIO) def test_node_delete_prompt_yes(self, mock_stdin): diff --git a/senlinclient/tests/unit/v1/test_shell.py b/senlinclient/tests/unit/v1/test_shell.py index 874eec4e..c7a520bd 100644 --- a/senlinclient/tests/unit/v1/test_shell.py +++ b/senlinclient/tests/unit/v1/test_shell.py @@ -780,17 +780,6 @@ class ShellTest(testtools.TestCase): sh.do_cluster_delete(service, args) service.delete_cluster.assert_called_once_with('CID', False) - def test_do_cluster_delete_not_found(self): - service = mock.Mock() - args = {'id': ['cluster_id']} - args = self._make_args(args) - - service.delete_cluster.side_effect = oexc.ResourceNotFound - ex = self.assertRaises(exc.CommandError, - sh.do_cluster_delete, service, args) - msg = _('Failed to delete some of the specified clusters.') - self.assertEqual(msg, six.text_type(ex)) - @mock.patch('subprocess.Popen') def test__run_script(self, mock_proc): x_proc = mock.Mock(returncode=0) @@ -1485,17 +1474,6 @@ class ShellTest(testtools.TestCase): service.delete_node.assert_called_once_with('node1', False) - def test_do_node_delete_not_found(self): - service = mock.Mock() - ex = oexc.ResourceNotFound - service.delete_node.side_effect = ex - - args = self._make_args({'id': ['node1']}) - ex = self.assertRaises(exc.CommandError, - sh.do_node_delete, service, args) - msg = _('Failed to delete some of the specified nodes.') - self.assertEqual(msg, six.text_type(ex)) - def test_do_node_check(self): service = mock.Mock() args = self._make_args({'id': ['node1']}) diff --git a/senlinclient/v1/cluster.py b/senlinclient/v1/cluster.py index b100152b..7724588a 100644 --- a/senlinclient/v1/cluster.py +++ b/senlinclient/v1/cluster.py @@ -311,20 +311,16 @@ class DeleteCluster(command.Command): self.log.info(_LI('Ctrl-d detected')) return - failure_count = 0 - + result = {} for cid in parsed_args.cluster: try: - senlin_client.delete_cluster(cid, False) + cluster = senlin_client.delete_cluster(cid, False) + result[cid] = ('OK', cluster.location.split('/')[-1]) except Exception as ex: - failure_count += 1 - print(ex) - if failure_count: - raise exc.CommandError(_('Failed to delete %(count)s of the ' - '%(total)s specified cluster(s).') % - {'count': failure_count, - 'total': len(parsed_args.cluster)}) - print('Request accepted') + result[cid] = ('ERROR', six.text_type(ex)) + + for rid, res in result.items(): + senlin_utils.print_action_result(rid, res) class ResizeCluster(command.Command): diff --git a/senlinclient/v1/node.py b/senlinclient/v1/node.py index 3fd96c66..367b4eb4 100644 --- a/senlinclient/v1/node.py +++ b/senlinclient/v1/node.py @@ -19,6 +19,7 @@ from openstack import exceptions as sdk_exc from osc_lib.command import command from osc_lib import exceptions as exc from osc_lib import utils +import six from senlinclient.common.i18n import _ from senlinclient.common.i18n import _LI @@ -314,20 +315,16 @@ class DeleteNode(command.Command): self.log.info(_LI('Ctrl-d detected')) return - failure_count = 0 - + result = {} for nid in parsed_args.node: try: - senlin_client.delete_node(nid, False) + node = senlin_client.delete_node(nid, False) + result[nid] = ('OK', node.location.split('/')[-1]) except Exception as ex: - failure_count += 1 - print(ex) - if failure_count: - raise exc.CommandError(_('Failed to delete %(count)s of the ' - '%(total)s specified node(s).') % - {'count': failure_count, - 'total': len(parsed_args.node)}) - print('Request accepted') + result[nid] = ('ERROR', six.text_type(ex)) + + for rid, res in result.items(): + senlin_utils.print_action_result(rid, res) class CheckNode(command.Command): diff --git a/senlinclient/v1/shell.py b/senlinclient/v1/shell.py index e9b5865e..887bf6eb 100644 --- a/senlinclient/v1/shell.py +++ b/senlinclient/v1/shell.py @@ -582,18 +582,17 @@ def do_cluster_collect(service, args): def do_cluster_delete(service, args): """Delete the cluster(s).""" show_deprecated('senlin cluster-delete', 'openstack cluster delete') - failure_count = 0 + result = {} for cid in args.id: try: - service.delete_cluster(cid, False) + cluster = service.delete_cluster(cid, False) + result[cid] = ('OK', cluster.location.split('/')[-1]) except Exception as ex: - failure_count += 1 - print(ex) - if failure_count > 0: - msg = _('Failed to delete some of the specified clusters.') - raise exc.CommandError(msg) - print('Request accepted') + result[cid] = ('ERROR', six.text_type(ex)) + + for rid, res in result.items(): + utils.print_action_result(rid, res) def _run_script(node_id, addr, net, addr_type, port, user, ipv6, identity_file, @@ -1208,18 +1207,17 @@ def do_node_show(service, args): def do_node_delete(service, args): """Delete the node(s).""" show_deprecated('senlin node-delete', 'openstack cluster node delete') - failure_count = 0 + result = {} for nid in args.id: try: - service.delete_node(nid, False) + node = service.delete_node(nid, False) + result[nid] = ('OK', node.location.split('/')[-1]) except Exception as ex: - failure_count += 1 - print(ex) - if failure_count > 0: - msg = _('Failed to delete some of the specified nodes.') - raise exc.CommandError(msg) - print('Request accepted') + result[nid] = ('ERROR', six.text_type(ex)) + + for rid, res in result.items(): + utils.print_action_result(rid, res) @utils.arg('-n', '--name', metavar='',