676 lines
30 KiB
Diff
676 lines
30 KiB
Diff
|
From e1bdf2c02dd193cdd7a2da95e2a3cfa5e6e1e8b3 Mon Sep 17 00:00:00 2001
|
||
|
From: mhecko <mhecko@redhat.com>
|
||
|
Date: Mon, 29 Apr 2024 11:16:46 +0200
|
||
|
Subject: [PATCH 23/40] feature: add possibility to use net.naming-scheme
|
||
|
|
||
|
Leapp writes .link files to prevent interfaces being renamed
|
||
|
after booting to post-upgrade system. This patch adds a less
|
||
|
error-prone approach that uses net.naming-scheme kernel param.
|
||
|
The naming-scheme tells udev what hardware properties to use
|
||
|
when composing a device name. Moreover, possible values of this
|
||
|
parameter are coarse-grained "profiles", that tell udev to
|
||
|
behave as if it did on RHEL8.0.
|
||
|
|
||
|
The functionality is enabled by setting LEAPP_USE_NET_NAMING_SCHEME
|
||
|
environmental variable to 1. If the feature is enabled, the .link
|
||
|
file generation is disabled. A kernel parameter `net.naming-scheme=`
|
||
|
is added to the upgrade boot entry and the post-upgrade entry.
|
||
|
The value of the parameter will be `rhel-<source_major>.0`. Note
|
||
|
that the minor source version is *not used*. Using also source major
|
||
|
version instead of 0 causes the device names to change slightly,
|
||
|
so we use 0. Moreover, an extra RPM named `rhel-net-naming-sysattrs`
|
||
|
is installed to the target system and target userspace container.
|
||
|
The RPM provides definitions of the "profiles" for net.naming-scheme.
|
||
|
|
||
|
The feature is available only for 8>9 and higher. Attempting to
|
||
|
upgrade 7>8 with LEAPP_USE_NET_NAMING_SCHEME=1 will ignore
|
||
|
the value of LEAPP_USE_NET_NAMING_SCHEME.
|
||
|
|
||
|
Add a possibility to use the net.naming-scheme cmdline argument
|
||
|
to make immutable network interface names during the upgrade.
|
||
|
The feature can be used only for 8>9 upgrades and higher.
|
||
|
To enable the feature, use LEAPP_USE_NET_NAMING_SCHEME=1.
|
||
|
|
||
|
Jira-ref: RHEL-23473
|
||
|
---
|
||
|
.../actors/addupgradebootentry/actor.py | 10 +-
|
||
|
.../libraries/addupgradebootentry.py | 78 ++++++++++-----
|
||
|
.../tests/unit_test_addupgradebootentry.py | 47 ++++-----
|
||
|
.../actors/kernelcmdlineconfig/actor.py | 16 +++-
|
||
|
.../libraries/kernelcmdlineconfig.py | 12 ++-
|
||
|
.../libraries/persistentnetnamesconfig.py | 5 +-
|
||
|
.../common/models/kernelcmdlineargs.py | 21 ++++
|
||
|
.../actors/emit_net_naming_scheme/actor.py | 28 ++++++
|
||
|
.../libraries/emit_net_naming.py | 63 ++++++++++++
|
||
|
.../tests/test_emit_net_naming_scheme.py | 95 +++++++++++++++++++
|
||
|
10 files changed, 318 insertions(+), 57 deletions(-)
|
||
|
create mode 100644 repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/actor.py
|
||
|
create mode 100644 repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/libraries/emit_net_naming.py
|
||
|
create mode 100644 repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/tests/test_emit_net_naming_scheme.py
|
||
|
|
||
|
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/actor.py b/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||
|
index f400ebf8..e4ecf39e 100644
|
||
|
--- a/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||
|
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||
|
@@ -8,11 +8,13 @@ from leapp.models import (
|
||
|
FirmwareFacts,
|
||
|
GrubConfigError,
|
||
|
KernelCmdline,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
LiveImagePreparationInfo,
|
||
|
LiveModeArtifacts,
|
||
|
LiveModeConfig,
|
||
|
TargetKernelCmdlineArgTasks,
|
||
|
- TransactionDryRun
|
||
|
+ TransactionDryRun,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
)
|
||
|
from leapp.tags import InterimPreparationPhaseTag, IPUWorkflowTag
|
||
|
|
||
|
@@ -33,9 +35,11 @@ class AddUpgradeBootEntry(Actor):
|
||
|
LiveModeArtifacts,
|
||
|
LiveModeConfig,
|
||
|
KernelCmdline,
|
||
|
- TransactionDryRun
|
||
|
+ TransactionDryRun,
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
)
|
||
|
- produces = (TargetKernelCmdlineArgTasks,)
|
||
|
+ produces = (LateTargetKernelCmdlineArgTasks,)
|
||
|
tags = (IPUWorkflowTag, InterimPreparationPhaseTag)
|
||
|
|
||
|
def process(self):
|
||
|
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||
|
index 553ffc35..b236e39b 100644
|
||
|
--- a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||
|
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||
|
@@ -9,14 +9,16 @@ from leapp.models import (
|
||
|
BootContent,
|
||
|
KernelCmdline,
|
||
|
KernelCmdlineArg,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
LiveImagePreparationInfo,
|
||
|
LiveModeArtifacts,
|
||
|
LiveModeConfig,
|
||
|
- TargetKernelCmdlineArgTasks
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
)
|
||
|
|
||
|
|
||
|
-def collect_boot_args(livemode_enabled):
|
||
|
+def collect_upgrade_kernel_args(livemode_enabled):
|
||
|
args = {
|
||
|
'enforcing': '0',
|
||
|
'rd.plymouth': '0',
|
||
|
@@ -34,7 +36,10 @@ def collect_boot_args(livemode_enabled):
|
||
|
livemode_args = construct_cmdline_args_for_livemode()
|
||
|
args.update(livemode_args)
|
||
|
|
||
|
- return args
|
||
|
+ upgrade_kernel_args = collect_set_of_kernel_args_from_msgs(UpgradeKernelCmdlineArgTasks, 'to_add')
|
||
|
+ args.update(upgrade_kernel_args)
|
||
|
+
|
||
|
+ return set(args.items())
|
||
|
|
||
|
|
||
|
def collect_undesired_args(livemode_enabled):
|
||
|
@@ -43,11 +48,11 @@ def collect_undesired_args(livemode_enabled):
|
||
|
args = dict(zip(('ro', 'rhgb', 'quiet'), itertools.repeat(None)))
|
||
|
args['rd.lvm.lv'] = _get_rdlvm_arg_values()
|
||
|
|
||
|
- return args
|
||
|
+ return set(args.items())
|
||
|
|
||
|
|
||
|
-def format_grubby_args_from_args_dict(args_dict):
|
||
|
- """ Format the given args dictionary in a form required by grubby's --args. """
|
||
|
+def format_grubby_args_from_args_set(args_dict):
|
||
|
+ """ Format the given args set in a form required by grubby's --args. """
|
||
|
|
||
|
def fmt_single_arg(arg_pair):
|
||
|
key, value = arg_pair
|
||
|
@@ -65,7 +70,7 @@ def format_grubby_args_from_args_dict(args_dict):
|
||
|
else:
|
||
|
yield (key, value) # Just a single (key, value) pair
|
||
|
|
||
|
- arg_sequence = itertools.chain(*(flatten_arguments(arg_pair) for arg_pair in args_dict.items()))
|
||
|
+ arg_sequence = itertools.chain(*(flatten_arguments(arg_pair) for arg_pair in args_dict))
|
||
|
|
||
|
# Sorting should be fine as only values can be None, but we cannot have a (key, None) and (key, value) in
|
||
|
# the dictionary at the same time.
|
||
|
@@ -78,7 +83,7 @@ def format_grubby_args_from_args_dict(args_dict):
|
||
|
def figure_out_commands_needed_to_add_entry(kernel_path, initramfs_path, args_to_add, args_to_remove):
|
||
|
boot_entry_modification_commands = []
|
||
|
|
||
|
- args_to_add_str = format_grubby_args_from_args_dict(args_to_add)
|
||
|
+ args_to_add_str = format_grubby_args_from_args_set(args_to_add)
|
||
|
|
||
|
create_entry_cmd = [
|
||
|
'/usr/sbin/grubby',
|
||
|
@@ -93,7 +98,7 @@ def figure_out_commands_needed_to_add_entry(kernel_path, initramfs_path, args_to
|
||
|
|
||
|
# We need to update root= param separately, since we cannot do it during --add-kernel with --copy-default.
|
||
|
# This is likely a bug in grubby.
|
||
|
- root_param_value = args_to_add.get('root', None)
|
||
|
+ root_param_value = dict(args_to_add).get('root', None)
|
||
|
if root_param_value:
|
||
|
enforce_root_param_for_the_entry_cmd = [
|
||
|
'/usr/sbin/grubby',
|
||
|
@@ -103,7 +108,7 @@ def figure_out_commands_needed_to_add_entry(kernel_path, initramfs_path, args_to
|
||
|
boot_entry_modification_commands.append(enforce_root_param_for_the_entry_cmd)
|
||
|
|
||
|
if args_to_remove:
|
||
|
- args_to_remove_str = format_grubby_args_from_args_dict(args_to_remove)
|
||
|
+ args_to_remove_str = format_grubby_args_from_args_set(args_to_remove)
|
||
|
remove_undesired_args_cmd = [
|
||
|
'/usr/sbin/grubby',
|
||
|
'--update-kernel', kernel_path,
|
||
|
@@ -113,18 +118,55 @@ def figure_out_commands_needed_to_add_entry(kernel_path, initramfs_path, args_to
|
||
|
return boot_entry_modification_commands
|
||
|
|
||
|
|
||
|
+def collect_set_of_kernel_args_from_msgs(msg_type, arg_list_field_name):
|
||
|
+ cmdline_modification_msgs = api.consume(msg_type)
|
||
|
+ lists_of_args_to_add = (getattr(msg, arg_list_field_name, []) for msg in cmdline_modification_msgs)
|
||
|
+ args = itertools.chain(*lists_of_args_to_add)
|
||
|
+ return set((arg.key, arg.value) for arg in args)
|
||
|
+
|
||
|
+
|
||
|
+def emit_removal_of_args_meant_only_for_upgrade_kernel(added_upgrade_kernel_args):
|
||
|
+ """
|
||
|
+ Emit message requesting removal of upgrade kernel args that should not be on the target kernel.
|
||
|
+
|
||
|
+ Target kernel args are created by copying the args of the booted (upgrade) kernel. Therefore,
|
||
|
+ we need to explicitly modify the target kernel cmdline, removing what should not have been copied.
|
||
|
+ """
|
||
|
+ target_args_to_add = collect_set_of_kernel_args_from_msgs(TargetKernelCmdlineArgTasks, 'to_add')
|
||
|
+ actual_kernel_args = collect_set_of_kernel_args_from_msgs(KernelCmdline, 'parameters')
|
||
|
+
|
||
|
+ # actual_kernel_args should not be changed during upgrade, unless explicitly removed by
|
||
|
+ # TargetKernelCmdlineArgTasks.to_remove, but that is handled by some other upgrade component. We just want
|
||
|
+ # to make sure we remove what was not on the source system and that we don't overwrite args to be added to target.
|
||
|
+ args_not_present_on_target_kernel = added_upgrade_kernel_args - actual_kernel_args - target_args_to_add
|
||
|
+
|
||
|
+ # We remove only what we've added and what will not be already removed by someone else.
|
||
|
+ args_to_remove = [KernelCmdlineArg(key=arg[0], value=arg[1]) for arg in args_not_present_on_target_kernel]
|
||
|
+
|
||
|
+ if args_to_remove:
|
||
|
+ msg = ('Following upgrade kernel args were added, but they should not be present '
|
||
|
+ 'on target cmdline: `%s`, requesting removal.')
|
||
|
+ api.current_logger().info(msg, args_not_present_on_target_kernel)
|
||
|
+ args_sorted = sorted(args_to_remove, key=lambda arg: arg.key)
|
||
|
+ api.produce(LateTargetKernelCmdlineArgTasks(to_remove=args_sorted))
|
||
|
+
|
||
|
+
|
||
|
def add_boot_entry(configs=None):
|
||
|
kernel_dst_path, initram_dst_path = get_boot_file_paths()
|
||
|
+
|
||
|
_remove_old_upgrade_boot_entry(kernel_dst_path, configs=configs)
|
||
|
|
||
|
livemode_enabled = next(api.consume(LiveImagePreparationInfo), None) is not None
|
||
|
|
||
|
- cmdline_args = collect_boot_args(livemode_enabled)
|
||
|
+ # We have to keep the desired and unwanted args separate and modify cmline in two separate grubby calls. Merging
|
||
|
+ # these sets and trying to execute only a single command would leave the unwanted cmdline args present if they
|
||
|
+ # are present on the original system.
|
||
|
+ added_cmdline_args = collect_upgrade_kernel_args(livemode_enabled)
|
||
|
undesired_cmdline_args = collect_undesired_args(livemode_enabled)
|
||
|
|
||
|
commands_to_run = figure_out_commands_needed_to_add_entry(kernel_dst_path,
|
||
|
initram_dst_path,
|
||
|
- args_to_add=cmdline_args,
|
||
|
+ args_to_add=added_cmdline_args,
|
||
|
args_to_remove=undesired_cmdline_args)
|
||
|
|
||
|
def run_commands_adding_entry(extra_command_suffix=None):
|
||
|
@@ -146,16 +188,8 @@ def add_boot_entry(configs=None):
|
||
|
# See https://bugzilla.redhat.com/show_bug.cgi?id=1764306
|
||
|
run(['/usr/sbin/zipl'])
|
||
|
|
||
|
- if 'debug' in cmdline_args:
|
||
|
- # The kernelopts for target kernel are generated based on the cmdline used in the upgrade initramfs,
|
||
|
- # therefore, if we enabled debug above, and the original system did not have the debug kernelopt, we
|
||
|
- # need to explicitly remove it from the target os boot entry.
|
||
|
- # NOTE(mhecko): This will also unconditionally remove debug kernelopt if the source system used it.
|
||
|
- api.produce(TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug')]))
|
||
|
-
|
||
|
- # NOTE(mmatuska): This will remove the option even if the source system had it set.
|
||
|
- # However enforcing=0 shouldn't be set persistently anyway.
|
||
|
- api.produce(TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='enforcing', value='0')]))
|
||
|
+ effective_upgrade_kernel_args = added_cmdline_args - undesired_cmdline_args
|
||
|
+ emit_removal_of_args_meant_only_for_upgrade_kernel(effective_upgrade_kernel_args)
|
||
|
|
||
|
except CalledProcessError as e:
|
||
|
raise StopActorExecutionError(
|
||
|
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||
|
index c4f5232b..2f58ba9e 100644
|
||
|
--- a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||
|
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||
|
@@ -12,6 +12,7 @@ from leapp.models import (
|
||
|
BootContent,
|
||
|
KernelCmdline,
|
||
|
KernelCmdlineArg,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
LiveModeArtifacts,
|
||
|
LiveModeConfig,
|
||
|
TargetKernelCmdlineArgTasks
|
||
|
@@ -82,8 +83,10 @@ def test_add_boot_entry(monkeypatch, run_args, arch):
|
||
|
assert addupgradebootentry.run.args[0] == run_args.args_remove
|
||
|
assert addupgradebootentry.run.args[1] == run_args.args_add
|
||
|
assert api.produce.model_instances == [
|
||
|
- TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug')]),
|
||
|
- TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='enforcing', value='0')])
|
||
|
+ LateTargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug'),
|
||
|
+ KernelCmdlineArg(key='enforcing', value='0'),
|
||
|
+ KernelCmdlineArg(key='plymouth.enable', value='0'),
|
||
|
+ KernelCmdlineArg(key='rd.plymouth', value='0')])
|
||
|
]
|
||
|
|
||
|
if run_args.args_zipl:
|
||
|
@@ -103,16 +106,16 @@ def test_debug_kernelopt_removal_task_production(monkeypatch, is_leapp_invoked_w
|
||
|
CurrentActorMocked(envars={'LEAPP_DEBUG': str(int(is_leapp_invoked_with_debug))}))
|
||
|
|
||
|
addupgradebootentry.add_boot_entry()
|
||
|
+ assert len(api.produce.model_instances) == 1
|
||
|
|
||
|
- expected_produced_messages = []
|
||
|
- if is_leapp_invoked_with_debug:
|
||
|
- expected_produced_messages = [TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug')])]
|
||
|
-
|
||
|
- expected_produced_messages.append(
|
||
|
- TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='enforcing', value='0')])
|
||
|
- )
|
||
|
+ produced_msg = api.produce.model_instances[0]
|
||
|
+ assert isinstance(produced_msg, LateTargetKernelCmdlineArgTasks)
|
||
|
|
||
|
- assert api.produce.model_instances == expected_produced_messages
|
||
|
+ debug_kernel_cmline_arg = KernelCmdlineArg(key='debug')
|
||
|
+ if is_leapp_invoked_with_debug:
|
||
|
+ assert debug_kernel_cmline_arg in produced_msg.to_remove
|
||
|
+ else:
|
||
|
+ assert debug_kernel_cmline_arg not in produced_msg.to_remove
|
||
|
|
||
|
|
||
|
def test_add_boot_entry_configs(monkeypatch):
|
||
|
@@ -132,8 +135,10 @@ def test_add_boot_entry_configs(monkeypatch):
|
||
|
assert addupgradebootentry.run.args[2] == run_args_add + ['-c', CONFIGS[0]]
|
||
|
assert addupgradebootentry.run.args[3] == run_args_add + ['-c', CONFIGS[1]]
|
||
|
assert api.produce.model_instances == [
|
||
|
- TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug')]),
|
||
|
- TargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='enforcing', value='0')]),
|
||
|
+ LateTargetKernelCmdlineArgTasks(to_remove=[KernelCmdlineArg(key='debug'),
|
||
|
+ KernelCmdlineArg(key='enforcing', value='0'),
|
||
|
+ KernelCmdlineArg(key='plymouth.enable', value='0'),
|
||
|
+ KernelCmdlineArg(key='rd.plymouth', value='0')])
|
||
|
]
|
||
|
|
||
|
|
||
|
@@ -183,7 +188,7 @@ def test_fix_grub_config_error(monkeypatch, error_type, test_file_name):
|
||
|
(False, False),
|
||
|
)
|
||
|
)
|
||
|
-def test_collect_boot_args(monkeypatch, is_debug_enabled, network_enablement_type):
|
||
|
+def test_collect_upgrade_kernel_args(monkeypatch, is_debug_enabled, network_enablement_type):
|
||
|
env_vars = {'LEAPP_DEBUG': str(int(is_debug_enabled))}
|
||
|
if network_enablement_type:
|
||
|
env_vars['LEAPP_DEVEL_INITRAM_NETWORK'] = network_enablement_type
|
||
|
@@ -192,7 +197,8 @@ def test_collect_boot_args(monkeypatch, is_debug_enabled, network_enablement_typ
|
||
|
monkeypatch.setattr(addupgradebootentry, 'construct_cmdline_args_for_livemode',
|
||
|
lambda *args: {'livemodearg': 'value'})
|
||
|
|
||
|
- args = addupgradebootentry.collect_boot_args(livemode_enabled=True)
|
||
|
+ arg_set = addupgradebootentry.collect_upgrade_kernel_args(livemode_enabled=True)
|
||
|
+ args = dict(arg_set)
|
||
|
|
||
|
assert args['enforcing'] == '0'
|
||
|
assert args['rd.plymouth'] == '0'
|
||
|
@@ -320,16 +326,3 @@ def test_get_device_uuid(monkeypatch):
|
||
|
uuid = addupgradebootentry._get_device_uuid(path)
|
||
|
|
||
|
assert uuid == 'MY_UUID1'
|
||
|
-
|
||
|
-
|
||
|
-@pytest.mark.parametrize(
|
||
|
- ('args', 'expected_result'),
|
||
|
- (
|
||
|
- ([('argA', 'val'), ('argB', 'valB'), ('argC', None), ], 'argA=val argB=valB argC'),
|
||
|
- ([('argA', ('val1', 'val2'))], 'argA=val1 argA=val2')
|
||
|
- )
|
||
|
-)
|
||
|
-def test_format_grubby_args_from_args_dict(args, expected_result):
|
||
|
- actual_result = addupgradebootentry.format_grubby_args_from_args_dict(dict(args))
|
||
|
-
|
||
|
- assert actual_result == expected_result
|
||
|
diff --git a/repos/system_upgrade/common/actors/kernelcmdlineconfig/actor.py b/repos/system_upgrade/common/actors/kernelcmdlineconfig/actor.py
|
||
|
index 3585a14e..6d5f39dd 100644
|
||
|
--- a/repos/system_upgrade/common/actors/kernelcmdlineconfig/actor.py
|
||
|
+++ b/repos/system_upgrade/common/actors/kernelcmdlineconfig/actor.py
|
||
|
@@ -3,7 +3,13 @@ import os
|
||
|
from leapp.actors import Actor
|
||
|
from leapp.exceptions import StopActorExecutionError
|
||
|
from leapp.libraries.actor import kernelcmdlineconfig
|
||
|
-from leapp.models import FirmwareFacts, InstalledTargetKernelInfo, KernelCmdlineArg, TargetKernelCmdlineArgTasks
|
||
|
+from leapp.models import (
|
||
|
+ FirmwareFacts,
|
||
|
+ InstalledTargetKernelInfo,
|
||
|
+ KernelCmdlineArg,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
+ TargetKernelCmdlineArgTasks
|
||
|
+)
|
||
|
from leapp.reporting import Report
|
||
|
from leapp.tags import FinalizationPhaseTag, IPUWorkflowTag
|
||
|
|
||
|
@@ -14,7 +20,13 @@ class KernelCmdlineConfig(Actor):
|
||
|
"""
|
||
|
|
||
|
name = 'kernelcmdlineconfig'
|
||
|
- consumes = (KernelCmdlineArg, InstalledTargetKernelInfo, FirmwareFacts, TargetKernelCmdlineArgTasks)
|
||
|
+ consumes = (
|
||
|
+ KernelCmdlineArg,
|
||
|
+ InstalledTargetKernelInfo,
|
||
|
+ FirmwareFacts,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
+ TargetKernelCmdlineArgTasks
|
||
|
+ )
|
||
|
produces = (Report,)
|
||
|
tags = (FinalizationPhaseTag, IPUWorkflowTag)
|
||
|
|
||
|
diff --git a/repos/system_upgrade/common/actors/kernelcmdlineconfig/libraries/kernelcmdlineconfig.py b/repos/system_upgrade/common/actors/kernelcmdlineconfig/libraries/kernelcmdlineconfig.py
|
||
|
index 19c50f3c..98b8b95b 100644
|
||
|
--- a/repos/system_upgrade/common/actors/kernelcmdlineconfig/libraries/kernelcmdlineconfig.py
|
||
|
+++ b/repos/system_upgrade/common/actors/kernelcmdlineconfig/libraries/kernelcmdlineconfig.py
|
||
|
@@ -1,3 +1,4 @@
|
||
|
+import itertools
|
||
|
import re
|
||
|
|
||
|
from leapp import reporting
|
||
|
@@ -5,7 +6,12 @@ from leapp.exceptions import StopActorExecutionError
|
||
|
from leapp.libraries import stdlib
|
||
|
from leapp.libraries.common.config import architecture, version
|
||
|
from leapp.libraries.stdlib import api
|
||
|
-from leapp.models import InstalledTargetKernelInfo, KernelCmdlineArg, TargetKernelCmdlineArgTasks
|
||
|
+from leapp.models import (
|
||
|
+ InstalledTargetKernelInfo,
|
||
|
+ KernelCmdlineArg,
|
||
|
+ LateTargetKernelCmdlineArgTasks,
|
||
|
+ TargetKernelCmdlineArgTasks
|
||
|
+)
|
||
|
|
||
|
KERNEL_CMDLINE_FILE = "/etc/kernel/cmdline"
|
||
|
|
||
|
@@ -71,7 +77,9 @@ def retrieve_arguments_to_modify():
|
||
|
kernelargs_msgs_to_add = list(api.consume(KernelCmdlineArg))
|
||
|
kernelargs_msgs_to_remove = []
|
||
|
|
||
|
- for target_kernel_arg_task in api.consume(TargetKernelCmdlineArgTasks):
|
||
|
+ modification_msgs = itertools.chain(api.consume(TargetKernelCmdlineArgTasks),
|
||
|
+ api.consume(LateTargetKernelCmdlineArgTasks))
|
||
|
+ for target_kernel_arg_task in modification_msgs:
|
||
|
kernelargs_msgs_to_add.extend(target_kernel_arg_task.to_add)
|
||
|
kernelargs_msgs_to_remove.extend(target_kernel_arg_task.to_remove)
|
||
|
|
||
|
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py b/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
|
||
|
index dc5196ea..2f12742a 100644
|
||
|
--- a/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
|
||
|
+++ b/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
|
||
|
@@ -2,7 +2,7 @@ import errno
|
||
|
import os
|
||
|
import re
|
||
|
|
||
|
-from leapp.libraries.common.config import get_env
|
||
|
+from leapp.libraries.common.config import get_env, version
|
||
|
from leapp.libraries.stdlib import api
|
||
|
from leapp.models import (
|
||
|
InitrdIncludes,
|
||
|
@@ -39,6 +39,9 @@ def generate_link_file(interface):
|
||
|
|
||
|
@suppress_deprecation(InitrdIncludes)
|
||
|
def process():
|
||
|
+ if get_env('LEAPP_USE_NET_NAMING_SCHEMES', '0') == '1' and version.get_target_major_version() != '8':
|
||
|
+ api.current_logger().info('Skipping generation of .link files renaming NICs as LEAPP_USE_NET_NAMING_SCHEMES=1')
|
||
|
+ return
|
||
|
|
||
|
if get_env('LEAPP_NO_NETWORK_RENAMING', '0') == '1':
|
||
|
api.current_logger().info(
|
||
|
diff --git a/repos/system_upgrade/common/models/kernelcmdlineargs.py b/repos/system_upgrade/common/models/kernelcmdlineargs.py
|
||
|
index e3568a0a..fafd2853 100644
|
||
|
--- a/repos/system_upgrade/common/models/kernelcmdlineargs.py
|
||
|
+++ b/repos/system_upgrade/common/models/kernelcmdlineargs.py
|
||
|
@@ -24,6 +24,27 @@ class TargetKernelCmdlineArgTasks(Model):
|
||
|
to_remove = fields.List(fields.Model(KernelCmdlineArg), default=[])
|
||
|
|
||
|
|
||
|
+class LateTargetKernelCmdlineArgTasks(Model):
|
||
|
+ """
|
||
|
+ Desired modifications of the target kernel args produced later in the upgrade process.
|
||
|
+
|
||
|
+ Defined to prevent loops in the actor dependency graph.
|
||
|
+ """
|
||
|
+ topic = SystemInfoTopic
|
||
|
+
|
||
|
+ to_add = fields.List(fields.Model(KernelCmdlineArg), default=[])
|
||
|
+ to_remove = fields.List(fields.Model(KernelCmdlineArg), default=[])
|
||
|
+
|
||
|
+
|
||
|
+class UpgradeKernelCmdlineArgTasks(Model):
|
||
|
+ """
|
||
|
+ Modifications of the upgrade kernel cmdline.
|
||
|
+ """
|
||
|
+ topic = SystemInfoTopic
|
||
|
+
|
||
|
+ to_add = fields.List(fields.Model(KernelCmdlineArg), default=[])
|
||
|
+
|
||
|
+
|
||
|
class KernelCmdline(Model):
|
||
|
"""
|
||
|
Kernel command line parameters the system was booted with
|
||
|
diff --git a/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/actor.py b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/actor.py
|
||
|
new file mode 100644
|
||
|
index 00000000..769fe20b
|
||
|
--- /dev/null
|
||
|
+++ b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/actor.py
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+from leapp.actors import Actor
|
||
|
+from leapp.libraries.actor import emit_net_naming as emit_net_naming_lib
|
||
|
+from leapp.models import (
|
||
|
+ KernelCmdline,
|
||
|
+ RpmTransactionTasks,
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ TargetUserSpaceUpgradeTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
+)
|
||
|
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
|
||
|
+
|
||
|
+
|
||
|
+class EmitNetNamingScheme(Actor):
|
||
|
+ """
|
||
|
+ Emit necessary modifications of the upgrade environment and target command line to use net.naming-scheme.
|
||
|
+ """
|
||
|
+ name = 'emit_net_naming_scheme'
|
||
|
+ consumes = (KernelCmdline,)
|
||
|
+ produces = (
|
||
|
+ RpmTransactionTasks,
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ TargetUserSpaceUpgradeTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks,
|
||
|
+ )
|
||
|
+ tags = (ChecksPhaseTag, IPUWorkflowTag)
|
||
|
+
|
||
|
+ def process(self):
|
||
|
+ emit_net_naming_lib.emit_msgs_to_use_net_naming_schemes()
|
||
|
diff --git a/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/libraries/emit_net_naming.py b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/libraries/emit_net_naming.py
|
||
|
new file mode 100644
|
||
|
index 00000000..65abdd4d
|
||
|
--- /dev/null
|
||
|
+++ b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/libraries/emit_net_naming.py
|
||
|
@@ -0,0 +1,63 @@
|
||
|
+from leapp.exceptions import StopActorExecutionError
|
||
|
+from leapp.libraries.common.config import get_env, version
|
||
|
+from leapp.libraries.stdlib import api
|
||
|
+from leapp.models import (
|
||
|
+ KernelCmdline,
|
||
|
+ KernelCmdlineArg,
|
||
|
+ RpmTransactionTasks,
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ TargetUserSpaceUpgradeTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
+)
|
||
|
+
|
||
|
+NET_NAMING_SYSATTRS_RPM_NAME = 'rhel-net-naming-sysattrs'
|
||
|
+
|
||
|
+
|
||
|
+def is_net_scheme_compatible_with_current_cmdline():
|
||
|
+ kernel_cmdline = next(api.consume(KernelCmdline), None)
|
||
|
+ if not kernel_cmdline:
|
||
|
+ # Super unlikely
|
||
|
+ raise StopActorExecutionError('Did not receive any KernelCmdline messages.')
|
||
|
+
|
||
|
+ allows_predictable_names = True
|
||
|
+ already_has_a_net_naming_scheme = False
|
||
|
+ for param in kernel_cmdline.parameters:
|
||
|
+ if param.key == 'net.ifnames':
|
||
|
+ if param.value == '0':
|
||
|
+ allows_predictable_names = False
|
||
|
+ elif param.value == '1':
|
||
|
+ allows_predictable_names = True
|
||
|
+ if param.key == 'net.naming-scheme':
|
||
|
+ # We assume that the kernel cmdline does not contain invalid entries, namely,
|
||
|
+ # that the net.naming-scheme refers to a valid scheme.
|
||
|
+ already_has_a_net_naming_scheme = True
|
||
|
+
|
||
|
+ is_compatible = allows_predictable_names and not already_has_a_net_naming_scheme
|
||
|
+
|
||
|
+ msg = ('Should net.naming-scheme be added to kernel cmdline: %s. '
|
||
|
+ 'Reason: allows_predictable_names=%s, already_has_a_net_naming_scheme=%s')
|
||
|
+ api.current_logger().info(msg, 'yes' if is_compatible else 'no',
|
||
|
+ allows_predictable_names,
|
||
|
+ already_has_a_net_naming_scheme)
|
||
|
+
|
||
|
+ return is_compatible
|
||
|
+
|
||
|
+
|
||
|
+def emit_msgs_to_use_net_naming_schemes():
|
||
|
+ if get_env('LEAPP_USE_NET_NAMING_SCHEMES', '0') != '1' and version.get_target_major_version() != '8':
|
||
|
+ return
|
||
|
+
|
||
|
+ # The package should be installed regardless of whether we will modify the cmdline -
|
||
|
+ # if the cmdline already contains net.naming-scheme, then the package will be useful
|
||
|
+ # in both, the upgrade environment and on the target system.
|
||
|
+ pkgs_to_install = [NET_NAMING_SYSATTRS_RPM_NAME]
|
||
|
+ api.produce(TargetUserSpaceUpgradeTasks(install_rpms=pkgs_to_install))
|
||
|
+ api.produce(RpmTransactionTasks(to_install=pkgs_to_install))
|
||
|
+
|
||
|
+ if not is_net_scheme_compatible_with_current_cmdline():
|
||
|
+ return
|
||
|
+
|
||
|
+ naming_scheme = 'rhel-{0}.0'.format(version.get_source_major_version())
|
||
|
+ cmdline_args = [KernelCmdlineArg(key='net.naming-scheme', value=naming_scheme)]
|
||
|
+ api.produce(UpgradeKernelCmdlineArgTasks(to_add=cmdline_args))
|
||
|
+ api.produce(TargetKernelCmdlineArgTasks(to_add=cmdline_args))
|
||
|
diff --git a/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/tests/test_emit_net_naming_scheme.py b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/tests/test_emit_net_naming_scheme.py
|
||
|
new file mode 100644
|
||
|
index 00000000..7a5eeba5
|
||
|
--- /dev/null
|
||
|
+++ b/repos/system_upgrade/el8toel9/actors/emit_net_naming_scheme/tests/test_emit_net_naming_scheme.py
|
||
|
@@ -0,0 +1,95 @@
|
||
|
+import pytest
|
||
|
+
|
||
|
+from leapp.libraries.actor import emit_net_naming as emit_net_naming_lib
|
||
|
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
|
||
|
+from leapp.libraries.stdlib import api
|
||
|
+from leapp.models import (
|
||
|
+ KernelCmdline,
|
||
|
+ KernelCmdlineArg,
|
||
|
+ RpmTransactionTasks,
|
||
|
+ TargetKernelCmdlineArgTasks,
|
||
|
+ TargetUserSpaceUpgradeTasks,
|
||
|
+ UpgradeKernelCmdlineArgTasks
|
||
|
+)
|
||
|
+
|
||
|
+
|
||
|
+@pytest.mark.parametrize(
|
||
|
+ ('kernel_args', 'should_be_compatible'),
|
||
|
+ [
|
||
|
+ ([KernelCmdlineArg(key='net.naming-scheme', value='rhel-8.10')], False),
|
||
|
+ ([KernelCmdlineArg(key='net.ifnames', value='1')], True),
|
||
|
+ ([KernelCmdlineArg(key='net.ifnames', value='0')], False),
|
||
|
+ (
|
||
|
+ [
|
||
|
+ KernelCmdlineArg(key='net.naming-scheme', value='rhel-8.10'),
|
||
|
+ KernelCmdlineArg(key='net.ifname', value='0'),
|
||
|
+ KernelCmdlineArg(key='root', value='/dev/vda1')
|
||
|
+ ],
|
||
|
+ False
|
||
|
+ ),
|
||
|
+ ([KernelCmdlineArg(key='root', value='/dev/vda1')], True),
|
||
|
+ ]
|
||
|
+)
|
||
|
+def test_is_net_scheme_compatible_with_current_cmdline(monkeypatch, kernel_args, should_be_compatible):
|
||
|
+ kernel_cmdline = KernelCmdline(parameters=kernel_args)
|
||
|
+
|
||
|
+ def mocked_consume(msg_type):
|
||
|
+ yield {KernelCmdline: kernel_cmdline}[msg_type]
|
||
|
+
|
||
|
+ monkeypatch.setattr(api, 'consume', mocked_consume)
|
||
|
+
|
||
|
+ assert emit_net_naming_lib.is_net_scheme_compatible_with_current_cmdline() == should_be_compatible, \
|
||
|
+ [(arg.key, arg.value) for arg in kernel_cmdline.parameters]
|
||
|
+
|
||
|
+
|
||
|
+@pytest.mark.parametrize(
|
||
|
+ ('is_net_scheme_enabled', 'is_current_cmdline_compatible'),
|
||
|
+ [
|
||
|
+ (True, True),
|
||
|
+ (True, False),
|
||
|
+ (False, True)
|
||
|
+ ]
|
||
|
+)
|
||
|
+def test_emit_msgs_to_use_net_naming_schemes(monkeypatch, is_net_scheme_enabled, is_current_cmdline_compatible):
|
||
|
+ envvar_value = '1' if is_net_scheme_enabled else '0'
|
||
|
+
|
||
|
+ mocked_actor = CurrentActorMocked(src_ver='8.10',
|
||
|
+ dst_ver='9.5',
|
||
|
+ envars={'LEAPP_USE_NET_NAMING_SCHEMES': envvar_value})
|
||
|
+ monkeypatch.setattr(api, 'current_actor', mocked_actor)
|
||
|
+
|
||
|
+ monkeypatch.setattr(api, 'produce', produce_mocked())
|
||
|
+ monkeypatch.setattr(emit_net_naming_lib,
|
||
|
+ 'is_net_scheme_compatible_with_current_cmdline',
|
||
|
+ lambda: is_current_cmdline_compatible)
|
||
|
+
|
||
|
+ emit_net_naming_lib.emit_msgs_to_use_net_naming_schemes()
|
||
|
+
|
||
|
+ def ensure_one_msg_of_type_produced(produced_messages, msg_type):
|
||
|
+ msgs = (msg for msg in produced_messages if isinstance(msg, msg_type))
|
||
|
+ msg = next(msgs)
|
||
|
+ assert not next(msgs, None), 'More than one message of type {type} produced'.format(type=type)
|
||
|
+ return msg
|
||
|
+
|
||
|
+ produced_messages = api.produce.model_instances
|
||
|
+ if is_net_scheme_enabled:
|
||
|
+ userspace_tasks = ensure_one_msg_of_type_produced(produced_messages, TargetUserSpaceUpgradeTasks)
|
||
|
+ assert userspace_tasks.install_rpms == [emit_net_naming_lib.NET_NAMING_SYSATTRS_RPM_NAME]
|
||
|
+
|
||
|
+ rpm_tasks = ensure_one_msg_of_type_produced(produced_messages, RpmTransactionTasks)
|
||
|
+ assert rpm_tasks.to_install == [emit_net_naming_lib.NET_NAMING_SYSATTRS_RPM_NAME]
|
||
|
+ else:
|
||
|
+ assert not api.produce.called
|
||
|
+ return
|
||
|
+
|
||
|
+ upgrade_cmdline_mods = (msg for msg in produced_messages if isinstance(msg, UpgradeKernelCmdlineArgTasks))
|
||
|
+ target_cmdline_mods = (msg for msg in produced_messages if isinstance(msg, TargetKernelCmdlineArgTasks))
|
||
|
+
|
||
|
+ if is_current_cmdline_compatible:
|
||
|
+ # We should emit cmdline modifications - both UpgradeKernelCmdlineArgTasks and TargetKernelCmdlineArgTasks
|
||
|
+ # should be produced
|
||
|
+ assert next(upgrade_cmdline_mods, None)
|
||
|
+ assert next(target_cmdline_mods, None)
|
||
|
+ else:
|
||
|
+ assert not next(upgrade_cmdline_mods, None)
|
||
|
+ assert not next(target_cmdline_mods, None)
|
||
|
--
|
||
|
2.47.0
|
||
|
|