From f55ad2c80cc8a193f9c9fc36f3c6085576c708a2 Mon Sep 17 00:00:00 2001 From: Jiri Stransky Date: Tue, 20 Feb 2018 18:14:07 +0100 Subject: [PATCH] Persist user-files/* for 'overcloud update' command Reuse the generic file persistence logic to persist also any files under "user-files/" path in the plan. These are files that can be potentially referenced from other files in the plan (e.g. user-environment.yaml) and if they aren't persisted, the plan could get into inconsistent state (broken references). Change-Id: I54d10b11e024a481a9ff905a7cce79cb7f562ea0 Closes-Bug: #1749700 --- .../tests/workflows/test_plan_management.py | 7 ++++ tripleoclient/workflows/plan_management.py | 38 +++++++++++++------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/tripleoclient/tests/workflows/test_plan_management.py b/tripleoclient/tests/workflows/test_plan_management.py index 84bcab837..f73ec646d 100644 --- a/tripleoclient/tests/workflows/test_plan_management.py +++ b/tripleoclient/tests/workflows/test_plan_management.py @@ -239,6 +239,9 @@ class TestPlanUpdateWorkflows(base.TestCommand): {'name': 'user-environment.yaml'}, {'name': 'roles_data.yaml'}, {'name': 'network_data.yaml'}, + {'name': 'user-files/somecustomfile.yaml'}, + {'name': 'user-files/othercustomfile.yaml'}, + {'name': 'this-should-not-be-persisted.yaml'}, ] ) @@ -281,6 +284,10 @@ class TestPlanUpdateWorkflows(base.TestCommand): 'roles_data.yaml: mock content\n'), mock.call('test-overcloud', 'network_data.yaml', 'network_data.yaml: mock content\n'), + mock.call('test-overcloud', 'user-files/somecustomfile.yaml', + 'user-files/somecustomfile.yaml: mock content\n'), + mock.call('test-overcloud', 'user-files/othercustomfile.yaml', + 'user-files/othercustomfile.yaml: mock content\n'), ], any_order=True, ) diff --git a/tripleoclient/workflows/plan_management.py b/tripleoclient/workflows/plan_management.py index c0c96f5fa..c1ed52c70 100644 --- a/tripleoclient/workflows/plan_management.py +++ b/tripleoclient/workflows/plan_management.py @@ -151,16 +151,21 @@ def update_plan_from_templates(clients, name, tht_root, roles_file=None, keep_file_contents = {} if keep_env: + # Dict items are (remote_name, local_name). local_name may be + # None in which case we only try to load from Swift (remote). + keep_map = { + constants.PLAN_ENVIRONMENT: plan_env_file, + constants.USER_ENVIRONMENT: None, + constants.OVERCLOUD_ROLES_FILE: roles_file, + constants.OVERCLOUD_NETWORKS_FILE: networks_file, + } + # Also try to fetch any files under 'user-files/' + # dir. local_name is always None for these + keep_map.update(dict(map( + lambda path: (path, None), + _list_user_files(swift_client, name)))) keep_file_contents = _load_content_or_file( - swift_client, - name, - { - constants.PLAN_ENVIRONMENT: plan_env_file, - constants.USER_ENVIRONMENT: None, - constants.OVERCLOUD_ROLES_FILE: roles_file, - constants.OVERCLOUD_NETWORKS_FILE: networks_file, - } - ) + swift_client, name, keep_map) elif not plan_env_file: passwords = _load_passwords(swift_client, name) @@ -200,9 +205,7 @@ def _load_content_or_file(swift_client, container, remote_and_local_map): # mapping (remote_name, content) file_contents = {} - plan_files = list(map(lambda i: i['name'], - swift_client.get_container( - container, full_listing=True)[1])) + plan_files = _list_plan_files(swift_client, container) for remote_name in remote_and_local_map: LOG.debug("Attempting to load {0}".format(remote_name)) @@ -225,6 +228,17 @@ def _load_content_or_file(swift_client, container, remote_and_local_map): return file_contents +def _list_user_files(swift_client, container): + return list(filter(lambda path: path.startswith('user-files/'), + _list_plan_files(swift_client, container))) + + +def _list_plan_files(swift_client, container): + return list(map(lambda i: i['name'], + swift_client.get_container( + container, full_listing=True)[1])) + + def _upload_file(swift_client, container, filename, local_filename): with open(local_filename) as file_content: swift_client.put_object(container, filename, file_content)