From a57b709395bfc1373a25b9d68cec084bc2f83958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Jens=C3=A5s?= Date: Tue, 12 Sep 2023 00:05:33 +0200 Subject: [PATCH] [train-only] Validate rendered net_config_override In change I127c2742522e695dd1fd15413a47bf4d8ebea8fa the _validate_no_ip_change validation was updated to check for ip address change in net_config_override template - when a template using mapping keys like {{PUBLIC_INTERFACE_IP}} the validation will fail since netaddr cannot parse that as an IP address. As was done for OSP17, pass in the rendered network_config_json to the preflight check and validate against this when checking for a changed IP address. Also whe net_config_override allow a match with CONF.undercloud_public_host to pass validation since doc's and example net_config_override uses {{PUBLIC_INTERFACE_IP}} not {{LOCAL_IP}}. Change-Id: Ia01cfc6957536939232085dd6973ab0b105fe78a --- tripleoclient/v1/undercloud_config.py | 4 +- tripleoclient/v1/undercloud_preflight.py | 59 ++++++++++++++++-------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/tripleoclient/v1/undercloud_config.py b/tripleoclient/v1/undercloud_config.py index 785ff1d1c..4ba86ce7f 100644 --- a/tripleoclient/v1/undercloud_config.py +++ b/tripleoclient/v1/undercloud_config.py @@ -753,6 +753,7 @@ def prepare_undercloud_deploy(upgrade=False, no_validations=True, if CONF.get('cleanup'): deploy_args.append('--cleanup') + net_config_json = None if CONF.get('net_config_override', None): data_file = CONF['net_config_override'] if os.path.abspath(data_file) != data_file: @@ -825,7 +826,8 @@ def prepare_undercloud_deploy(upgrade=False, no_validations=True, if CONF.get('enable_validations') and not no_validations: utils.ansible_symlink() - undercloud_preflight.check(verbose_level, upgrade) + undercloud_preflight.check(verbose_level, upgrade, + net_config_json=net_config_json) deploy_args += ['-e', os.path.join( tht_templates, "environments/tripleo-validations.yaml")] diff --git a/tripleoclient/v1/undercloud_preflight.py b/tripleoclient/v1/undercloud_preflight.py index b20fb03a4..07c714265 100644 --- a/tripleoclient/v1/undercloud_preflight.py +++ b/tripleoclient/v1/undercloud_preflight.py @@ -287,7 +287,7 @@ def _validate_interface_exists(config_var='local_interface'): raise FailedValidation(message) -def _validate_no_ip_change(): +def _validate_no_ip_change(net_config_json=None): """Disallow provisioning interface IP changes Changing the provisioning network IP causes a number of issues, so we @@ -295,34 +295,53 @@ def _validate_no_ip_change(): be changed. """ if CONF.net_config_override: - os_net_config_file = CONF.net_config_override + network_config = net_config_json else: - os_net_config_file = '/etc/os-net-config/config.json' - # Nothing to do if we haven't already installed - if not os.path.isfile( - os.path.expanduser(os_net_config_file)): - return - try: + os_net_config_file = '/etc/os-net-config/config.yaml' + + if not os.path.isfile(os.path.expanduser(os_net_config_file)): + os_net_config_file = '/etc/os-net-config/config.json' + + # Nothing to do if we haven't already installed + if not os.path.isfile(os.path.expanduser(os_net_config_file)): + return + with open(os_net_config_file, 'r') as f: network_config = yaml.safe_load(f) - ctlplane = [i for i in network_config.get('network_config', []) - if i['name'] == 'br-ctlplane'][0] - except ValueError: + + if network_config is None: # File was empty return + + try: + ctlplane = [i for i in network_config.get('network_config', []) + if i.get('name') == 'br-ctlplane'][0] except IndexError: # Nothing to check if br-ctlplane wasn't configured return + existing_ip = ctlplane['addresses'][0]['ip_netmask'] conf_netaddr = netaddr.IPNetwork(CONF.local_ip) + conf_public_netaddr = netaddr.IPNetwork(CONF.undercloud_public_host) existing_netaddr = netaddr.IPNetwork(existing_ip) - if (conf_netaddr != existing_netaddr - or conf_netaddr.ip != existing_netaddr.ip): - message = _('Changing the local_ip is not allowed. Existing IP: ' - '{0}, Configured IP: {1}').format( - existing_ip, CONF.local_ip) - LOG.error(message) - raise FailedValidation(message) + # NOTE(hjensas): + # {{PUBLIC_INTERFACE_IP}} maps to CONF.undercloud_public_host + # {{LOCAL_IP}} maps to CONF.local_ip + # In several examples and docs {{PUBLIC_INTERFACE_IP}} is + # used in net_config_override templates instead of {{LOCAL_IP}} + # so let's make that OK. + if (CONF.net_config_override + and (conf_public_netaddr == existing_netaddr + and conf_public_netaddr.ip == existing_netaddr.ip)): + return + if (conf_netaddr == existing_netaddr + and conf_netaddr.ip == existing_netaddr.ip): + return + + message = _('Changing the local_ip is not allowed. Existing IP: ' + '{0}, Configured IP: {1}').format(existing_ip, CONF.local_ip) + LOG.error(message) + raise FailedValidation(message) def _validate_passwords_file(): @@ -475,7 +494,7 @@ def _check_all_or_no_subnets_use_dns_nameservers(): raise FailedValidation(message) -def check(verbose_level, upgrade=False): +def check(verbose_level, upgrade=False, net_config_json=None): # Fetch configuration and use its log file param to add logging to a file utils.load_config(CONF, constants.UNDERCLOUD_CONF_PATH) utils.configure_logging(LOG, verbose_level, CONF['undercloud_log_file']) @@ -518,7 +537,7 @@ def check(verbose_level, upgrade=False): _checking_status('Network interfaces') _validate_interface_exists() _checking_status('Provisionning IP change') - _validate_no_ip_change() + _validate_no_ip_change(net_config_json=net_config_json) _checking_status('Architecture') _validate_architecure_options() except KeyError as e: