Skip to content

Commit

Permalink
Update Grub on component devices if /boot is on md device
Browse files Browse the repository at this point in the history
Previously, if /boot was on md device such as RAID consisting of
multiple partitions on different drives, the part of Grub residing in
the 512 Mb after MBR was only updated for one of the drives. This
resulted in broken Grub.

Now, Grub is updated on all the component devices of an md array if Grub
was already installed on them before the upgrade.
  • Loading branch information
matejmatuska committed Jun 22, 2023
1 parent 948c782 commit 60cc6cd
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 27 deletions.
2 changes: 1 addition & 1 deletion repos/system_upgrade/common/actors/checkgrubcore/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def process(self):
grub_info = next(self.consume(GrubInfo), None)
if not grub_info:
raise StopActorExecutionError('Actor did not receive any GrubInfo message.')
if grub_info.orig_device_name:
if grub_info.orig_devices:
create_report([
reporting.Title(
'GRUB2 core will be automatically updated during the upgrade'
Expand Down
6 changes: 3 additions & 3 deletions repos/system_upgrade/common/actors/scangrubdevice/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def process(self):
if architecture.matches_architecture(architecture.ARCH_S390X):
return

device_name = grub.get_grub_device()
if device_name:
self.produce(GrubInfo(orig_device_name=device_name))
devices = grub.get_grub_devices()
if devices:
self.produce(GrubInfo(orig_devices=devices))
else:
self.produce(GrubInfo())
8 changes: 4 additions & 4 deletions repos/system_upgrade/common/actors/updategrubcore/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class UpdateGrubCore(Actor):
def process(self):
ff = next(self.consume(FirmwareFacts), None)
if ff and ff.firmware == 'bios':
grub_dev = grub.get_grub_device()
if grub_dev:
update_grub_core(grub_dev)
grub_devs = grub.get_grub_devices()
if grub_devs:
update_grub_core(grub_devs)
else:
api.current_logger().warning('Leapp could not detect GRUB on {}'.format(grub_dev))
api.current_logger().warning('Leapp could not detect GRUB devices')
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,39 @@
from leapp.libraries.stdlib import api, CalledProcessError, config, run


def update_grub_core(grub_dev):
def update_grub_core(grub_devs):
"""
Update GRUB core after upgrade from RHEL7 to RHEL8
On legacy systems, GRUB core does not get automatically updated when GRUB packages
are updated.
"""
cmd = ['grub2-install', grub_dev]
if config.is_debug():
cmd += ['-v']
try:
run(cmd)
except CalledProcessError as err:
reporting.create_report([
reporting.Title('GRUB core update failed'),
reporting.Summary(str(err)),
reporting.Groups([reporting.Groups.BOOT]),
reporting.Severity(reporting.Severity.HIGH),
reporting.Remediation(
hint='Please run "grub2-install <GRUB_DEVICE>" manually after upgrade'
)
])
api.current_logger().warning('GRUB core update on {} failed'.format(grub_dev))
raise StopActorExecution()

successful = []
for dev in grub_devs:
cmd = ['grub2-install', dev]
if config.is_debug():
cmd += ['-v']
try:
run(cmd)
except CalledProcessError as err:
reporting.create_report([
reporting.Title('GRUB core update failed'),
reporting.Summary(str(err)),
reporting.Groups([reporting.Groups.BOOT]),
reporting.Severity(reporting.Severity.HIGH),
reporting.Remediation(
hint='Please run "grub2-install <GRUB_DEVICE>" manually after upgrade'
)
])
api.current_logger().warning('GRUB core update on {} failed'.format(dev))
raise StopActorExecution()
else:
successful.append(dev)

reporting.create_report([
reporting.Title('GRUB core successfully updated'),
reporting.Summary('GRUB core on {} was successfully updated'.format(grub_dev)),
reporting.Summary('GRUB core on {} was successfully updated'.format(', '.join(successful))),
reporting.Groups([reporting.Groups.BOOT]),
reporting.Severity(reporting.Severity.INFO)
])
17 changes: 17 additions & 0 deletions repos/system_upgrade/common/libraries/grub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from leapp.exceptions import StopActorExecution
from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.libraries.common import mdraid


def has_grub(blk_dev):
Expand Down Expand Up @@ -59,6 +60,22 @@ def get_boot_partition():
return boot_partition


def get_grub_devices():
boot_device = get_boot_partition()
devices = []
if mdraid.is_mdraid_dev(boot_device):
component_devs = mdraid.get_component_devices(boot_device)
blk_devs = [blk_dev_from_partition(dev) for dev in component_devs]
devices.extend(blk_devs)
else:
devices.append(blk_dev_from_partition(boot_device))

have_grub = [dev for dev in devices if has_grub(dev)]
api.current_logger().info('GRUB is installed on {}'.format(",".join(have_grub)))
return have_grub


# TODO deprecate
def get_grub_device():
"""
Get block device where GRUB is located. We assume GRUB is on the same device
Expand Down
26 changes: 26 additions & 0 deletions repos/system_upgrade/common/libraries/mdraid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from leapp.exceptions import StopActorExecution
from leapp.libraries.stdlib import api, CalledProcessError, run

def is_mdraid_dev(dev):
try:
result = run(['mdadm', '--query', dev])
except CalledProcessError:
api.current_logger().warning(
'Could not check if device is an md device'
)
raise StopActorExecution()
return '--detail' in result['stdout']


def get_component_devices(raid_dev):
try:
result = run(['mdadm', '--detail', '--verbose', '--brief', raid_dev])
except CalledProcessError as err:
api.current_logger().warning(
'Could not get md array component devices: {}'.format(err)
)
raise StopActorExecution()
# example output:
# ARRAY /dev/md0 level=raid1 num-devices=2 metadata=1.2 name=localhost.localdomain:0 UUID=c4acea6e:d56e1598:91822e3f:fb26832c
# devices=/dev/vda1,/dev/vdb1
return result['stdout'].rsplit('=', 2)[-1].strip().split(',')
3 changes: 3 additions & 0 deletions repos/system_upgrade/common/models/grubinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class GrubInfo(Model):
"""
topic = SystemFactsTopic

# TODO deprecate
orig_device_name = fields.Nullable(fields.String())
"""
Original name of the block device where Grub is located.
Expand All @@ -17,3 +18,5 @@ class GrubInfo(Model):
it's recommended to use `leapp.libraries.common.grub.get_grub_device()` anywhere
else.
"""

orig_devices = fields.List(fields.String(), default=[])

0 comments on commit 60cc6cd

Please sign in to comment.