Skip to content

Commit 91b0bc3

Browse files
author
mhecko
committed
refactor handling of kernel-related information
Refactor the handling of kernel-related information away from using distributed ad-hoc logic based only on kernel release in IPUConfiguration. Instead, introduce the KernelInfo message providing rich information about the booted kernel. These changes also affect the information about the target kernel which previously only included target kernel's nevra that was misleadingly marked as 'version'. The new target kernel info message also contains paths to frequently used files such as the kernel image path and initramfs location. All old functionality has been kept in place, but deprecated.
1 parent 34d4629 commit 91b0bc3

File tree

21 files changed

+726
-402
lines changed

21 files changed

+726
-402
lines changed

repos/system_upgrade/common/actors/forcedefaultboottotargetkernelversion/actor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from leapp.actors import Actor
22
from leapp.libraries.actor import forcedefaultboot
3-
from leapp.models import InstalledTargetKernelVersion
3+
from leapp.models import InstalledTargetKernelInfo
44
from leapp.tags import FinalizationPhaseTag, IPUWorkflowTag
55

66

@@ -14,7 +14,7 @@ class ForceDefaultBootToTargetKernelVersion(Actor):
1414
"""
1515

1616
name = 'force_default_boot_to_target_kernel_version'
17-
consumes = (InstalledTargetKernelVersion,)
17+
consumes = (InstalledTargetKernelInfo,)
1818
produces = ()
1919
tags = (FinalizationPhaseTag, IPUWorkflowTag)
2020

repos/system_upgrade/common/actors/forcedefaultboottotargetkernelversion/libraries/forcedefaultboot.py

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,33 @@
1-
import os
2-
from collections import namedtuple
3-
41
from leapp.libraries import stdlib
52
from leapp.libraries.common.config import architecture
63
from leapp.libraries.stdlib import api, config
7-
from leapp.models import InstalledTargetKernelVersion
8-
9-
KernelInfo = namedtuple('KernelInfo', ('kernel_path', 'initrd_path'))
10-
11-
12-
def get_kernel_info(message):
13-
kernel_name = 'vmlinuz-{}'.format(message.version)
14-
initrd_name = 'initramfs-{}.img'.format(message.version)
15-
kernel_path = os.path.join('/boot', kernel_name)
16-
initrd_path = os.path.join('/boot', initrd_name)
17-
18-
target_version_bootable = True
19-
if not os.path.exists(kernel_path):
20-
target_version_bootable = False
21-
api.current_logger().warning('Mandatory kernel %s does not exist', kernel_path)
22-
if not os.path.exists(initrd_path):
23-
target_version_bootable = False
24-
api.current_logger().warning('Mandatory initrd %s does not exist', initrd_path)
25-
26-
if target_version_bootable:
27-
return KernelInfo(kernel_path=kernel_path, initrd_path=initrd_path)
28-
29-
api.current_logger().warning('Skipping check due to missing mandatory files')
30-
return None
4+
from leapp.models import InstalledTargetKernelInfo
315

326

337
def update_default_kernel(kernel_info):
348
try:
35-
stdlib.run(['grubby', '--info', kernel_info.kernel_path])
9+
stdlib.run(['grubby', '--info', kernel_info.kernel_img_path])
3610
except stdlib.CalledProcessError:
3711
api.current_logger().error('Expected kernel %s to be installed at the boot loader but cannot be found.',
38-
kernel_info.kernel_path)
12+
kernel_info.kernel_img_path)
3913
except OSError:
4014
api.current_logger().error('Could not check for kernel existence in boot loader. Is grubby installed?')
4115
else:
4216
try:
43-
stdlib.run(['grubby', '--set-default', kernel_info.kernel_path])
17+
stdlib.run(['grubby', '--set-default', kernel_info.kernel_img_path])
4418
if architecture.matches_architecture(architecture.ARCH_S390X):
4519
# on s390x we need to call zipl explicitly because of issue in grubby,
4620
# otherwise the new boot entry will not be set as default
4721
# See https://bugzilla.redhat.com/show_bug.cgi?id=1764306
4822
stdlib.run(['/usr/sbin/zipl'])
4923
except (OSError, stdlib.CalledProcessError):
50-
api.current_logger().error('Failed to set default kernel to: %s', kernel_info.kernel_path, exc_info=True)
24+
api.current_logger().error('Failed to set default kernel to: %s',
25+
kernel_info.kernel_img_path, exc_info=True)
5126

5227

5328
def process():
54-
if (config.is_debug and not
55-
architecture.matches_architecture(architecture.ARCH_S390X)): # pylint: disable=using-constant-test
29+
is_system_s390x = architecture.matches_architecture(architecture.ARCH_S390X)
30+
if config.is_debug and not is_system_s390x: # pylint: disable=using-constant-test
5631
try:
5732
# the following command prints output of grubenv for debugging purposes and is repeated after setting
5833
# default kernel so we can be sure we have the right saved entry
@@ -65,12 +40,18 @@ def process():
6540
stdlib.run(['grub2-editenv', 'list'])
6641
except stdlib.CalledProcessError:
6742
api.current_logger().error('Failed to execute "grub2-editenv list" command')
68-
message = next(api.consume(InstalledTargetKernelVersion), None)
69-
if not message:
43+
44+
kernel_info = next(api.consume(InstalledTargetKernelInfo), None)
45+
if not kernel_info:
7046
api.current_logger().warning(('Skipped - Forcing checking and setting default boot entry to target kernel'
7147
' version due to missing message'))
7248
return
7349

50+
if not kernel_info.kernel_img_path: # Should be always set
51+
api.current_logger().warning(('Skipping forcing of default boot entry - target kernel info '
52+
'does not contain a kernel image path.'))
53+
return
54+
7455
try:
7556
current_default_kernel = stdlib.run(['grubby', '--default-kernel'])['stdout'].strip()
7657
except (OSError, stdlib.CalledProcessError):
@@ -84,17 +65,12 @@ def process():
8465
api.current_logger().warning('Failed to query grubby for default {}'.format(type_), exc_info=True)
8566
return
8667

87-
kernel_info = get_kernel_info(message)
88-
if not kernel_info:
89-
return
90-
91-
if current_default_kernel != kernel_info.kernel_path:
68+
if current_default_kernel != kernel_info.kernel_img_path:
9269
api.current_logger().warning(('Current default boot entry not target kernel version: Current default: %s.'
9370
'Forcing default kernel to %s'),
94-
current_default_kernel, kernel_info.kernel_path)
71+
current_default_kernel, kernel_info.kernel_img_path)
9572
update_default_kernel(kernel_info)
96-
if (config.is_debug and not
97-
architecture.matches_architecture(architecture.ARCH_S390X)): # pylint: disable=using-constant-test
73+
if config.is_debug and not is_system_s390x: # pylint: disable=using-constant-test
9874
try:
9975
stdlib.run(['grub2-editenv', 'list'])
10076
except stdlib.CalledProcessError:

repos/system_upgrade/common/actors/forcedefaultboottotargetkernelversion/tests/test_forcedefaultboot_forcedefaultboottotargetkernelversion.py

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from leapp.libraries.common.config import architecture
99
from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked
1010
from leapp.libraries.stdlib import api
11-
from leapp.models import InstalledTargetKernelVersion
11+
from leapp.models import InstalledTargetKernelInfo
1212

1313
Expected = namedtuple(
1414
'Expected', (
@@ -19,15 +19,15 @@
1919

2020
Case = namedtuple(
2121
'Case',
22-
('initrd_exists',
23-
'kernel_exists',
22+
('kernel_exists',
2423
'entry_default',
2524
'entry_exists',
2625
'message_available',
2726
'arch_s390x'
2827
)
2928
)
3029

30+
TARGET_KERNEL_NEVRA = 'kernel-core-1.2.3.4.el8.x86_64'
3131
TARGET_KERNEL_VERSION = '1.2.3.4.el8.x86_64'
3232
TARGET_KERNEL_TITLE = 'Red Hat Enterprise Linux ({}) 8.1 (Ootpa)'.format(TARGET_KERNEL_VERSION)
3333
TARGET_KERNEL_PATH = '/boot/vmlinuz-{}'.format(TARGET_KERNEL_VERSION)
@@ -37,48 +37,27 @@
3737
OLD_KERNEL_TITLE = 'Red Hat Enterprise Linux ({}) 7.6 (Maipo)'.format(OLD_KERNEL_VERSION)
3838
OLD_KERNEL_PATH = '/boot/vmlinuz-{}'.format(OLD_KERNEL_VERSION)
3939

40+
4041
CASES = (
41-
(Case(initrd_exists=True, kernel_exists=True, entry_default=True, entry_exists=True, message_available=True,
42-
arch_s390x=False),
43-
Expected(grubby_setdefault=False, zipl_called=False)),
44-
(Case(initrd_exists=False, kernel_exists=True, entry_default=False, entry_exists=True, message_available=True,
45-
arch_s390x=False),
46-
Expected(grubby_setdefault=False, zipl_called=False)),
47-
(Case(initrd_exists=True, kernel_exists=False, entry_default=False, entry_exists=True, message_available=True,
48-
arch_s390x=False),
42+
(Case(kernel_exists=True, entry_default=True, entry_exists=True, message_available=True, arch_s390x=False),
4943
Expected(grubby_setdefault=False, zipl_called=False)),
50-
(Case(initrd_exists=False, kernel_exists=False, entry_default=False, entry_exists=True, message_available=True,
51-
arch_s390x=False),
44+
(Case(kernel_exists=False, entry_default=False, entry_exists=True, message_available=True, arch_s390x=False),
5245
Expected(grubby_setdefault=False, zipl_called=False)),
53-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=True, message_available=False,
54-
arch_s390x=False),
46+
(Case(kernel_exists=True, entry_default=False, entry_exists=True, message_available=False, arch_s390x=False),
5547
Expected(grubby_setdefault=False, zipl_called=False)),
56-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=False, message_available=False,
57-
arch_s390x=False),
48+
(Case(kernel_exists=True, entry_default=False, entry_exists=False, message_available=False, arch_s390x=False),
5849
Expected(grubby_setdefault=False, zipl_called=False)),
59-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=True, message_available=True,
60-
arch_s390x=False),
50+
(Case(kernel_exists=True, entry_default=False, entry_exists=True, message_available=True, arch_s390x=False),
6151
Expected(grubby_setdefault=True, zipl_called=False)),
62-
(Case(initrd_exists=True, kernel_exists=True, entry_default=True, entry_exists=True, message_available=True,
63-
arch_s390x=True),
64-
Expected(grubby_setdefault=False, zipl_called=False)),
65-
(Case(initrd_exists=False, kernel_exists=True, entry_default=False, entry_exists=True, message_available=True,
66-
arch_s390x=True),
67-
Expected(grubby_setdefault=False, zipl_called=False)),
68-
(Case(initrd_exists=True, kernel_exists=False, entry_default=False, entry_exists=True, message_available=True,
69-
arch_s390x=True),
52+
(Case(kernel_exists=True, entry_default=True, entry_exists=True, message_available=True, arch_s390x=True),
7053
Expected(grubby_setdefault=False, zipl_called=False)),
71-
(Case(initrd_exists=False, kernel_exists=False, entry_default=False, entry_exists=True, message_available=True,
72-
arch_s390x=True),
54+
(Case(kernel_exists=False, entry_default=False, entry_exists=True, message_available=True, arch_s390x=True),
7355
Expected(grubby_setdefault=False, zipl_called=False)),
74-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=True, message_available=False,
75-
arch_s390x=True),
56+
(Case(kernel_exists=True, entry_default=False, entry_exists=True, message_available=False, arch_s390x=True),
7657
Expected(grubby_setdefault=False, zipl_called=False)),
77-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=False, message_available=False,
78-
arch_s390x=True),
58+
(Case(kernel_exists=True, entry_default=False, entry_exists=False, message_available=False, arch_s390x=True),
7959
Expected(grubby_setdefault=False, zipl_called=False)),
80-
(Case(initrd_exists=True, kernel_exists=True, entry_default=False, entry_exists=True, message_available=True,
81-
arch_s390x=True),
60+
(Case(kernel_exists=True, entry_default=False, entry_exists=True, message_available=True, arch_s390x=True),
8261
Expected(grubby_setdefault=True, zipl_called=True))
8362
)
8463

@@ -143,7 +122,11 @@ def grubby_set_default(self, cmd):
143122
def mocked_consume(case):
144123
def impl(*args):
145124
if case.message_available:
146-
return iter((InstalledTargetKernelVersion(version=TARGET_KERNEL_VERSION),))
125+
kernel_img_path = TARGET_KERNEL_PATH if case.kernel_exists else ''
126+
msg = InstalledTargetKernelInfo(pkg_nevra=TARGET_KERNEL_NEVRA,
127+
kernel_img_path=kernel_img_path,
128+
initramfs_path=TARGET_INITRD_PATH)
129+
return iter((msg,))
147130
return iter(())
148131
return impl
149132

repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def produce_ipu_config(actor):
6868
flavour = os.environ.get('LEAPP_UPGRADE_PATH_FLAVOUR')
6969
target_version = os.environ.get('LEAPP_UPGRADE_PATH_TARGET_RELEASE')
7070
os_release = get_os_release('/etc/os-release')
71+
7172
actor.produce(IPUConfig(
7273
leapp_env_vars=get_env_vars(),
7374
os_release=os_release,

repos/system_upgrade/common/actors/kernel/checkinstalledkernels/actor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from leapp.actors import Actor
22
from leapp.libraries.actor import checkinstalledkernels
3-
from leapp.models import InstalledRedHatSignedRPM
3+
from leapp.models import InstalledRedHatSignedRPM, KernelInfo
44
from leapp.reporting import Report
55
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
66

@@ -30,7 +30,7 @@ class CheckInstalledKernels(Actor):
3030
"""
3131

3232
name = 'check_installed_kernels'
33-
consumes = (InstalledRedHatSignedRPM,)
33+
consumes = (InstalledRedHatSignedRPM, KernelInfo)
3434
produces = (Report,)
3535
tags = (IPUWorkflowTag, ChecksPhaseTag)
3636

repos/system_upgrade/common/actors/kernel/checkinstalledkernels/libraries/checkinstalledkernels.py

Lines changed: 19 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,12 @@ def labelCompare(*args):
1313

1414
from leapp import reporting
1515
from leapp.exceptions import StopActorExecutionError
16-
from leapp.libraries.common.config import architecture, version
16+
from leapp.libraries.common.config import architecture, utils
1717
from leapp.libraries.stdlib import api
18-
from leapp.models import InstalledRedHatSignedRPM
18+
from leapp.models import InstalledRedHatSignedRPM, KernelInfo
1919

2020

21-
def get_current_kernel_version():
22-
"""
23-
Get the version of the running kernel as a string.
24-
"""
25-
return api.current_actor().configuration.kernel.split('-')[0]
26-
27-
28-
def get_current_kernel_release():
29-
"""
30-
Get the release of the current kernel as a string.
31-
"""
32-
return api.current_actor().configuration.kernel.split('-')[1]
33-
34-
35-
def get_current_kernel_evr():
36-
"""
37-
Get a 3-tuple (EVR) of the current booted kernel.
38-
39-
Epoch in this case is always empty string. In case of kernel, epoch is
40-
never expected to be set.
41-
"""
42-
return ('', get_current_kernel_version(), get_current_kernel_release())
43-
44-
45-
def get_pkgs(pkg_name):
21+
def get_all_pkgs_with_name(pkg_name):
4622
"""
4723
Get all installed packages of the given name signed by Red Hat.
4824
"""
@@ -56,17 +32,8 @@ def get_EVR(pkg):
5632
5733
Epoch is always set as an empty string as in case of kernel epoch is not
5834
expected to be set - ever.
59-
60-
The release includes an architecture as well.
61-
"""
62-
return ('', pkg.version, '{}.{}'.format(pkg.release, pkg.arch))
63-
64-
65-
def _get_pkgs_evr(pkgs):
66-
"""
67-
Return 3-tuples (EVR) of the given packages.
6835
"""
69-
return [get_EVR(pkg) for pkg in pkgs]
36+
return ('', pkg.version, pkg.release)
7037

7138

7239
def get_newest_evr(pkgs):
@@ -78,35 +45,22 @@ def get_newest_evr(pkgs):
7845
"""
7946
if not pkgs:
8047
return None
81-
rpms_evr = _get_pkgs_evr(pkgs)
8248

83-
newest_evr = rpms_evr.pop()
84-
for pkg in rpms_evr:
85-
if labelCompare(newest_evr, pkg) < 0:
86-
newest_evr = pkg
87-
return newest_evr
88-
89-
90-
def _get_kernel_rpm_name():
91-
base_name = 'kernel'
92-
if version.is_rhel_realtime():
93-
api.current_logger().info('The Real Time kernel boot detected.')
94-
base_name = 'kernel-rt'
49+
newest_evr = get_EVR(pkgs[0])
50+
for pkg in pkgs:
51+
evr = get_EVR(pkg)
52+
if labelCompare(newest_evr, evr) < 0:
53+
newest_evr = evr
9554

96-
if version.get_source_major_version() == '7':
97-
return base_name
98-
99-
# Since RHEL 8, the kernel|kernel-rt rpm is just a metapackage that even
100-
# does not have to be installed on the system.
101-
# The kernel-core|kernel-rt-core rpm is the one we care about instead.
102-
return '{}-core'.format(base_name)
55+
return newest_evr
10356

10457

10558
def process():
106-
kernel_name = _get_kernel_rpm_name()
107-
pkgs = get_pkgs(kernel_name)
59+
kernel_info = utils.require_exactly_one_message_of_type(KernelInfo)
60+
pkgs = get_all_pkgs_with_name(kernel_info.pkg.name)
61+
10862
if not pkgs:
109-
# Hypothatical, user is not allowed to install any kernel that is not signed by RH
63+
# Hypothetical, user is not allowed to install any kernel that is not signed by RH
11064
# In case we would like to be cautious, we could check whether there are no other
11165
# kernels installed as well.
11266
api.current_logger().error('Cannot find any installed kernel signed by Red Hat.')
@@ -130,13 +84,13 @@ def process():
13084
reporting.RelatedResource('package', 'kernel')
13185
])
13286

133-
current_evr = get_current_kernel_evr()
134-
newest_evr = get_newest_evr(pkgs)
87+
current_kernel_evr = get_EVR(kernel_info.pkg)
88+
newest_kernel_evr = get_newest_evr(pkgs)
13589

136-
api.current_logger().debug('Current kernel EVR: {}'.format(current_evr))
137-
api.current_logger().debug('Newest kernel EVR: {}'.format(newest_evr))
90+
api.current_logger().debug('Current kernel EVR: {}'.format(current_kernel_evr))
91+
api.current_logger().debug('Newest kernel EVR: {}'.format(newest_kernel_evr))
13892

139-
if current_evr != newest_evr:
93+
if current_kernel_evr != newest_kernel_evr:
14094
title = 'Newest installed kernel not in use'
14195
summary = ('To ensure a stable upgrade, the machine needs to be'
14296
' booted into the latest installed kernel.')

0 commit comments

Comments
 (0)