From 3b242e95750d323f5e2d2a439d37ce16c378820e Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 8 Jan 2016 15:52:36 -0500 Subject: [PATCH] Update --template-object to support nested stacks This patch updates heatclient so that it supports creating stacks from an object (Swift container) which contain nested stack relative links to nested stack URLs. The motivation here: We would like to be able to use heatclient to create stacks directly from Swift containers in TripleO. The --template-object support already exists and is great... it just needs to support loading the associated nested stacks as well. Change-Id: I53ac83e9f9985224d19993935467c03611aaef6a Closes-bug: #1532326 --- heatclient/common/template_utils.py | 30 ++++++++++++++------ heatclient/tests/unit/test_template_utils.py | 27 ++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/heatclient/common/template_utils.py b/heatclient/common/template_utils.py index 4fa72d86..2134a761 100644 --- a/heatclient/common/template_utils.py +++ b/heatclient/common/template_utils.py @@ -30,6 +30,7 @@ def get_template_contents(template_file=None, template_url=None, template_object=None, object_request=None, files=None, existing=False): + is_object = False # Transform a bare file path to a file:// URL. if template_file: template_url = utils.normalise_file_path_to_url(template_file) @@ -38,6 +39,7 @@ def get_template_contents(template_file=None, template_url=None, tpl = request.urlopen(template_url).read() elif template_object: + is_object = True template_url = template_object tpl = object_request and object_request('GET', template_object) @@ -66,11 +68,13 @@ def get_template_contents(template_file=None, template_url=None, tmpl_base_url = utils.base_url_for_url(template_url) if files is None: files = {} - resolve_template_get_files(template, files, tmpl_base_url) + resolve_template_get_files(template, files, tmpl_base_url, is_object, + object_request) return files, template -def resolve_template_get_files(template, files, template_base_url): +def resolve_template_get_files(template, files, template_base_url, + is_object=False, object_request=None): def ignore_if(key, value): if key != 'get_file' and key != 'type': @@ -86,7 +90,7 @@ def resolve_template_get_files(template, files, template_base_url): return isinstance(value, (dict, list)) get_file_contents(template, files, template_base_url, - ignore_if, recurse_if) + ignore_if, recurse_if, is_object, object_request) def is_template(file_content): @@ -100,7 +104,8 @@ def is_template(file_content): def get_file_contents(from_data, files, base_url=None, - ignore_if=None, recurse_if=None): + ignore_if=None, recurse_if=None, + is_object=False, object_request=None): if recurse_if and recurse_if(from_data): if isinstance(from_data, dict): @@ -108,7 +113,8 @@ def get_file_contents(from_data, files, base_url=None, else: recurse_data = from_data for value in recurse_data: - get_file_contents(value, files, base_url, ignore_if, recurse_if) + get_file_contents(value, files, base_url, ignore_if, recurse_if, + is_object, object_request) if isinstance(from_data, dict): for key, value in six.iteritems(from_data): @@ -120,10 +126,18 @@ def get_file_contents(from_data, files, base_url=None, str_url = parse.urljoin(base_url, value) if str_url not in files: - file_content = utils.read_url_content(str_url) + if is_object and object_request: + file_content = object_request('GET', str_url) + else: + file_content = utils.read_url_content(str_url) if is_template(file_content): - template = get_template_contents( - template_url=str_url, files=files)[1] + if is_object: + template = get_template_contents( + template_object=str_url, files=files, + object_request=object_request)[1] + else: + template = get_template_contents( + template_url=str_url, files=files)[1] file_content = jsonutils.dumps(template) files[str_url] = file_content # replace the data value with the normalised absolute URL diff --git a/heatclient/tests/unit/test_template_utils.py b/heatclient/tests/unit/test_template_utils.py index 5e32b896..29935480 100644 --- a/heatclient/tests/unit/test_template_utils.py +++ b/heatclient/tests/unit/test_template_utils.py @@ -493,6 +493,33 @@ class TestGetTemplateContents(testtools.TestCase): self.assertEqual({}, files) self.assertTrue(self.object_requested) + def test_get_nested_stack_template_contents_object(self): + tmpl = ('{"heat_template_version": "2016-04-08",' + '"resources": {' + '"FooBar": {' + '"type": "foo/bar.yaml"}}}') + url = 'http://no.where/path/to/a.yaml' + self.m.ReplayAll() + + self.object_requested = False + + def object_request(method, object_url): + self.object_requested = True + self.assertEqual('GET', method) + self.assertTrue(object_url.startswith("http://no.where/path/to/")) + if object_url == url: + return tmpl + else: + return '{"heat_template_version": "2016-04-08"}' + + files, tmpl_parsed = template_utils.get_template_contents( + template_object=url, + object_request=object_request) + + self.assertEqual(files['http://no.where/path/to/foo/bar.yaml'], + '{"heat_template_version": "2016-04-08"}') + self.assertTrue(self.object_requested) + def check_non_utf8_content(self, filename, content): base_url = 'file:///tmp' url = '%s/%s' % (base_url, filename)