Fabian Deutsch has uploaded a new change for review. Change subject: update: Make sure to use the right kernel modules ......................................................................
update: Make sure to use the right kernel modules The initramfs rebuild suffered from the fact that in the Engine upgrade flow, the running kernel and the modules available in /lib/modules did not match the updated kernel version, this is because the new rootfs would only become effective on the next boot. This is a problem because dracut has assumptions. This patch does some tricks - mainly mounting /lib/modules and /boot into the right places - to enable dracut to work nicely. Change-Id: Ie893e722e24b1dd2e8e41970e16091d83c65dad8 Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1270228 Signed-off-by: Fabian Deutsch <[email protected]> --- M ovirt-node.spec.in R scripts/ovirt-node-rebuild-initramfs M src/ovirt/node/utils/system.py M src/ovirtnode/install.py 4 files changed, 119 insertions(+), 21 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/64/47664/1 diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index fd3c688..5ee4523 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -954,7 +954,7 @@ %{_sbindir}/persist %{_sbindir}/unpersist %{_sbindir}/ovirt-node-upgrade -%{_sbindir}/ovirt-node-update-initramfs +%{_sbindir}/ovirt-node-rebuild-initramfs %{python_sitelib}/ovirt_config_setup %exclude %{python_sitelib}/ovirt_config_setup/cim.py* %exclude %{python_sitelib}/ovirt_config_setup/snmp.py* diff --git a/scripts/ovirt-node-update-initramfs b/scripts/ovirt-node-rebuild-initramfs similarity index 90% rename from scripts/ovirt-node-update-initramfs rename to scripts/ovirt-node-rebuild-initramfs index 6af825f..a7a9871 100755 --- a/scripts/ovirt-node-update-initramfs +++ b/scripts/ovirt-node-rebuild-initramfs @@ -31,7 +31,8 @@ initramfs = system.Initramfs() try: - initramfs.rebuild() + kver = check_output(["uname", "-r"]) + initramfs.rebuild(kver) except: log.exception("Initramfs regeneration failed") sys.exit(1) diff --git a/src/ovirt/node/utils/system.py b/src/ovirt/node/utils/system.py index 472d0bb..4de3a4b 100755 --- a/src/ovirt/node/utils/system.py +++ b/src/ovirt/node/utils/system.py @@ -356,16 +356,23 @@ @contextmanager -def mounted_boot(): - LOGGER.info("Mounting /liveos and /boot") - import ovirtnode.ovirtfunctions as ofunc +def mounted_boot(source="/liveos"): + """Used to mount /boot + Normally /boot is from the /liveos mountpoint, but sometimes it's + elsewhere, thus we have source + """ - ofunc.mount_liveos() - if not os.path.ismount("/liveos"): - raise RuntimeError("Failed to mount /liveos") + LOGGER.info("Mounting %r to /boot" % source) - liveos = Mount("/liveos") - boot = Mount(device="/liveos", path="/boot") + if source == "/liveos": + import ovirtnode.ovirtfunctions as ofunc + ofunc.mount_liveos() + + if not os.path.ismount("/liveos"): + raise RuntimeError("Failed to mount /liveos") + + liveos = Mount(source) + boot = Mount(device=source, path="/boot") liveos.remount(rw=True) boot.mount("bind") @@ -1321,21 +1328,35 @@ The main obstacle is mounting the correct paths. Furthermore we are taking care that now orphans are left over. + + Args: + dracut_chroot: Path for dracut chroot + boot_source: Source where to take /boot from """ + dracut_chroot = None + boot_source = None + + def __init__(self, dracut_chroot="/", boot_source=None): + self.dracut_chroot = dracut_chroot + self.boot_source = boot_source + def try_unlink(self, path): try: os.unlink(path) except OSError as e: LOGGER.warn("Failed to remove %r: %s", path, e) - def _generate_new_initramfs(self, new_initrd): + def _generate_new_initramfs(self, new_initrd, kver): LOGGER.info("Generating new initramfs " - "%r (this can take a while)" % new_initrd) - + "%r for kver %s (this can take a while)" % + (new_initrd, kver)) rd_stdout = "" try: - rd_stdout = check_output(["dracut", new_initrd], - stderr=process.STDOUT) + argv = ["chroot", self.dracut_chroot, + "dracut", "--kver", kver, new_initrd] + LOGGER.debug("Calling: %s" % argv) + + rd_stdout = check_output(argv, stderr=process.STDOUT) except: LOGGER.warn("dracut failed to generate the initramfs") LOGGER.warn("dracut output: %s" % rd_stdout) @@ -1368,16 +1389,17 @@ self.try_unlink(new_initrd) raise - def rebuild(self): + def rebuild(self, kver): pri_initrd = "/boot/initrd0.img" new_initrd = "/var/tmp/initrd0.img.new" LOGGER.info("Preparing to regenerate the initramfs") LOGGER.info("The regenreation will overwrite the " "existing") + LOGGER.info("Rebuilding for kver: %s" % kver) - with mounted_boot(): - self._generate_new_initramfs(new_initrd) + with mounted_boot(source=self.boot_source): + self._generate_new_initramfs(new_initrd, kver) self._install_new_initramfs(new_initrd, pri_initrd) LOGGER.info("Initramfs regenration completed successfully") diff --git a/src/ovirtnode/install.py b/src/ovirtnode/install.py index d59b3a8..5ea1d26 100755 --- a/src/ovirtnode/install.py +++ b/src/ovirtnode/install.py @@ -28,6 +28,7 @@ import re import time import logging +import tempfile OVIRT_VARS = _functions.parse_defaults() from ovirtnode.storage import Storage @@ -675,9 +676,6 @@ else: logger.info("Grub Installation Completed") - # Update initramfs to pickup multipath wwids - _system.Initramfs().rebuild() - if _functions.is_iscsi_install() or _functions.findfs("BootNew"): # copy default for when Root/HostVG is inaccessible(iscsi upgrade) shutil.copy(_functions.OVIRT_DEFAULTS, "/boot") @@ -699,6 +697,81 @@ logger.error("Unable to relabel " + candidate_dev + " to RootUpdate ") return False + _functions.system("udevadm settle --timeout=10") + + # + # Rebuild the initramfs + # A few hacks are needed to prep the chroot + # The general issue is that we need to run dracut in the context fo the new iso + # and that we need to put the initrd in the right place of the new iso. + # These two things make the logic a bit more complicated. + # + mnts = [] + try: + if not _functions.system("blkid -L RootUpdate"): + raise RuntimeError("RootUpdate not found") + + # Let's mount the update fs, and use that kernel version and modules + # We need this work to help dracut + isomnt = tempfile.mkdtemp("RootUpdate") + squashmnt = tempfile.mkdtemp("RootUpdate-LiveOS") + updfs = tempfile.mkdtemp("RootUpdate-LiveOS-Img") + mnts += [isomnt, squashmnt, updfs] + + # Unpack the iso + def _call(args): + logger.debug("Calling: %s" % args) + try: + out = subprocess.check_output(args) + logger.debug("Out: %s" % out) + except Exception as e: + logger.debug("Failed with: %s %s" % (e, e.output)) + raise + + _call(["mount", "LABEL=RootUpdate", isomnt]) + _call(["mount", "%s/LiveOS/squashfs.img" % isomnt, squashmnt]) + _call(["mount", "%s/LiveOS/ext3fs.img" % squashmnt, updfs]) + + # Now mount the update modules into place, and find the + # correct kver + def rbind(path, updfs=updfs): + dst = updfs + "/" + path + logger.debug("Binding %r to %r" % (path, dst)) + _call(["mount", "--rbind", "/" + path, dst]) + return dst + + for path in ["etc", "dev", "proc", "sys", "tmp", "run", "var/tmp"]: + mnts += [rbind(path)] + + upd_kver = str(_functions.passthrough("ls -1 %s/lib/modules" % updfs)).strip() + + if len(upd_kver.splitlines()) != 1: + # It would be very unusual to see more than one kver directory + # in /lib/modules, because our images just contain one kernel + raise RuntimeError("Found more than one kernel version") + + # Update initramfs to pickup multipath wwids + # Let /boot point to the filesystem on the update candidate partition + builder = _system.Initramfs(dracut_chroot=updfs, boot_source=isomnt) + builder.rebuild(kver=upd_kver) + + except Exception as e: + logger.debug("Failed to build initramfs: %s" % e, exc_info=True) + output = getattr(e, "output", "") + if output: + logger.debug("Output: %s" % output) + raise + + + finally: + # Clean up all eventual mounts + pass + # Disabled for now because akward things happen, we leave it to + # systemd to unnmount on reboot + # for mnt in reversed(mnts): + # d = _functions.passthrough("umount -fl %s" % mnt, logger.debug) + # logger.debug("Returned: %s" % d) + _functions.disable_firstboot() if _functions.finish_install(): if _functions.is_firstboot(): @@ -710,3 +783,5 @@ return True else: return False + +# vim: et sts=4 sw=4: -- To view, visit https://gerrit.ovirt.org/47664 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie893e722e24b1dd2e8e41970e16091d83c65dad8 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-node Gerrit-Branch: ovirt-3.6 Gerrit-Owner: Fabian Deutsch <[email protected]> Gerrit-Reviewer: Fabian Deutsch <[email protected]> _______________________________________________ node-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/node-patches
