diff options
| author | Jenkins <jenkins@review.openstack.org> | 2016-02-26 05:43:15 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2016-02-26 05:43:15 +0000 |
| commit | fdc1ee7deeff894fc37ceb5cf6791910af3ed3af (patch) | |
| tree | ab2e3bf34171a68330d7ba135b4b4d9c072a0f55 | |
| parent | 9336c5bc87681639b99e369cedcd6a64e794b55c (diff) | |
| parent | 7627e1bae53747e1471caf632dfc1b6edf2e26cf (diff) | |
| download | python-heatclient-fdc1ee7deeff894fc37ceb5cf6791910af3ed3af.tar.gz | |
Merge "Changes to support server-side environment resolution"
| -rw-r--r-- | heatclient/common/template_utils.py | 85 | ||||
| -rw-r--r-- | heatclient/tests/unit/test_template_utils.py | 36 | ||||
| -rw-r--r-- | heatclient/v1/shell.py | 30 |
3 files changed, 137 insertions, 14 deletions
diff --git a/heatclient/common/template_utils.py b/heatclient/common/template_utils.py index b80878d..fae54ef 100644 --- a/heatclient/common/template_utils.py +++ b/heatclient/common/template_utils.py @@ -189,17 +189,51 @@ def deep_update(old, new): def process_multiple_environments_and_files(env_paths=None, template=None, template_url=None, env_path_is_object=None, - object_request=None): - + object_request=None, + env_list_tracker=None): + """Reads one or more environment files. + + Reads in each specified environment file and returns a dictionary + of the filenames->contents (suitable for the files dict) + and the consolidated environment (after having applied the correct + overrides based on order). + + If a list is provided in the env_list_tracker parameter, the behavior + is altered to take advantage of server-side environment resolution. + Specifically, this means: + + * Populating env_list_tracker with an ordered list of environment file + URLs to be passed to the server + * Including the contents of each environment file in the returned + files dict, keyed by one of the URLs in env_list_tracker + + :param env_paths: list of paths to the environment files to load; if + None, empty results will be returned + :type env_paths: list or None + :param template: unused; only included for API compatibility + :param template_url: unused; only included for API compatibility + :param env_list_tracker: if specified, environment filenames will be + stored within + :type env_list_tracker: list or None + :return: tuple of files dict and a dict of the consolidated environment + :rtype: tuple + """ merged_files = {} merged_env = {} + # If we're keeping a list of environment files separately, include the + # contents of the files in the files dict + include_env_in_files = env_list_tracker is not None + if env_paths: for env_path in env_paths: - files, env = process_environment_and_files(env_path, template, - template_url, - env_path_is_object, - object_request) + files, env = process_environment_and_files( + env_path=env_path, + template=template, + template_url=template_url, + env_path_is_object=env_path_is_object, + object_request=object_request, + include_env_in_files=include_env_in_files) # 'files' looks like {"filename1": contents, "filename2": contents} # so a simple update is enough for merging @@ -209,12 +243,32 @@ def process_multiple_environments_and_files(env_paths=None, template=None, # not enough merged_env = deep_update(merged_env, env) + if env_list_tracker is not None: + env_url = utils.normalise_file_path_to_url(env_path) + env_list_tracker.append(env_url) + return merged_files, merged_env -def process_environment_and_files(env_path=None, template=None, - template_url=None, env_path_is_object=None, - object_request=None): +def process_environment_and_files(env_path=None, + template=None, + template_url=None, + env_path_is_object=None, + object_request=None, + include_env_in_files=False): + """Loads a single environment file. + + Returns an entry suitable for the files dict which maps the environment + filename to its contents. + + :param env_path: full path to the file to load + :type env_path: str or None + :param include_env_in_files: if specified, the raw environment file itself + will be included in the returned files dict + :type include_env_in_files: bool + :return: tuple of files dict and the loaded environment as a dict + :rtype: (dict, dict) + """ files = {} env = {} @@ -234,6 +288,10 @@ def process_environment_and_files(env_path=None, template=None, env_url = utils.normalise_file_path_to_url(env_path) env_base_url = utils.base_url_for_url(env_url) raw_env = request.urlopen(env_url).read() + + if include_env_in_files: + files[env_url] = raw_env + env = environment_format.parse(raw_env) resolve_environment_urls( @@ -246,6 +304,15 @@ def process_environment_and_files(env_path=None, template=None, def resolve_environment_urls(resource_registry, files, env_base_url, is_object=False, object_request=None): + """Handles any resource URLs specified in an environment. + + :param resource_registry: mapping of type name to template filename + :type resource_registry: dict + :param files: dict to store loaded file contents into + :type files: dict + :param env_base_url: base URL to look in when loading files + :type env_base_url: str or None + """ if resource_registry is None: return diff --git a/heatclient/tests/unit/test_template_utils.py b/heatclient/tests/unit/test_template_utils.py index c6ffebd..920573d 100644 --- a/heatclient/tests/unit/test_template_utils.py +++ b/heatclient/tests/unit/test_template_utils.py @@ -374,6 +374,42 @@ class ShellEnvironmentTest(testtools.TestCase): self.assertEqual(self.template_a.decode('utf-8'), files['http://no.where/path/to/b/a.yaml']) + def test_process_multiple_environments_and_files_tracker(self): + # Setup + self.m.StubOutWithMock(request, 'urlopen') + env_file1 = '/home/my/dir/env1.yaml' + + env1 = b''' + parameters: + "param1": "value1" + resource_registry: + "OS::Thingy1": "file:///home/b/a.yaml" + ''' + request.urlopen('file://%s' % env_file1).AndReturn( + six.BytesIO(env1)) + request.urlopen('file:///home/b/a.yaml').AndReturn( + six.BytesIO(self.template_a)) + request.urlopen('file:///home/b/a.yaml').AndReturn( + six.BytesIO(self.template_a)) + self.m.ReplayAll() + + # Test + env_file_list = [] + files, env = template_utils.process_multiple_environments_and_files( + [env_file1], env_list_tracker=env_file_list) + + # Verify + expected_env = {'parameters': {'param1': 'value1'}, + 'resource_registry': + {'OS::Thingy1': 'file:///home/b/a.yaml'} + } + self.assertEqual(expected_env, env) + + self.assertEqual(self.template_a.decode('utf-8'), + files['file:///home/b/a.yaml']) + + self.assertEqual(['file:///home/my/dir/env1.yaml'], env_file_list) + def test_global_files(self): url = 'file:///home/b/a.yaml' env = ''' diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index d530958..43395d0 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -103,8 +103,9 @@ def do_stack_create(hc, args): args.template_url, args.template_object, _authenticated_fetcher(hc)) + env_files_list = [] env_files, env = template_utils.process_multiple_environments_and_files( - env_paths=args.environment_file) + env_paths=args.environment_file, env_list_tracker=env_files_list) if args.create_timeout: logger.warning(_LW('%(arg1)s is deprecated, ' @@ -128,6 +129,10 @@ def do_stack_create(hc, args): 'environment': env } + # If one or more environments is found, pass the listing to the server + if env_files_list: + fields['environment_files'] = env_files_list + if args.tags: fields['tags'] = args.tags timeout = args.timeout or args.create_timeout @@ -249,8 +254,9 @@ def do_stack_preview(hc, args): args.template_url, args.template_object, _authenticated_fetcher(hc)) + env_files_list = [] env_files, env = template_utils.process_multiple_environments_and_files( - env_paths=args.environment_file) + env_paths=args.environment_file, env_list_tracker=env_files_list) fields = { 'stack_name': args.name, @@ -265,6 +271,10 @@ def do_stack_preview(hc, args): 'environment': env } + # If one or more environments is found, pass the listing to the server + if env_files_list: + fields['environment_files'] = env_files_list + if args.tags: fields['tags'] = args.tags @@ -461,9 +471,9 @@ def do_stack_update(hc, args): args.template_object, _authenticated_fetcher(hc), existing=args.existing) - + env_files_list = [] env_files, env = template_utils.process_multiple_environments_and_files( - env_paths=args.environment_file) + env_paths=args.environment_file, env_list_tracker=env_files_list) if args.pre_update: template_utils.hooks_to_env(env, args.pre_update, 'pre-update') @@ -480,6 +490,10 @@ def do_stack_update(hc, args): 'environment': env } + # If one or more environments is found, pass the listing to the server + if env_files_list: + fields['environment_files'] = env_files_list + if args.tags: fields['tags'] = args.tags if args.timeout: @@ -831,8 +845,10 @@ def do_template_validate(hc, args): args.template_object, _authenticated_fetcher(hc)) + env_files_list = [] env_files, env = template_utils.process_multiple_environments_and_files( - env_paths=args.environment_file) + env_paths=args.environment_file, env_list_tracker=env_files_list) + fields = { 'template': template, 'parameters': utils.format_parameters(args.parameters), @@ -843,6 +859,10 @@ def do_template_validate(hc, args): if args.ignore_errors: fields['ignore_errors'] = args.ignore_errors + # If one or more environments is found, pass the listing to the server + if env_files_list: + fields['environment_files'] = env_files_list + if args.show_nested: fields['show_nested'] = args.show_nested |
