diff --git a/tripleoclient/constants.py b/tripleoclient/constants.py index f939650cc..3e98a16e3 100644 --- a/tripleoclient/constants.py +++ b/tripleoclient/constants.py @@ -78,6 +78,14 @@ UPDATE_PREPARE_ENV = "environments/lifecycle/update-prepare.yaml" UPDATE_CONVERGE_ENV = "environments/lifecycle/update-converge.yaml" UPGRADE_PREPARE_ENV = "environments/lifecycle/upgrade-prepare.yaml" UPGRADE_CONVERGE_ENV = "environments/lifecycle/upgrade-converge.yaml" +UPGRADE_CONVERGE_FORBIDDEN_PARAMS = ["ceph3_namespace", + "ceph3_tag", + "ceph3_image", + "name_prefix_stein", + "name_suffix_stein", + "namespace_stein", + "tag_stein", + ] FFWD_UPGRADE_PREPARE_ENV = "environments/lifecycle/ffwd-upgrade-prepare.yaml" FFWD_UPGRADE_CONVERGE_ENV = "environments/lifecycle/ffwd-upgrade-converge.yaml" FFWD_UPGRADE_PREPARE_SCRIPT = ("#!/bin/bash \n" diff --git a/tripleoclient/exceptions.py b/tripleoclient/exceptions.py index b738b462d..8f94dcb7d 100644 --- a/tripleoclient/exceptions.py +++ b/tripleoclient/exceptions.py @@ -135,3 +135,7 @@ class UndercloudUpgradeNotConfirmed(Base): class CellExportError(Base): """Cell export failed""" + + +class BannedParameters(Base): + """Some of the environment parameters provided should be removed""" diff --git a/tripleoclient/v1/overcloud_upgrade.py b/tripleoclient/v1/overcloud_upgrade.py index 02b655251..13eede967 100644 --- a/tripleoclient/v1/overcloud_upgrade.py +++ b/tripleoclient/v1/overcloud_upgrade.py @@ -25,6 +25,7 @@ from tripleoclient import utils as oooutils from tripleoclient.v1.overcloud_deploy import DeployOvercloud from tripleoclient.workflows import deployment from tripleoclient.workflows import package_update +from tripleoclient.workflows import parameters CONF = cfg.CONF logging.register_options(CONF) @@ -43,6 +44,8 @@ class UpgradePrepare(DeployOvercloud): template = constants.UPGRADE_PREPARE_ENV + forbidden_params = [] + log = logging.getLogger(__name__ + ".UpgradePrepare") def get_parser(self, prog_name): @@ -75,6 +78,11 @@ class UpgradePrepare(DeployOvercloud): parsed_args.environment_files = oooutils.prepend_environment( parsed_args.environment_files, templates_dir, self.template) + # Parse all environment files looking for undesired + # parameters + parameters.check_forbidden_params(self.log, + parsed_args.environment_files, + self.forbidden_params) super(UpgradePrepare, self).take_action(parsed_args) # Download stack_name-config as this is skiped in @@ -256,4 +264,6 @@ class UpgradeConvergeOvercloud(UpgradePrepare): template = constants.UPGRADE_CONVERGE_ENV + forbidden_params = constants.UPGRADE_CONVERGE_FORBIDDEN_PARAMS + log = logging.getLogger(__name__ + ".UpgradeConvergeOvercloud") diff --git a/tripleoclient/workflows/parameters.py b/tripleoclient/workflows/parameters.py index ea905737d..cc08ea7d1 100644 --- a/tripleoclient/workflows/parameters.py +++ b/tripleoclient/workflows/parameters.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. import logging +import os import re import yaml @@ -156,3 +157,84 @@ def generate_fencing_parameters(clients, **workflow_input): if ('fencing_parameters' in payload and (payload.get('status', 'FAILED') == "SUCCESS")): return payload['fencing_parameters'] + + +def check_forbidden_params(log, env_files, forbidden): + """Looks for undesired parameters in the environment files. + + Each of the environment files pass in env_files will be parsed + and if the parameters_default key is found, then all the keys + from the nested dictionary found under will be converted into + a list, for example: + + parameters_default: + key1: value1 + key2: value2 + key3: + - value3 + - key31: + key311: value311 + key312: value312 + key32: value32 + + Will be converted by get_all_keys into: + [key1, key2, key3, key31, key311, key312, key32] + + This list provides us with all the parameters used in the environment + file, without the values, in the format of a list. So we can use sets + to find occurrences of the forbbiden paramenters. + + The variable matched_params will get all the ocurrences of forbidden + parameters stored, so we can parse all the environment files and show + all the parameters which should get removed from the environment files + at once (saving the user to run the command, modify a template, run it + again, modify another, etc...). If matched_params list is not empty, + an exception will be raised, stopping the execution of the command and + displaying the commands which need to be removed. + + :param log: logging object passed from the calling method + :type log: Logging object + :param env_files: list of the environment files passed in the command + :type env_files: list of strings + :param forbidden: list of the undesired parameters + :type forbidden: list of strings + + :returns exception if some of the forbidden parameters are found in + the environment files. + """ + + # Iterates over a nested dict and returns all the + # keys from the dict in a list + # example: + # * input: {'a': '1', 'b': ['c': '2', 'd': {'e': '3'}]} + # * output: ['a', 'b', 'c', 'd', 'e'] + def get_all_keys(obj, keys_list): + if isinstance(obj, dict): + keys_list += obj.keys() + for value in obj.values(): + get_all_keys(value, keys_list) + elif isinstance(obj, list): + for value in obj: + get_all_keys(value, keys_list) + + matched_params = [] + + for file in env_files: + if os.path.exists(file): + with open(file, 'r') as env_file: + contents = yaml.safe_load(env_file) + pd = contents.get('parameter_defaults', {}) + if pd: + # Intersection of values and forbidden params + list_of_keys = [] + get_all_keys(pd, list_of_keys) + found_in_pd = list(set(list_of_keys) & set(forbidden)) + + # Combine them without duplicates + matched_params = list(set(matched_params + found_in_pd)) + + if matched_params: + raise exceptions.BannedParameters("The following parameters should be " + "removed from the environment files:" + "\n{}\n" + .format('\n'.join(matched_params)))