Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions coriolis/osmorphing/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,39 @@
GRUB2_SERIAL = "serial --word=8 --stop=1 --speed=%d --parity=%s --unit=0"
LOG = logging.getLogger(__name__)

IFCFG_TEMPLATE = """
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=%(device_name)s
DEVICE=%(device_name)s
ONBOOT=yes
NM_CONTROLLED=%(nm_controlled)s
"""

NMCONNECTION_TEMPLATE = """[connection]
id=%(device_name)s
uuid=%(connection_uuid)s
type=ethernet
interface-name=%(device_name)s
autoconnect=true

[ethernet]

[ipv4]
method=auto
may-fail=false

[ipv6]
method=auto
addr-gen-mode=default
"""


# Required OS release fields which are expected from the OSDetect tools.
# 'schemas.CORIOLIS_DETECTED_OS_MORPHING_INFO_SCHEMA' schema:
Expand Down Expand Up @@ -222,6 +255,12 @@ class BaseLinuxOSMorphingTools(BaseOSMorphingTools):
_packages = {}
_NETWORK_SCRIPTS_PATH = "etc/sysconfig/network-scripts"
_NM_CONNECTIONS_PATH = "etc/NetworkManager/system-connections"
# ifcfg profile template written for DHCP NICs. Subclasses may override it
# when the target uses a different ifcfg format (e.g. wicked-based SUSE).
_IFCFG_TEMPLATE = IFCFG_TEMPLATE
# Minimum OS major version at which ifcfg profiles should be marked as
# NetworkManager-controlled (NM_CONTROLLED=yes).
_IFCFG_NM_CONTROLLED_MIN_VERSION = None

def __init__(self, conn, os_root_dir, os_root_dev, hypervisor,
event_manager, detected_os_info, osmorphing_parameters,
Expand Down Expand Up @@ -467,6 +506,75 @@ def _get_keyfiles_by_type(self, nmconnection_type, network_scripts_path):
keyfiles.append((file, keyfile))
return keyfiles

def _get_existing_ethernet_nmconnection_files(self):
if not self._test_path(self._NM_CONNECTIONS_PATH):
return []
return [cfg_path for cfg_path, _ in self._get_keyfiles_by_type(
"ethernet", self._NM_CONNECTIONS_PATH)]

def _get_ifcfg_nm_controlled(self):
min_version = self._IFCFG_NM_CONTROLLED_MIN_VERSION
if min_version is not None and self._version_supported_util(
self._version, minimum=min_version):
return "yes"
return "no"

def _backup_nmconnection_files(self, nmconnection_files=None,
backup_file_suffix=".bak"):
if nmconnection_files is None:
nmconnection_files = (
self._get_existing_ethernet_nmconnection_files())
for cfg_path in nmconnection_files:
self._exec_cmd_chroot(
'mv "%s" "%s%s"' % (cfg_path, cfg_path, backup_file_suffix))
LOG.debug("Backed up nmconnection profile '%s'", cfg_path)

def _backup_ethernet_ifcfg_configs(self, backup_file_suffix=".bak"):
if not self._test_path(self._NETWORK_SCRIPTS_PATH):
return
for cfg_path, _ in self._get_ifcfgs_by_type(
"Ethernet", self._NETWORK_SCRIPTS_PATH):
if os.path.basename(cfg_path) == "ifcfg-lo":
continue
self._exec_cmd_chroot(
'mv "%s" "%s%s"' % (cfg_path, cfg_path, backup_file_suffix))
LOG.debug("Backed up ifcfg profile '%s'", cfg_path)

def _write_nic_configs(self, nics_info):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the nics_info format is entirely provider specific, all we need is the number of nics:

"nics_info": {
"type": "array",
"items": {
"type": "object"
}
},

I guess it's reasonable since providers can override this and handle provider specific nic info.

self._backup_ethernet_ifcfg_configs()
for idx, _ in enumerate(nics_info or []):
dev_name = "eth%d" % idx
cfg_path = "%s/ifcfg-%s" % (self._NETWORK_SCRIPTS_PATH, dev_name)
self._write_file_sudo(
cfg_path,
self._IFCFG_TEMPLATE % {
"device_name": dev_name,
"nm_controlled": self._get_ifcfg_nm_controlled(),
})

def _write_nmconnection_configs(self, nics_info, nmconnection_files=None):
nics_info = nics_info or []
if not nics_info:
return

# Systems may have both nmconnection keyfiles and legacy ifcfg
# profiles; back up Ethernet profiles from both so stale source configs
# cannot override the freshly written DHCP profiles.
self._backup_nmconnection_files(nmconnection_files)
self._backup_ethernet_ifcfg_configs()

for idx, _ in enumerate(nics_info):
dev_name = "eth%d" % idx
cfg_path = "%s/%s.nmconnection" % (
self._NM_CONNECTIONS_PATH, dev_name)
self._write_file_sudo(
cfg_path,
NMCONNECTION_TEMPLATE % {
"device_name": dev_name,
"connection_uuid": str(uuid.uuid4()),
})
self._exec_cmd_chroot("chmod 600 /%s" % cfg_path)

def _copy_resolv_conf(self):
resolv_conf = "etc/resolv.conf"
resolv_conf_path = os.path.join(self._os_root_dir, resolv_conf)
Expand Down
102 changes: 1 addition & 101 deletions coriolis/osmorphing/redhat.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,10 @@
RELEASE_FEDORA = "Fedora"


IFCFG_TEMPLATE = """
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=%(device_name)s
DEVICE=%(device_name)s
ONBOOT=yes
NM_CONTROLLED=%(nm_controlled)s
"""

NMCONNECTION_TEMPLATE = """[connection]
id=%(device_name)s
uuid=%(connection_uuid)s
type=ethernet
interface-name=%(device_name)s
autoconnect=true

[ethernet]

[ipv4]
method=auto
may-fail=false

[ipv6]
method=auto
addr-gen-mode=default
"""


class BaseRedHatMorphingTools(base.BaseLinuxOSMorphingTools):
BIOS_GRUB_LOCATION = "/boot/grub2"
UEFI_GRUB_LOCATION = "/boot/efi/EFI/redhat"
_IFCFG_NM_CONTROLLED_MIN_VERSION = 8

@classmethod
def check_os_supported(cls, detected_os_info):
Expand Down Expand Up @@ -112,11 +79,6 @@ def _has_systemd(self):
except Exception:
return False

def _get_ifcfg_nm_controlled(self):
if self._version_supported_util(self._version, minimum=8):
return "yes"
return "no"

def _set_dhcp_net_config(self, ifcfgs_ethernet):
for ifcfg_file, iface_cfg in ifcfgs_ethernet:
if iface_cfg.get("BOOTPROTO") == "none":
Expand All @@ -141,68 +103,6 @@ def _set_dhcp_net_config(self, ifcfgs_ethernet):
del network_cfg["GATEWAY"]
self._write_config_file(network_cfg_file, network_cfg)

def _get_existing_ethernet_nmconnection_files(self):
if not self._test_path(self._NM_CONNECTIONS_PATH):
return []
return [cfg_path for cfg_path, _ in self._get_keyfiles_by_type(
"ethernet", self._NM_CONNECTIONS_PATH)]

def _backup_nmconnection_files(self, nmconnection_files=None,
backup_file_suffix=".bak"):
if nmconnection_files is None:
nmconnection_files = (
self._get_existing_ethernet_nmconnection_files())
for cfg_path in nmconnection_files:
self._exec_cmd_chroot(
'mv "%s" "%s%s"' % (cfg_path, cfg_path, backup_file_suffix))
LOG.debug("Backed up nmconnection profile '%s'", cfg_path)

def _backup_all_ifcfg_configs(self, backup_file_suffix=".bak"):
if not self._test_path(self._NETWORK_SCRIPTS_PATH):
return
for cfg_path, _ in self._get_ifcfgs_by_type(
"Ethernet", self._NETWORK_SCRIPTS_PATH):
if os.path.basename(cfg_path) == "ifcfg-lo":
continue
self._exec_cmd_chroot(
'mv "%s" "%s%s"' % (cfg_path, cfg_path, backup_file_suffix))
LOG.debug("Backed up ifcfg profile '%s'", cfg_path)

def _write_nic_configs(self, nics_info):
self._backup_all_ifcfg_configs()
for idx, _ in enumerate(nics_info or []):
dev_name = "eth%d" % idx
cfg_path = "%s/ifcfg-%s" % (self._NETWORK_SCRIPTS_PATH, dev_name)
self._write_file_sudo(
cfg_path,
IFCFG_TEMPLATE % {
"device_name": dev_name,
"nm_controlled": self._get_ifcfg_nm_controlled(),
})

def _write_nmconnection_configs(self, nics_info, nmconnection_files):
nics_info = nics_info or []
if not nics_info:
return

# Red Hat-based systems may have both nmconnection keyfiles and legacy
# ifcfg profiles; back up Ethernet profiles from both so stale source
# configs cannot override the freshly written DHCP profiles.
self._backup_nmconnection_files(nmconnection_files)
self._backup_all_ifcfg_configs()

for idx, _ in enumerate(nics_info):
dev_name = "eth%d" % idx
cfg_path = "%s/%s.nmconnection" % (
self._NM_CONNECTIONS_PATH, dev_name)
self._write_file_sudo(
cfg_path,
NMCONNECTION_TEMPLATE % {
"device_name": dev_name,
"connection_uuid": str(uuid.uuid4()),
})
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.
Expand Down
50 changes: 46 additions & 4 deletions coriolis/osmorphing/suse.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,20 @@
"https://download.opensuse.org/repositories/Cloud:/Tools/%s/")
CLOUD_TOOLS_NEW_URL_MINIMUM_VERSION = 16

# SUSE (SLES/openSUSE 12 and 15) manages the network with wicked, which reads
# ifcfg files. SLES 16 switched to NetworkManager keyfiles and is handled by
# the inherited '_write_nmconnection_configs'.
SUSE_IFCFG_TEMPLATE = """BOOTPROTO='dhcp'
STARTMODE='auto'
"""


class BaseSUSEMorphingTools(base.BaseLinuxOSMorphingTools):

BIOS_GRUB_LOCATION = "/boot/grub2"
UEFI_GRUB_LOCATION = "/boot/efi/EFI/suse"
_NETWORK_SCRIPTS_PATH = "etc/sysconfig/network"
_IFCFG_TEMPLATE = SUSE_IFCFG_TEMPLATE

@classmethod
def get_required_detected_os_info_fields(cls):
Expand Down Expand Up @@ -61,12 +70,45 @@ def check_os_supported(cls, detected_os_info):
return False

def disable_predictable_nic_names(self):
# TODO(gsamfira): implement once we have networking support
pass
grub_cfg = "etc/default/grub"
if not self._test_path(grub_cfg):
LOG.warning(
"Could not find /%s. Skipping predictable NIC names "
"disabling.", grub_cfg)
return
contents = self._read_file_sudo(grub_cfg)
cfg = utils.Grub2ConfigEditor(contents)
cfg.append_to_option(
"GRUB_CMDLINE_LINUX_DEFAULT",
{"opt_type": "key_val", "opt_key": "net.ifnames", "opt_val": 0})
cfg.append_to_option(
"GRUB_CMDLINE_LINUX_DEFAULT",
{"opt_type": "key_val", "opt_key": "biosdevname", "opt_val": 0})
cfg.append_to_option(
"GRUB_CMDLINE_LINUX",
{"opt_type": "key_val", "opt_key": "net.ifnames", "opt_val": 0})
cfg.append_to_option(
"GRUB_CMDLINE_LINUX",
{"opt_type": "key_val", "opt_key": "biosdevname", "opt_val": 0})
self._write_file_sudo("etc/default/grub", cfg.dump())
self._schedule_grub2_update()

def set_net_config(self, nics_info, dhcp):
Comment thread
mihaelabalutoiu marked this conversation as resolved.
# TODO(alexpilotti): add networking support
pass
if dhcp:
nics_info = nics_info or []
if not nics_info:
return
self.disable_predictable_nic_names()
nmconnection_files = (
self._get_existing_ethernet_nmconnection_files())
if nmconnection_files:
self._write_nmconnection_configs(nics_info, nmconnection_files)
else:
self._write_nic_configs(nics_info)
return

LOG.info("Setting static IP configuration")
self._setup_network_preservation(nics_info)

def get_installed_packages(self):
cmd = 'rpm -qa --qf "%{NAME}\\n"'
Expand Down
Loading
Loading