-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
check_grub_legacy: inhibit when GRUB legacy is present
Adds a new actor checking for whether any of the GRUB devices have the old GRUB Legacy installed. If any of such devices is detected, the upgrade is inhibited. The GRUB Legacy is detected by searching for the string 'GRUB version 0.94' in `file -s` of the device.
- Loading branch information
Showing
3 changed files
with
136 additions
and
0 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
repos/system_upgrade/el7toel8/actors/checklegacygrub/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import check_legacy_grub as check_legacy_grub_lib | ||
from leapp.reporting import Report | ||
from leapp.tags import FactsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class CheckLegacyGrub(Actor): | ||
""" | ||
Check whether GRUB Legacy is installed in the MBR. | ||
GRUB Legacy is deprecated since RHEL 7 in favour of GRUB2. | ||
""" | ||
|
||
name = 'check_grub_legacy' | ||
consumes = () | ||
produces = (Report,) | ||
tags = (FactsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
check_legacy_grub_lib.check_grub_disks_for_legacy_grub() |
71 changes: 71 additions & 0 deletions
71
repos/system_upgrade/el7toel8/actors/checklegacygrub/libraries/check_legacy_grub.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
from leapp import reporting | ||
from leapp.exceptions import StopActorExecution | ||
from leapp.libraries.common import grub as grub_lib | ||
from leapp.libraries.stdlib import api, CalledProcessError, run | ||
from leapp.reporting import create_report | ||
|
||
# There is no grub legacy package on RHEL7, therefore, the system must have been upgraded from RHEL6 | ||
MIGRATION_TO_GRUB2_GUIDE_URL = 'https://access.redhat.com/solutions/2643721' | ||
|
||
|
||
def has_legacy_grub(device): | ||
try: | ||
output = run(['file', '-s', device]) | ||
except CalledProcessError as err: | ||
msg = 'Failed to determine the file type for the special device `{0}`. Full error: `{1}`' | ||
api.current_logger().warning(msg.format(device, str(err))) | ||
|
||
# According to `file` manpage, the exit code > 0 iff the file does not exists (meaning) | ||
# that grub_lib.get_grub_devices() is unreliable for some reason (better stop the upgrade), | ||
# or because the file type could not be determined. However, its manpage directly gives examples | ||
# of file -s being used on block devices, so this should be unlikely - especially if one would | ||
# consider that get_grub_devices was able to determine that it is a grub device. | ||
raise StopActorExecution() | ||
|
||
grub_legacy_version_string = 'GRUB version 0.94' | ||
return grub_legacy_version_string in output['stdout'] | ||
|
||
|
||
def check_grub_disks_for_legacy_grub(): | ||
# Both GRUB2 and Grub Legacy are recognized by `get_grub_devices` | ||
grub_devices = grub_lib.get_grub_devices() | ||
|
||
legacy_grub_devices = [] | ||
for device in grub_devices: | ||
if has_legacy_grub(device): | ||
legacy_grub_devices.append(device) | ||
|
||
if legacy_grub_devices: | ||
details = ( | ||
'Leapp detected GRUB Legacy to be installed on the system. ' | ||
'The GRUB Legacy bootloader is unsupported on RHEL7 and GRUB2 must be used instead. ' | ||
'The presence of GRUB Legacy is possible on systems that have been upgraded from RHEL 6 in the past, ' | ||
'but required manual post-upgrade steps have not been performed. ' | ||
'Note that the in-place upgrade from RHEL 6 to RHEL 7 systems is in such a case ' | ||
'considered as unfinished.\n\n' | ||
|
||
'GRUB Legacy has been detected on following devices:\n' | ||
'{block_devices_fmt}\n' | ||
) | ||
|
||
hint = ( | ||
'Migrate to the GRUB2 bootloader on the reported devices. ' | ||
'Also finish other post-upgrade steps related to the previous in-place upgrade, the majority of which ' | ||
'is a part of the related preupgrade report for upgrades from RHEL 6 to RHEL 7.' | ||
'If you are not sure whether all previously required post-upgrade steps ' | ||
'have been performed, consider a clean installation of the RHEL 8 system instead. ' | ||
'Note that the in-place upgrade to RHEL 8 can fail in various ways ' | ||
'if the RHEL 7 system is misconfigured.' | ||
) | ||
|
||
block_devices_fmt = '\n'.join(legacy_grub_devices) | ||
create_report([ | ||
reporting.Title("GRUB Legacy is used on the system"), | ||
reporting.Summary(details.format(block_devices_fmt=block_devices_fmt)), | ||
reporting.Severity(reporting.Severity.HIGH), | ||
reporting.Groups([reporting.Groups.BOOT]), | ||
reporting.Remediation(hint=hint), | ||
reporting.Groups([reporting.Groups.INHIBITOR]), | ||
reporting.ExternalLink(url=MIGRATION_TO_GRUB2_GUIDE_URL, | ||
title='How to install GRUB2 after a RHEL6 to RHEL7 upgrade'), | ||
]) |
45 changes: 45 additions & 0 deletions
45
repos/system_upgrade/el7toel8/actors/checklegacygrub/tests/test_check_legacy_grub.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import pytest | ||
|
||
from leapp.libraries.actor import check_legacy_grub as check_legacy_grub_lib | ||
from leapp.libraries.common import grub as grub_lib | ||
from leapp.libraries.common.testutils import create_report_mocked | ||
from leapp.utils.report import is_inhibitor | ||
|
||
VDA_WITH_LEGACY_GRUB = ( | ||
'/dev/vda: x86 boot sector; GRand Unified Bootloader, stage1 version 0x3, ' | ||
'stage2 address 0x2000, stage2 segment 0x200, GRUB version 0.94; partition 1: ID=0x83, ' | ||
'active, starthead 32, startsector 2048, 1024000 sectors; partition 2: ID=0x83, starthead 221, ' | ||
'startsector 1026048, 19945472 sectors, code offset 0x48\n' | ||
) | ||
|
||
NVME0N1_VDB_WITH_GRUB = ( | ||
'/dev/nvme0n1: x86 boot sector; partition 1: ID=0x83, active, starthead 32, startsector 2048, 6291456 sectors; ' | ||
'partition 2: ID=0x83, starthead 191, startsector 6293504, 993921024 sectors, code offset 0x63' | ||
) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('grub_device_to_file_output', 'should_inhibit'), | ||
[ | ||
({'/dev/vda': VDA_WITH_LEGACY_GRUB}, True), | ||
({'/dev/nvme0n1': NVME0N1_VDB_WITH_GRUB}, False), | ||
({'/dev/vda': VDA_WITH_LEGACY_GRUB, '/dev/nvme0n1': NVME0N1_VDB_WITH_GRUB}, True) | ||
] | ||
) | ||
def test_check_legacy_grub(monkeypatch, grub_device_to_file_output, should_inhibit): | ||
|
||
def file_cmd_mock(cmd, *args, **kwargs): | ||
assert cmd[:2] == ['file', '-s'] | ||
return {'stdout': grub_device_to_file_output[cmd[2]]} | ||
|
||
monkeypatch.setattr(check_legacy_grub_lib, 'create_report', create_report_mocked()) | ||
monkeypatch.setattr(grub_lib, 'get_grub_devices', lambda: list(grub_device_to_file_output.keys())) | ||
monkeypatch.setattr(check_legacy_grub_lib, 'run', file_cmd_mock) | ||
|
||
check_legacy_grub_lib.check_grub_disks_for_legacy_grub() | ||
|
||
assert bool(check_legacy_grub_lib.create_report.called) == should_inhibit | ||
if should_inhibit: | ||
assert len(check_legacy_grub_lib.create_report.reports) == 1 | ||
report = check_legacy_grub_lib.create_report.reports[0] | ||
assert is_inhibitor(report) |