Skip to content

Commit d7f37d6

Browse files
committed
Add possibility to add kernel drivers to initrd
Before this change there was no possibility for developers to specify what kernel drivers should be included in the upgrade/target initramfs. This includes third-party drivers, which are necessary for system upgrades in some spefic use cases. Changes include: - A new model `KernelModule` (analogous to the `DracutModule` model) has been created, to handle kernel drivers. - Added an `include_kernel_drivers` field in the `UpgradeInitramfsTasks` model to handle a list of these drivers. - Data in the `include_kernel_drivers` field is processed correctly to detect conflicting paths. - Modified the `generate-iniram.sh` script to accept and process the new data - Added checks for kernel drivers, in the `CheckInitramfsTasks` actor. - Updated the unit-tests accordingly.
1 parent 777e0a6 commit d7f37d6

File tree

7 files changed

+365
-91
lines changed

7 files changed

+365
-91
lines changed

repos/system_upgrade/common/actors/commonleappdracutmodules/libraries/modscan.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
'kernel-core',
3232
'kernel-modules',
3333
'keyutils',
34+
'kmod',
3435
'lldpad',
3536
'lvm2',
3637
'mdadm',

repos/system_upgrade/common/actors/initramfs/checkinitramfstasks/libraries/checkinitramfstasks.py

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
from leapp.models import TargetInitramfsTasks, UpgradeInitramfsTasks
77

88
DRACUT_MOD_DIR = '/usr/lib/dracut/modules.d/'
9-
SUMMARY_DRACUT_FMT = (
10-
'The requested dracut modules for the initramfs are in conflict.'
11-
' At least one dracut module is specified to be installed from'
12-
' multiple paths. The list of conflicting dracut module names'
13-
' with paths is listed below: {}'
9+
SUMMARY_FMT = (
10+
'The requested {kind} modules for the initramfs are in conflict.'
11+
' At least one {kind} module is specified to be installed from'
12+
' multiple paths. The list of conflicting {kind} module names'
13+
' with paths is listed below: {conflicts}'
1414
)
1515

1616

@@ -22,51 +22,68 @@ def _printable_modules(conflicts):
2222
return ''.join(output)
2323

2424

25-
def _treat_path(dmodule):
25+
def _treat_path_dracut(dmodule):
2626
"""
2727
In case the path is not set, set the expected path of the dracut module.
2828
"""
29+
2930
if not dmodule.module_path:
3031
return os.path.join(DRACUT_MOD_DIR, dmodule.name)
3132
return dmodule.module_path
3233

3334

34-
def _detect_dracut_modules_conflicts(msgtype):
35+
def _treat_path_kernel(kmodule):
36+
"""
37+
In case the path of a kernel module is not set, indicate that the module is
38+
taken from the current system.
39+
"""
40+
41+
if not kmodule.module_path:
42+
return kmodule.name + ' (system)'
43+
return kmodule.module_path
44+
45+
46+
def _detect_modules_conflicts(msgtype, kind):
3547
"""
3648
Return dict of modules with conflicting tasks
3749
38-
In this case when a dracut module should be applied but different
39-
sources are specified. E.g.:
40-
include dracut modules X where,
50+
In this case when a module should be applied but different sources are
51+
specified. E.g.:
52+
include modules X where,
4153
msg A) X
4254
msg B) X from custom path
4355
"""
44-
dracut_modules = defaultdict(set)
56+
57+
modules_map = {
58+
'dracut': {
59+
'msgattr': 'include_dracut_modules',
60+
'treat_path_fn': _treat_path_dracut,
61+
},
62+
'kernel': {
63+
'msgattr': 'include_kernel_modules',
64+
'treat_path_fn': _treat_path_kernel
65+
},
66+
}
67+
68+
modules = defaultdict(set)
4569
for msg in api.consume(msgtype):
46-
for dmodule in msg.include_dracut_modules:
47-
dracut_modules[dmodule.name].add(_treat_path(dmodule))
48-
return {key: val for key, val in dracut_modules.items() if len(val) > 1}
70+
for module in getattr(msg, modules_map[kind]['msgattr']):
71+
treat_path_fn = modules_map[kind]['treat_path_fn']
72+
modules[module.name].add(treat_path_fn(module))
73+
return {key: val for key, val in modules.items() if len(val) > 1}
4974

5075

5176
def process():
52-
conflicts = _detect_dracut_modules_conflicts(UpgradeInitramfsTasks)
53-
if conflicts:
54-
report = [
55-
reporting.Title('Conflicting requirements of dracut modules for the upgrade initramfs'),
56-
reporting.Summary(SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
57-
reporting.Severity(reporting.Severity.HIGH),
58-
reporting.Groups([reporting.Groups.SANITY]),
59-
reporting.Groups([reporting.Groups.INHIBITOR]),
60-
]
61-
reporting.create_report(report)
62-
63-
conflicts = _detect_dracut_modules_conflicts(TargetInitramfsTasks)
64-
if conflicts:
65-
report = [
66-
reporting.Title('Conflicting requirements of dracut modules for the target initramfs'),
67-
reporting.Summary(SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
68-
reporting.Severity(reporting.Severity.HIGH),
69-
reporting.Groups([reporting.Groups.SANITY]),
70-
reporting.Groups([reporting.Groups.INHIBITOR]),
71-
]
72-
reporting.create_report(report)
77+
groups = [('upgrade', 'kernel', UpgradeInitramfsTasks), ('upgrade', 'dracut', UpgradeInitramfsTasks),
78+
('target', 'dracut', TargetInitramfsTasks)]
79+
for (msgname, kind, msgtype) in groups:
80+
conflicts = _detect_modules_conflicts(msgtype, kind)
81+
if conflicts:
82+
report = [
83+
reporting.Title('Conflicting requirements of {kind} modules for the {msgname} initramfs'.format(
84+
kind=kind, msgname=msgname)),
85+
reporting.Summary(SUMMARY_FMT.format(kind=kind, conflicts=_printable_modules(conflicts))),
86+
reporting.Severity(reporting.Severity.HIGH),
87+
reporting.Groups([reporting.Groups.SANITY, reporting.Groups.INHIBITOR]),
88+
]
89+
reporting.create_report(report)

repos/system_upgrade/common/actors/initramfs/checkinitramfstasks/tests/unit_test_checkinitramfstasks.py

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
from leapp.libraries.actor import checkinitramfstasks
77
from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
88
from leapp.libraries.stdlib import api
9-
from leapp.models import DracutModule, Report, TargetInitramfsTasks, UpgradeInitramfsTasks
9+
from leapp.models import DracutModule, KernelModule, TargetInitramfsTasks, UpgradeInitramfsTasks
1010
from leapp.utils.report import is_inhibitor
1111

1212

1313
def gen_UIT(modules):
1414
if not isinstance(modules, list):
1515
modules = [modules]
1616
dracut_modules = [DracutModule(name=i[0], module_path=i[1]) for i in modules]
17-
return UpgradeInitramfsTasks(include_dracut_modules=dracut_modules)
17+
kernel_modules = [KernelModule(name=i[0], module_path=i[1]) for i in modules]
18+
return UpgradeInitramfsTasks(include_dracut_modules=dracut_modules, include_kernel_modules=kernel_modules)
1819

1920

2021
def gen_TIT(modules):
@@ -71,9 +72,57 @@ def gen_TIT(modules):
7172
TargetInitramfsTasks,
7273
),
7374
])
74-
def test_conflict_detection(monkeypatch, expected_res, input_msgs, test_msg_type):
75+
def test_dracut_conflict_detection(monkeypatch, expected_res, input_msgs, test_msg_type):
7576
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=input_msgs))
76-
res = checkinitramfstasks._detect_dracut_modules_conflicts(test_msg_type)
77+
res = checkinitramfstasks._detect_modules_conflicts(test_msg_type, 'dracut')
78+
assert res == expected_res
79+
80+
81+
@pytest.mark.parametrize('expected_res,input_msgs,test_msg_type', [
82+
(
83+
{},
84+
[],
85+
UpgradeInitramfsTasks,
86+
),
87+
(
88+
{},
89+
[gen_UIT([('modA', 'pathA'), ('modB', 'pathB')])],
90+
UpgradeInitramfsTasks,
91+
),
92+
(
93+
{},
94+
[gen_UIT([('modA', 'pathA'), ('modA', 'pathA')])],
95+
UpgradeInitramfsTasks,
96+
),
97+
(
98+
{'modA': {'pathA', 'pathB'}},
99+
[gen_UIT([('modA', 'pathA'), ('modA', 'pathB')])],
100+
UpgradeInitramfsTasks,
101+
),
102+
(
103+
{'modA': {'pathA', 'pathB'}},
104+
[gen_UIT(('modA', 'pathA')), gen_UIT(('modA', 'pathB'))],
105+
UpgradeInitramfsTasks,
106+
),
107+
(
108+
{'modA': {'pathA', 'pathB'}},
109+
[gen_UIT([('modA', 'pathA'), ('modA', 'pathB'), ('modB', 'pathC')])],
110+
UpgradeInitramfsTasks,
111+
),
112+
(
113+
{'modA': {'modA (system)', 'pathB'}},
114+
[gen_UIT([('modA', None), ('modA', 'pathB')])],
115+
UpgradeInitramfsTasks,
116+
),
117+
(
118+
{},
119+
[gen_UIT([('modA', 'pathA'), ('modA', 'pathB')])],
120+
TargetInitramfsTasks,
121+
),
122+
])
123+
def test_kernel_conflict_detection(monkeypatch, expected_res, input_msgs, test_msg_type):
124+
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=input_msgs))
125+
res = checkinitramfstasks._detect_modules_conflicts(test_msg_type, 'kernel')
77126
assert res == expected_res
78127

79128

repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/files/generate-initram.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ build() {
6767
DRACUT_MODULES_ADD=$(echo "--add $LEAPP_ADD_DRACUT_MODULES" | sed 's/,/ --add /g')
6868
fi
6969

70+
KERNEL_MODULES_ADD=""
71+
if [[ -n "$LEAPP_ADD_KERNEL_MODULES" ]]; then
72+
depmod "${KERNEL_VERSION}" -a
73+
KERNEL_MODULES_ADD=$(
74+
echo "--add-drivers $LEAPP_ADD_KERNEL_MODULES" |
75+
sed 's/,/ --add-drivers /g'
76+
)
77+
fi
78+
7079
DRACUT_INSTALL="systemd-nspawn"
7180
if [[ -n "$LEAPP_DRACUT_INSTALL_FILES" ]]; then
7281
DRACUT_INSTALL="$DRACUT_INSTALL $LEAPP_DRACUT_INSTALL_FILES"
@@ -89,6 +98,7 @@ build() {
8998
--confdir "$DRACUT_CONF_DIR" \
9099
--install "$DRACUT_INSTALL" \
91100
$DRACUT_MODULES_ADD \
101+
$KERNEL_MODULES_ADD \
92102
"$DRACUT_MDADMCONF_ARG" \
93103
"$DRACUT_LVMCONF_ARG" \
94104
--no-hostonly \

0 commit comments

Comments
 (0)