diff --git a/coriolis/osmorphing/base.py b/coriolis/osmorphing/base.py index b1091c4eb..bed86b5f4 100644 --- a/coriolis/osmorphing/base.py +++ b/coriolis/osmorphing/base.py @@ -127,6 +127,8 @@ class BaseLinuxOSMorphingTools(BaseOSMorphingTools): _packages = {} + latest = False + def __init__(self, conn, os_root_dir, os_root_dev, hypervisor, event_manager, detected_os_info, osmorphing_parameters, operation_timeout=None): @@ -180,6 +182,12 @@ def _version_supported_util(cls, version, minimum, maximum=None): "release: %s", version_float, minimum, version) return False + if cls.latest: + LOG.debug( + "Skipping remaining version checks for latest osmorphing tool " + "class: %s", cls.__name__) + return True + if maximum: if maximum == minimum and version_float == minimum: LOG.debug( diff --git a/coriolis/osmorphing/manager.py b/coriolis/osmorphing/manager.py index 50493b8a1..976d487b2 100644 --- a/coriolis/osmorphing/manager.py +++ b/coriolis/osmorphing/manager.py @@ -85,6 +85,27 @@ def get_osmorphing_tools_class_for_provider( "and 'osmorphing_info' %s: %s", type(provider), os_type, osmorphing_info, available_tools_cls) + module_classes = {} + for toolscls in available_tools_cls: + module_name = toolscls.__module__ + if module_name not in module_classes: + module_classes[module_name] = [] + module_classes[module_name].append(toolscls) + + for module_name, classes in module_classes.items(): + latest_flags = [getattr(cls, 'latest', False) for cls in classes] + latest_count = sum(latest_flags) + + if latest_count > 1: + latest_classes = [ + cls.__name__ for cls in classes if getattr( + cls, 'latest', False)] + raise exception.InvalidOSMorphingTools( + "Provider class '%s' returned multiple 'latest' OSMorphing " + "tools from module '%s': %s. Only one class per module " + "can be marked as 'latest'." % ( + type(provider), module_name, latest_classes)) + osmorphing_base_class = base_osmorphing.BaseOSMorphingTools for toolscls in available_tools_cls: if not issubclass(toolscls, osmorphing_base_class): diff --git a/coriolis/osmorphing/osdetect/centos.py b/coriolis/osmorphing/osdetect/centos.py index 0fe1c5e2d..4da014d30 100644 --- a/coriolis/osmorphing/osdetect/centos.py +++ b/coriolis/osmorphing/osdetect/centos.py @@ -22,10 +22,11 @@ def detect_os(self): release_info = self._read_file( redhat_release_path).decode().splitlines() if release_info: - m = re.match(r"^(.*) release ([0-9](\.[0-9])*)( \(.*\))?.*$", - release_info[0].strip()) + m = re.match( + r"^(.*) release ([0-9]+(?:\.[0-9]+)*)( \(.*\))?.*$", + release_info[0].strip()) if m: - distro, version, _, _ = m.groups() + distro, version, _ = m.groups() if CENTOS_DISTRO_IDENTIFIER not in distro: LOG.debug( "Distro does not appear to be a CentOS: %s", diff --git a/coriolis/osmorphing/redhat.py b/coriolis/osmorphing/redhat.py index 22d7ebfff..2f1eb511c 100644 --- a/coriolis/osmorphing/redhat.py +++ b/coriolis/osmorphing/redhat.py @@ -38,9 +38,28 @@ NM_CONTROLLED=no """ +NMCONNECTION_TEMPLATE = """[connection] +id=%(device_name)s +uuid=%(uuid)s +type=ethernet +interface-name=%(device_name)s + +[ethernet] + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=eui64 +method=auto + +[proxy] +""" + class BaseRedHatMorphingTools(base.BaseLinuxOSMorphingTools): _NETWORK_SCRIPTS_PATH = "etc/sysconfig/network-scripts" + _NMCONNECTION_PATH = "etc/NetworkManager/system-connections" BIOS_GRUB_LOCATION = "/boot/grub2" UEFI_GRUB_LOCATION = "/boot/efi/EFI/redhat" @@ -126,6 +145,29 @@ def _write_nic_configs(self, nics_info): "device_name": dev_name, }) + def _write_nmconnection_configs(self, nics_info): + nmconn_dir = self._NMCONNECTION_PATH + self._exec_cmd_chroot("mkdir -p /%s" % nmconn_dir) + + for idx, _ in enumerate(nics_info): + dev_name = "eth%d" % idx + connection_uuid = str(uuid.uuid4()) + cfg_path = "%s/%s.nmconnection" % (nmconn_dir, dev_name) + + if self._test_path(cfg_path): + self._exec_cmd_chroot( + "cp %s %s.bak" % (cfg_path, cfg_path) + ) + + self._write_file_sudo( + cfg_path, + NMCONNECTION_TEMPLATE % { + "device_name": dev_name, + "uuid": connection_uuid, + }) + + self._exec_cmd_chroot("chmod 600 /%s" % cfg_path) + def _comment_keys_from_ifcfg_files( self, keys, interfaces=None, backup_file_suffix=".bak"): """ Comments the provided list of keys from all 'ifcfg-*' files. @@ -160,10 +202,25 @@ def _comment_keys_from_ifcfg_files( "Commented all %s references from '%s'" % ( keys, fullpath)) + def _get_os_version(self): + try: + version_str = self._detected_os_info.get('release_version', '0') + major_version = int(version_str.split('.')[0]) + return major_version + except (ValueError, AttributeError): + LOG.warning( + "Could not parse OS version from detected_os_info: %s", + self._detected_os_info) + return 0 + def set_net_config(self, nics_info, dhcp): if dhcp: self.disable_predictable_nic_names() - self._write_nic_configs(nics_info) + os_version = self._get_os_version() + if os_version < 9: + self._write_nic_configs(nics_info) + else: + self._write_nmconnection_configs(nics_info) return LOG.info("Setting static IP configuration")