[PATCH] Restrict payload kernel versions to kernels in the payload (#1074358)

David Shea dshea at redhat.com
Tue Jan 20 19:53:15 UTC 2015


Remove the generic implementation of kernelVersionList from Payload.
Instead, have each payload return an iterable of the kernels that were
actually in the payload. Add a method to the packaging module to handle
version comparisons in the non-package payload types.

Remove rescueKernelList, since the bootloader was the only thing to use
this, so the bootloader can look for resuce kernels on its own.
---
 pyanaconda/bootloader.py            |  7 +++++-
 pyanaconda/packaging/__init__.py    | 44 ++++++++-----------------------------
 pyanaconda/packaging/dnfpayload.py  |  7 ++++++
 pyanaconda/packaging/livepayload.py | 36 ++++++++++++++++++++++++++++++
 pyanaconda/packaging/tarpayload.py  |  8 +++++--
 pyanaconda/packaging/yumpayload.py  |  8 +++++++
 6 files changed, 72 insertions(+), 38 deletions(-)

diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index ac9ac5c..b017265 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -27,6 +27,7 @@ import re
 import struct
 import blivet
 from parted import PARTITION_BIOS_GRUB
+from glob import glob
 
 from pyanaconda import iutil
 from blivet.devicelibs import raid
@@ -2387,7 +2388,11 @@ def writeBootLoader(storage, payload, instClass, ksdata):
         return
 
     # get a list of installed kernel packages
-    kernel_versions = payload.kernelVersionList + payload.rescueKernelList
+    # add whatever rescue kernels we can find to the end
+    kernel_versions = list(payload.kernelVersionList)
+    kernel_versions += glob(iutil.getSysroot() + "/boot/vmlinuz-*-rescue-*")
+    kernel_versions += glob(iutil.getSysroot() + "/boot/efi/EFI/%s/vmlinuz-*-rescue-*" % instClass.efi_dir)
+
     if not kernel_versions:
         log.warning("no kernel was installed -- boot loader config unchanged")
         return
diff --git a/pyanaconda/packaging/__init__.py b/pyanaconda/packaging/__init__.py
index 64985ac..42fe959 100644
--- a/pyanaconda/packaging/__init__.py
+++ b/pyanaconda/packaging/__init__.py
@@ -72,8 +72,15 @@ from pyanaconda.product import productName, productVersion
 import urlgrabber
 urlgrabber.grabber.default_grabber.opts.user_agent = "%s (anaconda)/%s" %(productName, productVersion)
 
+from distutils.version import LooseVersion
+
 REPO_NOT_SET = False
 
+def versionCmp(v1, v2):
+    """ Compare two version number strings. """
+
+    return LooseVersion(v1).__cmp__(LooseVersion(v2))
+
 ###
 ### ERROR HANDLING
 ###
@@ -128,8 +135,6 @@ class Payload(object):
         self.data = data
         self.storage = None
         self.instclass = None
-        self._kernelVersionList = []
-        self._rescueVersionList = []
         self.txID = None
 
     def setup(self, storage, instClass):
@@ -302,29 +307,6 @@ class Payload(object):
         self.data.packages.excludedGroupList.append(grp)
 
     ###
-    ### METHODS FOR WORKING WITH PACKAGES
-    ###
-    def _updateKernelVersionList(self):
-        try:
-            import yum
-        except ImportError:
-            cmpfunc = cmp
-        else:
-            cmpfunc = yum.rpmUtils.miscutils.compareVerOnly
-
-        files = glob(iutil.getSysroot() + "/boot/vmlinuz-*")
-        files.extend(glob(iutil.getSysroot() + "/boot/efi/EFI/%s/vmlinuz-*" % self.instclass.efi_dir))
-
-        versions = sorted((f.split("/")[-1][8:] for f in files if os.path.isfile(f)), cmp=cmpfunc)
-        log.debug("kernel versions: %s", versions)
-
-        # Store regular and rescue kernels separately
-        self._kernelVersionList = (
-                [v for v in versions if "-rescue-" not in v],
-                [v for v in versions if "-rescue-" in v]
-                )
-
-    ###
     ### METHODS FOR QUERYING STATE
     ###
     @property
@@ -334,16 +316,8 @@ class Payload(object):
 
     @property
     def kernelVersionList(self):
-        if not self._kernelVersionList:
-            self._updateKernelVersionList()
-
-        return self._kernelVersionList[0]
-
-    @property
-    def rescueKernelList(self):
-        # do re-scan if looking for rescue kernel
-        self._updateKernelVersionList()
-        return self._kernelVersionList[1]
+        """ An iterator of the kernel versions installed by the payload. """
+        raise NotImplementedError()
 
     ##
     ## METHODS FOR TREE VERIFICATION
diff --git a/pyanaconda/packaging/dnfpayload.py b/pyanaconda/packaging/dnfpayload.py
index d0eb90e..d3c481b 100644
--- a/pyanaconda/packaging/dnfpayload.py
+++ b/pyanaconda/packaging/dnfpayload.py
@@ -818,3 +818,10 @@ class DNFPayload(packaging.PackagePayload):
                 log.error(e)
 
         super(DNFPayload, self).postInstall()
+
+    @property
+    def kernelVersionList(self):
+        return ('%s-%s.%s' % (p.version, p.release, p.arch) for p in
+                sorted(self._base.sack.query().filter(name='kernel'),
+                       cmp=dnf.rpm.miscutils.compareEVR,
+                       key=lambda p: (p.epoch, p.version, p.release)))
diff --git a/pyanaconda/packaging/livepayload.py b/pyanaconda/packaging/livepayload.py
index 17c1bac..1dac9c7 100644
--- a/pyanaconda/packaging/livepayload.py
+++ b/pyanaconda/packaging/livepayload.py
@@ -56,6 +56,7 @@ from blivet.size import Size
 import blivet.util
 from pyanaconda.threads import threadMgr, AnacondaThread
 from pyanaconda.i18n import _
+from pyanaconda.packaging import versionCmp
 
 class LiveImagePayload(ImagePayload):
     """ A LivePayload copies the source image onto the target system. """
@@ -67,6 +68,8 @@ class LiveImagePayload(ImagePayload):
         self.pct_lock = None
         self.source_size = 1
 
+        self._kernelVersionList = []
+
     def setup(self, storage, instClass):
         super(LiveImagePayload, self).setup(storage, instClass)
 
@@ -80,6 +83,9 @@ class LiveImagePayload(ImagePayload):
         if rc != 0:
             raise PayloadInstallError("Failed to mount the install tree")
 
+        # Grab the kernel version list now so it's available after umount
+        self._updateKernelVersionList()
+
         source = iutil.eintr_retry_call(os.statvfs, INSTALL_TREE)
         self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
 
@@ -180,6 +186,17 @@ class LiveImagePayload(ImagePayload):
     def spaceRequired(self):
         return Size(iutil.getDirSize("/")*1024)
 
+    def _updateKernelVersionList(self):
+        files = glob.glob(INSTALL_TREE + "/boot/vmlinuz-*")
+        files.extend(glob.glob(INSTALL_TREE + "/boot/efi/EFI/%s/vmlinuz-*" % self.instclass.efi_dir))
+
+        self._kernelVersionList = sorted([f.split("/")[-1][8:] for f in files
+           if os.path.isfile(f) and "-rescue-" not in f], cmp=versionCmp)
+
+    @property
+    def kernelVersionList(self):
+        return self._kernelVersionList
+
 class URLGrabberProgress(object):
     """ Provide methods for urlgrabber progress."""
     def start(self, filename, url, basename, size, text):
@@ -388,6 +405,7 @@ class LiveImageKSPayload(LiveImagePayload):
 
         # Nothing more to mount
         if not os.path.exists(INSTALL_TREE+"/LiveOS"):
+            self._updateKernelVersionList()
             return
 
         # Mount the first .img in the directory on INSTALL_TREE
@@ -415,6 +433,8 @@ class LiveImageKSPayload(LiveImagePayload):
                 if errorHandler.cb(exn) == ERROR_RAISE:
                     raise exn
 
+            self._updateKernelVersionList()
+
             source = iutil.eintr_retry_call(os.statvfs, INSTALL_TREE)
             self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
 
@@ -493,3 +513,19 @@ class LiveImageKSPayload(LiveImagePayload):
             return Size(self._min_size)
         else:
             return Size(1024*1024*1024)
+
+    @property
+    def kernelVersionList(self):
+        # If it doesn't look like a tarfile use the super's kernelVersionList
+        if not self.is_tarfile:
+            return super(LiveImageKSPayload, self).kernelVersionList
+
+        import tarfile
+        with tarfile.open(self.image_path) as archive:
+            names = archive.getnames()
+
+            # Strip out vmlinuz- from the names
+            kernels = [n.split("/")[-1][8:] for n in names if "boot/vmlinuz-" in n]
+            kernels.sort(cmp=versionCmp)
+
+            return kernels
diff --git a/pyanaconda/packaging/tarpayload.py b/pyanaconda/packaging/tarpayload.py
index b6328e0..3082530 100644
--- a/pyanaconda/packaging/tarpayload.py
+++ b/pyanaconda/packaging/tarpayload.py
@@ -36,7 +36,7 @@ except ImportError:
     log.error("import of tarfile failed")
     tarfile = None
 
-from pyanaconda.packaging import ArchivePayload, PayloadError
+from pyanaconda.packaging import ArchivePayload, PayloadError, versionCmp
 from pyanaconda import iutil
 
 # TarPayload is not yet fully implemented
@@ -73,7 +73,11 @@ class TarPayload(ArchivePayload):
     @property
     def kernelVersionList(self):
         names = self.archive.getnames()
-        kernels = [n for n in names if "boot/vmlinuz-" in n]
+
+        # Strip out vmlinuz- from the names
+        kernels = [n.split("/")[-1][8:] for n in names if "boot/vmlinuz-" in n]
+        kernels.sort(cmp=versionCmp)
+
         return kernels
 
     def install(self):
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
index 742edad..73caa49 100644
--- a/pyanaconda/packaging/yumpayload.py
+++ b/pyanaconda/packaging/yumpayload.py
@@ -988,6 +988,14 @@ reposdir=%s
             else:
                 return environment.groups
 
+    @property
+    def kernelVersionList(self):
+        with _yum_lock:
+            return ("%s-%s.%s" % (p.version, p.release, p.arch) for p in
+                    sorted(self._yum.pkgSack.searchNames(['kernel']),
+                           cmp=yum.rpmUtils.miscutils.compareEVR,
+                           key=lambda p: (p.epoch, p.version, p.release)))
+
     ###
     ### METHODS FOR WORKING WITH GROUPS
     ###
-- 
2.1.0



More information about the anaconda-patches mailing list