Support openstack stack export
Heat supports exporting data of stack preparing
for abandon stack. This change supports
'openstack stack export' in client.
MODIFY
heatclient/osc/v1/stack.py
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='<stack>',
+ help=_('Name or ID of stack to export')
+ )
+ parser.add_argument(
+ '--output-file',
+ metavar='<output-file>',
+ 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."""

MODIFY
heatclient/tests/unit/osc/v1/test_stack.py
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']

MODIFY
heatclient/v1/stacks.py
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)

MODIFY
setup.cfg
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

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