From 597e98fec079c839831036495950f5cba2778d1d Mon Sep 17 00:00:00 2001 From: ricolin Date: Sat, 23 Sep 2017 02:13:40 +0800 Subject: [PATCH] Load files from adopt file when adopt stack Add files from adopt file into create fields. This allow us to adopt nested stack which the template defined in files. Story: #1700744 Task: #17263 Change-Id: I2b473791186949d49be59ee790185b3e394c7000 --- heatclient/osc/v1/stack.py | 7 +++- .../tests/test_templates/adopt_with_file.json | 32 +++++++++++++++ heatclient/tests/unit/osc/v1/test_stack.py | 40 ++++++++++++++++--- heatclient/v1/shell.py | 6 ++- 4 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 heatclient/tests/test_templates/adopt_with_file.json diff --git a/heatclient/osc/v1/stack.py b/heatclient/osc/v1/stack.py index 3817bea0..bdf7f5f0 100644 --- a/heatclient/osc/v1/stack.py +++ b/heatclient/osc/v1/stack.py @@ -22,6 +22,7 @@ from osc_lib import utils from oslo_serialization import jsonutils import six from six.moves.urllib import request +import yaml from heatclient._i18n import _ from heatclient.common import event_utils @@ -822,13 +823,15 @@ class AdoptStack(command.ShowOne): adopt_url = heat_utils.normalise_file_path_to_url( parsed_args.adopt_file) adopt_data = request.urlopen(adopt_url).read().decode('utf-8') - + yaml_adopt_data = yaml.safe_load(adopt_data) or {} + files = yaml_adopt_data.get('files', {}) + files.update(env_files) fields = { 'stack_name': parsed_args.name, 'disable_rollback': not parsed_args.enable_rollback, 'adopt_stack_data': adopt_data, 'parameters': heat_utils.format_parameters(parsed_args.parameter), - 'files': dict(list(env_files.items())), + 'files': files, 'environment': env, 'timeout': parsed_args.timeout } diff --git a/heatclient/tests/test_templates/adopt_with_file.json b/heatclient/tests/test_templates/adopt_with_file.json new file mode 100644 index 00000000..15190432 --- /dev/null +++ b/heatclient/tests/test_templates/adopt_with_file.json @@ -0,0 +1,32 @@ +{ + "files": { + "file://empty.yaml": "{\"heat_template_version\": \"2015-10-15\"}" + }, + "status": "COMPLETE", + "name": "test", + "tags": null, + "stack_user_project_id": "8f51847805ee4994a1ac1d6d1a9bcd9b", + "environment": { + "event_sinks": [], + "parameter_defaults": {}, + "parameters": {}, + "resource_registry": { + "file://empty.yaml": "file://empty.yaml", + "resources": {} + } + }, + "template": { + "heat_template_version": "2015-04-30", + "resources": { + "empty_child": { + "type": "file://empty.yaml" + } + } + }, + "action": "CREATE", + "project_id": "02228cd21ae24ed7966768a9a41be507", + "id": "25b97c3b-2e9a-4222-bc30-da116ae74a08", + "resources": { + "empty_child": {} + } +} diff --git a/heatclient/tests/unit/osc/v1/test_stack.py b/heatclient/tests/unit/osc/v1/test_stack.py index bcc9f69d..146c1bc2 100644 --- a/heatclient/tests/unit/osc/v1/test_stack.py +++ b/heatclient/tests/unit/osc/v1/test_stack.py @@ -730,9 +730,12 @@ class TestStackDelete(TestStack): class TestStackAdopt(TestStack): adopt_file = 'heatclient/tests/test_templates/adopt.json' + adopt_with_files = ('heatclient/tests/test_templates/adopt_with_file.json') with open(adopt_file, 'r') as f: adopt_data = f.read() + with open(adopt_with_files, 'r') as f: + adopt_with_files_data = f.read() defaults = { 'stack_name': 'my_stack', @@ -744,6 +747,18 @@ class TestStackAdopt(TestStack): 'timeout': None } + child_stack_yaml = "{\"heat_template_version\": \"2015-10-15\"}" + + expected_with_files = { + 'stack_name': 'my_stack', + 'disable_rollback': True, + 'adopt_stack_data': adopt_with_files_data, + 'parameters': {}, + 'files': {'file://empty.yaml': child_stack_yaml}, + 'environment': {}, + 'timeout': None + } + def setUp(self): super(TestStackAdopt, self).setUp() self.cmd = stack.AdoptStack(self.app, None) @@ -776,8 +791,8 @@ class TestStackAdopt(TestStack): 'Stack my_stack ADOPT_COMPLETE')) def test_stack_adopt_wait(self, mock_poll): arglist = ['my_stack', '--adopt-file', self.adopt_file, '--wait'] - self.stack_client.get.return_value = \ - stacks.Stack(None, {'stack_status': 'ADOPT_COMPLETE'}) + self.stack_client.get.return_value = stacks.Stack( + None, {'stack_status': 'ADOPT_COMPLETE'}) parsed_args = self.check_parser(self.cmd, arglist, []) self.cmd.take_action(parsed_args) @@ -791,12 +806,25 @@ class TestStackAdopt(TestStack): 'Stack my_stack ADOPT_FAILED')) def test_stack_adopt_wait_fail(self, mock_poll): arglist = ['my_stack', '--adopt-file', self.adopt_file, '--wait'] - self.stack_client.get.return_value = \ - stacks.Stack(None, {'stack_status': 'ADOPT_FAILED'}) + self.stack_client.get.return_value = stacks.Stack( + None, {'stack_status': 'ADOPT_FAILED'}) parsed_args = self.check_parser(self.cmd, arglist, []) self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) + def test_stack_adopt_with_adopt_files(self): + # Make sure when we adopt with files in adopt script, we will load + # those files as part of input when calling adopt. + arglist = ['my_stack', '--adopt-file', self.adopt_with_files] + cols = ['id', 'stack_name', 'description', 'creation_time', + 'updated_time', 'stack_status', 'stack_status_reason'] + parsed_args = self.check_parser(self.cmd, arglist, []) + + columns, data = self.cmd.take_action(parsed_args) + + self.stack_client.create.assert_called_with(**self.expected_with_files) + self.assertEqual(cols, columns) + class TestStackExport(TestStack): @@ -1225,8 +1253,8 @@ class TestStackCancel(_TestStackCheckBase, TestStack): self.mock_client.actions.cancel_update, 'ROLLBACK' ) - self.mock_client.stacks.get.return_value = \ - self.stack_update_in_progress + self.mock_client.stacks.get.return_value = ( + self.stack_update_in_progress) def test_stack_cancel(self): self._test_stack_action(2) diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index e5bf19c9..66d96512 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -185,6 +185,10 @@ def do_stack_adopt(hc, args): adopt_url = utils.normalise_file_path_to_url(args.adopt_file) adopt_data = request.urlopen(adopt_url).read() + yaml_adopt_data = yaml.safe_load(adopt_data) or {} + + files = yaml_adopt_data.get('files', {}) + files.update(env_files) if not len(adopt_data): raise exc.CommandError('Invalid adopt-file, no data!') @@ -201,7 +205,7 @@ def do_stack_adopt(hc, args): 'disable_rollback': not(args.enable_rollback), 'adopt_stack_data': adopt_data, 'parameters': utils.format_parameters(args.parameters), - 'files': dict(list(env_files.items())), + 'files': files, 'environment': env }