[node-patches] Change in ovirt-node[ovirt-3.6]: update: Make sure to use the right kernel modules

fabiand at redhat.com fabiand at redhat.com
Thu Oct 22 17:59:19 UTC 2015


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 <fabiand at fedoraproject.org>
---
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 <fabiand at redhat.com>
Gerrit-Reviewer: Fabian Deutsch <fabiand at redhat.com>



More information about the node-patches mailing list