[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