From dedc3ac0af9797f8d7d8897380b0a457a226c00d Mon Sep 17 00:00:00 2001 From: huangtianhua Date: Mon, 13 Feb 2017 18:15:24 +0800 Subject: [PATCH] Support openstack stack export Heat supports exporting data of stack preparing for abandon stack. This change supports 'openstack stack export' in client. Change-Id: I5d3778f307d10174dbb738548282f7495bd9c825 --- heatclient/osc/v1/stack.py | 44 ++++++++++++++++++++++ heatclient/tests/unit/osc/v1/test_stack.py | 36 ++++++++++++++++++ heatclient/v1/stacks.py | 7 ++++ setup.cfg | 1 + 4 files changed, 88 insertions(+) diff --git a/heatclient/osc/v1/stack.py b/heatclient/osc/v1/stack.py index 1c044aed..26da6139 100644 --- a/heatclient/osc/v1/stack.py +++ b/heatclient/osc/v1/stack.py @@ -874,6 +874,50 @@ class AbandonStack(format_utils.JsonFormat): return columns, data +class ExportStack(format_utils.JsonFormat): + """Export stack data json.""" + + log = logging.getLogger(__name__ + '.ExportStack') + + def get_parser(self, prog_name): + parser = super(ExportStack, self).get_parser(prog_name) + parser.add_argument( + 'stack', + metavar='', + help=_('Name or ID of stack to export') + ) + parser.add_argument( + '--output-file', + metavar='', + help=_('File to output export data') + ) + + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)', parsed_args) + + client = self.app.client_manager.orchestration + + try: + data_info = client.stacks.export(stack_id=parsed_args.stack) + except heat_exc.HTTPNotFound: + msg = _('Stack not found: %s') % parsed_args.stack + raise exc.CommandError(msg) + + if parsed_args.output_file is not None: + try: + with open(parsed_args.output_file, 'w') as f: + f.write(jsonutils.dumps(data_info, indent=2)) + return [], None + except IOError as e: + raise exc.CommandError(str(e)) + + data = list(six.itervalues(data_info)) + columns = list(six.iterkeys(data_info)) + return columns, data + + class OutputShowStack(command.ShowOne): """Show stack output.""" diff --git a/heatclient/tests/unit/osc/v1/test_stack.py b/heatclient/tests/unit/osc/v1/test_stack.py index 8239f480..54fe9be5 100644 --- a/heatclient/tests/unit/osc/v1/test_stack.py +++ b/heatclient/tests/unit/osc/v1/test_stack.py @@ -777,6 +777,42 @@ class TestStackAdopt(TestStack): self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) +class TestStackExport(TestStack): + + columns = ['stack_name', 'stack_status', 'id'] + data = ['my_stack', 'ABANDONED', '1234'] + + response = dict(zip(columns, data)) + + def setUp(self): + super(TestStackExport, self).setUp() + self.cmd = stack.ExportStack(self.app, None) + self.stack_client.export.return_value = self.response + + def test_stack_export(self): + arglist = ['my_stack'] + parsed_args = self.check_parser(self.cmd, arglist, []) + + columns, data = self.cmd.take_action(parsed_args) + + for column in self.columns: + self.assertIn(column, columns) + for datum in self.data: + self.assertIn(datum, data) + + @mock.patch('heatclient.osc.v1.stack.open', create=True) + def test_stack_export_output_file(self, mock_open): + arglist = ['my_stack', '--output-file', 'file.json'] + mock_open.return_value = mock.MagicMock(spec=io.IOBase) + parsed_args = self.check_parser(self.cmd, arglist, []) + + columns, data = self.cmd.take_action(parsed_args) + + mock_open.assert_called_once_with('file.json', 'w') + self.assertEqual([], columns) + self.assertIsNone(data) + + class TestStackAbandon(TestStack): columns = ['stack_name', 'stack_status', 'id'] diff --git a/heatclient/v1/stacks.py b/heatclient/v1/stacks.py index 2f02825a..b6e6bf6f 100644 --- a/heatclient/v1/stacks.py +++ b/heatclient/v1/stacks.py @@ -208,6 +208,13 @@ class StackManager(StackChildManager): body = utils.get_response_body(resp) return body + def export(self, stack_id): + """Export data of a stack.""" + stack_identifier = self._resolve_stack_id(stack_id) + resp = self.client.get('/stacks/%s/export' % stack_identifier) + body = utils.get_response_body(resp) + return body + def snapshot(self, stack_id, name=None): """Snapshot a stack.""" stack_identifier = self._resolve_stack_id(stack_id) diff --git a/setup.cfg b/setup.cfg index 4f42c807..3955766b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ openstack.orchestration.v1 = software_deployment_output_show = heatclient.osc.v1.software_deployment:ShowOutputDeployment software_deployment_show = heatclient.osc.v1.software_deployment:ShowDeployment stack_abandon = heatclient.osc.v1.stack:AbandonStack + stack_export = heatclient.osc.v1.stack:ExportStack stack_adopt = heatclient.osc.v1.stack:AdoptStack stack_cancel = heatclient.osc.v1.stack:CancelStack stack_check = heatclient.osc.v1.stack:CheckStack