[node-patches] Change in ovirt-node[master]: Add initramfs re-generation during installation

fabiand at redhat.com fabiand at redhat.com
Fri Jun 26 10:48:28 UTC 2015


Fabian Deutsch has uploaded a new change for review.

Change subject: Add initramfs re-generation during installation
......................................................................

Add initramfs re-generation during installation

Previously Node's initramfs was created at build time and never got
changed. This lead to problems in situations where some configuration
(i.e. a multipath configuration) was required in initramfs.
With this patch, the initramfs will be generated at installation time.

Change-Id: I209a82ff6bf10edf0857e362584bc6370081c320
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M ovirt-node.spec.in
M scripts/Makefile.am
A scripts/ovirt-node-update-initramfs
M src/ovirt/node/utils/system.py
M src/ovirtnode/install.py
5 files changed, 122 insertions(+), 40 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/12/42912/1

diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in
index 5867ec7..5b39f18 100644
--- a/ovirt-node.spec.in
+++ b/ovirt-node.spec.in
@@ -1043,6 +1043,7 @@
 %{_sbindir}/persist
 %{_sbindir}/unpersist
 %{_sbindir}/ovirt-node-upgrade
+%{_sbindir}/ovirt-node-update-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/Makefile.am b/scripts/Makefile.am
index 9facb20..7e3f257 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -21,7 +21,8 @@
 dist_sbin_SCRIPTS = \
   persist \
   unpersist \
-  ovirt-node-upgrade.py
+  ovirt-node-upgrade.py \
+  ovirt-node-update-initramfs
 
 dist_bin_SCRIPTS = \
   ovirt-node-setup \
diff --git a/scripts/ovirt-node-update-initramfs b/scripts/ovirt-node-update-initramfs
new file mode 100755
index 0000000..ec724e7
--- /dev/null
+++ b/scripts/ovirt-node-update-initramfs
@@ -0,0 +1,31 @@
+#!/bin/env python
+"""
+The bash logic is:
+mount -oremount,rw /run/initramfs/live
+mount -obind /run/initramfs/live /boot
+
+dracut -f
+
+pushd /boot
+  mv -v initrd0.img initrd0.img.orig
+  mv -v initramfs-* initrd0.img
+popd
+
+umount /boot
+mount -oremount,ro /run/initramfs/live
+"""
+
+import logging
+from ovirt.node.utils import system 
+
+
+log = logging.getLogger()
+
+
+if __name__ == "__main__":
+    stdout = logging.StreamHandler()
+    log.addHandler(stdout)
+    initramfs = system.Initramfs()
+    initramfs.rebuild()
+
+# vim: set sts=4 et:
diff --git a/src/ovirt/node/utils/system.py b/src/ovirt/node/utils/system.py
index 3c99967..74a9860 100644
--- a/src/ovirt/node/utils/system.py
+++ b/src/ovirt/node/utils/system.py
@@ -30,6 +30,7 @@
 import subprocess
 import sys
 import time
+from contextlib import contextmanager
 
 import rpm
 import system_config_keyboard.keyboard
@@ -37,6 +38,7 @@
 from ovirt.node import base, utils
 from ovirt.node.utils import process, parse_varfile
 from ovirt.node.utils.fs import File
+from ovirt.node.utils.process import check_output, check_call
 
 
 LOGGER = logging.getLogger(__name__)
@@ -351,6 +353,32 @@
             else:
                 copy_dir_if_not_exist("%s/%s" % (orig, f), "%s/%s" % (target,
                                                                       f))
+
+
+ at contextmanager
+def mounted_boot():
+    LOGGER.info("Mounting /liveos and /boot")
+    import ovirtnode.ovirtfunctions as ofunc
+
+    ofunc.mount_liveos()
+    if not os.path.ismount("/liveos"):
+        raise RuntimeError("Failed to mount /liveos")
+
+    liveos = Mount("/liveos")
+    boot = Mount(device="/liveos", path="/boot")
+
+    liveos.remount(rw=True)
+    boot.mount("bind")
+
+    if not os.path.ismount("/boot"):
+        raise RuntimeError("Failed to mount /boot")
+
+    # Now run something in this context
+    yield
+
+    boot.umount()
+    liveos.umount()
+    LOGGER.info("Successfully unmounted /liveos and /boot")
 
 
 class NVR(object):
@@ -915,17 +943,18 @@
             LOGGER.exception("Can't remount %s on %s!" % (device,
                                                           self.path))
 
-    def mount(self):
+    def mount(self, options=""):
         if not self.device:
             LOGGER.exception("Can't mount without a device specified")
             raise RuntimeError("No device was specified when Mount() "
                                "was initialized")
 
         fstype = self.fstype if self.fstype else "auto"
+        options = ["-o" + options] if options else []
 
         try:
-            utils.process.check_call(["mount", "-t", fstype,
-                                      self.device, self.path])
+            utils.process.check_call(["mount", "-t", fstype] + options +
+                                     [self.device, self.path])
         except:
             LOGGER.exception("Can't mount %s on %s" % (self.device,
                              self.path))
@@ -1196,3 +1225,57 @@
             vgs = [x.strip() for x in out.split("\n")]
 
         return vgs
+
+
+class Initramfs(base.Base):
+    """This class shallw rap the logic needed to rebuild the initramfs
+
+    The main obstacle is mounting the correct paths.
+    Furthermore we are taking care that now orphans are left over.
+    """
+    def _regenerate_initramfs(self):
+        pri_initrd = "/boot/initrd0.img"
+        new_initrd = pri_initrd + ".new"
+        backup_initrd = pri_initrd + ".old"
+
+        LOGGER.info("Regenerating initramfs "
+                    "'%s' (this can take a while)" % pri_initrd)
+
+        rd_stdout = ""
+        try:
+            rd_stdout = check_output(["dracut", new_initrd],
+                                     stderr=process.PIPE)
+        except:
+            LOGGER.warn("dracut failed to regenerate the initramfs")
+            LOGGER.warn("dracut output: %s" % rd_stdout)
+            raise
+
+        try:
+            check_call(["mv", pri_initrd, backup_initrd])
+            check_call(["mv", new_initrd, pri_initrd])
+        except:
+            LOGGER.warn("Failed to put new initrd in place")
+            if not os.path.exists(pri_initrd):
+                check_call(["mv", backup_initrd, pri_initrd])
+            raise
+        finally:
+            for orph in [backup_initrd, new_initrd]:
+                try:
+                    os.unlink(orph)
+                    LOGGER.debug("Removed orphan: %s" % orph)
+                except:
+                    pass
+
+    def rebuild(self):
+        LOGGER.info("Preparing to regenerate the initramfs")
+        LOGGER.info("The regenreation is performed in-place, "
+                    "the existing initrd will be overwritten")
+        try:
+            with mounted_boot():
+                self._regenerate_initramfs()
+                LOGGER.info("Initramfs regenration completed successfully")
+        except:
+            LOGGER.info("Initramfs regenration failed")
+            raise
+
+# vim: set sts=4 et:
diff --git a/src/ovirtnode/install.py b/src/ovirtnode/install.py
index e125daa..c2b808f 100755
--- a/src/ovirtnode/install.py
+++ b/src/ovirtnode/install.py
@@ -594,42 +594,8 @@
                                                             "rd_NO_MULTIPATH",
                                                             "")
 
-        is_mpath_root = self.disk and self.disk.startswith("/dev/mapper")
-        has_mpath_wwid = "mpath.wwid=" in self.bootparams
-        if is_mpath_root and not has_mpath_wwid:
-            """We need to specify the wwid of the root device if it
-            is using multiple paths to prevent races within dracut.
-            Basically there are two options:
-            1. bake wwid of root device into initrd
-            2. pass wwid of root device on kernel cmdline
-            I choose 2 because it seems to be less invasive.
-            https://bugzilla.redhat.com/show_bug.cgi?id=1152948
-            """
-            lsblkcmd = "lsblk -inls %s | awk 'FNR==2 {print $1}'" % self.disk
-            lsblkproc = _functions.subprocess_closefds(lsblkcmd, shell=True,
-                                                       stdout=subprocess.PIPE,
-                                                       stderr=subprocess.STDOUT)
-            lsblkout, lsblkerr = lsblkproc.communicate()
-            logger.debug("lsblk returned: %s -- %s" % (lsblkout, lsblkerr))
-            if not lsblkout.strip():
-                raise RuntimeError("Failed to determin parent of partition: %s" % self.disk)
-            part_parent = "/dev/mapper/" + lsblkout.strip()
-            logger.debug("lsblk found parent for partition %s: %s" % (self.disk, part_parent))
-
-            wwidcmd = "multipath -ll %s | egrep -o '^.*dm-[0-9]' | cut -d' ' -f1" % part_parent
-            logger.debug("Checking device for multipath: %s" % wwidcmd)
-            wwidproc = _functions.subprocess_closefds(wwidcmd, shell=True,
-                                                      stdout=subprocess.PIPE,
-                                                      stderr=subprocess.STDOUT)
-            wwidout, wwiderr = wwidproc.communicate()
-            logger.debug("multipath returned: %s -- %s" % (wwidout, wwiderr))
-            wwid = wwidout.strip()
-            if wwid:
-                logger.debug("Using multipath wwid: %s" % wwid)
-                self.bootparams += " mpath.wwid=%s" % wwid
-                logger.debug("Cmdline with mpath: %s" % self.bootparams)
-            else:
-                logger.debug("Got NO multipath wwid, not using any")
+        # Update initramfs to pickup multipath wwids
+        _system.Initramfs().rebuild()
 
         if " " in self.disk:
             # workaround for grub setup failing with spaces in dev.name:


-- 
To view, visit https://gerrit.ovirt.org/42912
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I209a82ff6bf10edf0857e362584bc6370081c320
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at redhat.com>



More information about the node-patches mailing list