From 3b2c7ef5f26d19f117f8431daff876421cda0008 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 24 2020 21:55:10 +0000 Subject: [PATCH 1/11] Enforce check of --extlinux in bootloader Previously, extlinux packages were checked even without setting --extlinux in bootloader, which is not the correct behaviour. --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index c6706cb..361b810 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -173,7 +173,7 @@ class ApplianceImageCreator(ImageCreator): if ((not hasattr(self.ks.handler.bootloader, "disabled")) or (hasattr(self.ks.handler.bootloader, "disabled") and self.ks.handler.bootloader.disabled is False)): # check for extlinux in kickstart then grub2 and falling back to grub - if hasattr(self.ks.handler.bootloader, "extlinux"): + if hasattr(self.ks.handler.bootloader, "extlinux") and self.ks.handler.bootloader.extlinux is True: if 'syslinux-extlinux' in packages: self.bootloader = 'extlinux' elif 'extlinux-bootloader' in packages: From 6b2a86ef569ea1674d5a4642912b7ba2419f7407 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 24 2020 22:01:10 +0000 Subject: [PATCH 2/11] Fallback and check for grub if we didn't find extlinux --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index 361b810..dbf0ebb 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -180,7 +180,7 @@ class ApplianceImageCreator(ImageCreator): self.bootloader = 'extlinux-bootloader' else: logging.warning("WARNING! syslinux-extlinux package not found.") - else: + if self.bootloader is None: if 'grub2' in packages: self.bootloader = 'grub2' partition_layout = 'gpt' From 8f97457beb821809e87666161b91f9788d10c61e Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 24 2020 22:01:48 +0000 Subject: [PATCH 3/11] Honor the partition type set in kickstart The only "forced" case remaining is that we select msdos if extlinux is being used. If nothing is selected, the default is msdos, just as before --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index dbf0ebb..8c0c519 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -168,7 +168,7 @@ class ApplianceImageCreator(ImageCreator): # Search for bootloader package in package list packages = kickstart.get_packages(self.ks) # make this the default - partition_layout = 'msdos' + partition_layout = None # set bootloader only if it is enabled and use user specified partition_layout if ((not hasattr(self.ks.handler.bootloader, "disabled")) or (hasattr(self.ks.handler.bootloader, "disabled") and self.ks.handler.bootloader.disabled is False)): @@ -176,23 +176,33 @@ class ApplianceImageCreator(ImageCreator): if hasattr(self.ks.handler.bootloader, "extlinux") and self.ks.handler.bootloader.extlinux is True: if 'syslinux-extlinux' in packages: self.bootloader = 'extlinux' + partition_layout = 'msdos' elif 'extlinux-bootloader' in packages: self.bootloader = 'extlinux-bootloader' + partition_layout = 'msdos' else: logging.warning("WARNING! syslinux-extlinux package not found.") if self.bootloader is None: if 'grub2' in packages: self.bootloader = 'grub2' - partition_layout = 'gpt' elif 'grub' in packages: self.bootloader = 'grub' else: logging.warning("WARNING! grub package not found.") else: # user explicitly disabled bootloader (i.e. not part of disk image) - if hasattr(self.ks.handler.clearpart, "disklabel"): + pass + + # Determine partition type if it was not forced + if partition_layout is None: + if (hasattr(self.ks.handler.clearpart, "disklabel") + and self.ks.handler.clearpart.disklabel is not None and self.ks.handler.clearpart.disklabel != ""): logging.debug("Using user set default disk label: {}".format(self.ks.handler.clearpart.disklabel)) partition_layout = self.ks.handler.clearpart.disklabel + else: + partition_layout = 'msdos' + else: + logging.debug("Forcing disk label to %s, because bootloader is %s" % (partition_layout, self.bootloader)) self.__instloop = PartitionedMount(self.__disks, self._instroot, From 68159901a71908c52d200f8e732b150bf8072a4d Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 25 2020 13:29:36 +0000 Subject: [PATCH 4/11] Set boot flag in /boot/efi instead of /boot, if it exists --- diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index b2b0413..e251e74 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -255,6 +255,11 @@ class PartitionedMount(Mount): self.__map_partitions() self.__calculate_mountorder() + boot_flag_mp = "/boot" + if "/boot/efi" in self.mountOrder: + boot_flag_mp = "/boot/efi" + + for mp in self.mountOrder: p = None for p1 in self.partitions: @@ -270,7 +275,8 @@ class PartitionedMount(Mount): p['UUID'] = self.__getuuid(p['device']) continue - if mp == '/boot': + if mp == boot_flag_mp: + logging.debug("Setting boot flag on in %s" % mp) # mark the partition bootable subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", str(p['num']), "boot", "on"]) From 24a9254106af053da997590b6429c28e8272f669 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 25 2020 13:30:25 +0000 Subject: [PATCH 5/11] Whitespace cleanup --- diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index e251e74..5dc47b9 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -120,7 +120,7 @@ class PartitionedMount(Mount): # XXX disabled return code check because parted always fails to # reload part table with loop devices. Annoying because we can't # distinguish this failure from real partition failures :-( - #if rc != 0 and 1 == 0: + #if rc != 0 and 1 == 0: # raise MountError("Error creating partition on %s" % d['disk'].device) def __map_partitions(self): From 65fb61f41f05ef43ed5f5685c5c5ec63f9f542ec Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 25 2020 17:14:55 +0000 Subject: [PATCH 6/11] Support EFI as filesystem --- diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index 5dc47b9..9d863c1 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -108,12 +108,19 @@ class PartitionedMount(Mount): "%dM" % p['start'], "%dM" % (p['start'] + d['extended'])]) logging.debug("Add %s part at %d of size %d" % (p['type'], p['start'], p['size'])) + p['originalfstype'] = p['fstype'] if p['fstype'].startswith('ext'): fstype = 'ext2' if p['fstype'].startswith('swap') or p['mountpoint'].startswith('swap'): fstype = 'linux-swap' if p['fstype'] == 'vfat': fstype = 'fat32' + if p['fstype'] == 'efi': + fstype = 'fat32' + p['fstype'] = 'vfat' + + logging.debug("Part fstype: %s, effective fstype %s" % (p['fstype'], fstype)) + rc = subprocess.call(["/sbin/parted", "-a", "opt", "-s", d['disk'].device, "mkpart", p['type'], fstype, "%dM" % p['start'], "%dM" % (p['start']+p['size'])]) @@ -280,6 +287,11 @@ class PartitionedMount(Mount): # mark the partition bootable subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", str(p['num']), "boot", "on"]) + if p['originalfstype'] == 'efi' and self.partition_layout == 'msdos': + logging.debug("Setting esp flag on in %s" % mp) + # mark the partition as efi, may fail on older versions of parted, like the ones in CentOS 7 + subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", str(p['num']), "esp", "on"]) + if mp == 'biosboot': subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", "1", "bios_grub", "on"]) continue From 7ea396abf0cfa5f7cad6008cfc7b208a51652228 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 26 2020 16:41:59 +0000 Subject: [PATCH 7/11] Create grub.cfg in the right place if EFI is being used --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index 8c0c519..a6081e8 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -454,11 +454,22 @@ class ApplianceImageCreator(ImageCreator): subprocess.call(["umount", self._instroot + "/dev"]) raise MountError("Unable to install grub2 bootloader") + mkconfig_dest = "/boot/grub2/grub.cfg" + try: + logging.debug(self._instroot + "/boot/grub2/grubenv") + if os.path.islink(self._instroot + "/boot/grub2/grubenv"): + dest=os.readlink(self._instroot + "/boot/grub2/grubenv") + dest=dest.replace("grubenv","grub.cfg") + os.symlink(dest,self._instroot+mkconfig_dest) + logging.debug("Symlink created from %s to %s" % (dest,mkconfig_dest)) + except: + logging.debug("Error creating symlink for %s" % mkconfig_dest) + logging.debug("Grub2 installed.") - logging.debug("Generating grub2 configuration file...") + logging.debug("Generating grub2 configuration file in (%s)..." % mkconfig_dest) # Generating grub2 config file - subprocess.call(["chroot", self._instroot, "grub2-mkconfig", "-o", "/boot/grub2/grub.cfg"]) + subprocess.call(["chroot", self._instroot, "grub2-mkconfig", "-o", mkconfig_dest]) # umount /dev filesystem subprocess.call(["umount", self._instroot + "/dev"]) From ef3487e9e686dda6c1af1c94561264fe264a6ab0 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 26 2020 16:41:59 +0000 Subject: [PATCH 8/11] Skip empty devices in partitions --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index a6081e8..0ac8025 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -235,7 +235,7 @@ class ApplianceImageCreator(ImageCreator): parts = kickstart.get_partitions(self.ks) for p in parts: dev = p.disk - if not dev in devs: + if dev != "" and not dev in devs: devs.append(dev) if devs == []: From aeac2bac502f9c19d5700fc81cebda48bb02cb25 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 26 2020 16:41:59 +0000 Subject: [PATCH 9/11] Use sfdisk to set efi partition if parted fails --- diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index 9d863c1..a75884c 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -290,7 +290,10 @@ class PartitionedMount(Mount): if p['originalfstype'] == 'efi' and self.partition_layout == 'msdos': logging.debug("Setting esp flag on in %s" % mp) # mark the partition as efi, may fail on older versions of parted, like the ones in CentOS 7 - subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", str(p['num']), "esp", "on"]) + rc = subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", str(p['num']), "esp", "on"]) + if rc != 0: + logging.debug("parted failed setting esp flag, trying sfdisk") + subprocess.call(["/sbin/sfdisk", "--change-id", self.disks[p['disk']]['disk'].device, str(p['num']), "ef"]) if mp == 'biosboot': subprocess.call(["/sbin/parted", "-s", self.disks[p['disk']]['disk'].device, "set", "1", "bios_grub", "on"]) From 6cb1dcf09104598185c08a472bff6acbddc5c30f Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 26 2020 16:44:19 +0000 Subject: [PATCH 10/11] Set boot flag on efi only if grub2 --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index 0ac8025..ed74f54 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -206,7 +206,8 @@ class ApplianceImageCreator(ImageCreator): self.__instloop = PartitionedMount(self.__disks, self._instroot, - partition_layout) + partition_layout, + self.bootloader) for p in parts: if p.disk: diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index a75884c..e18d98e 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -35,7 +35,7 @@ from imgcreate.fs import * class PartitionedMount(Mount): - def __init__(self, disks, mountdir, partition_layout): + def __init__(self, disks, mountdir, partition_layout, bootloader): Mount.__init__(self, mountdir) self.disks = {} for name in list(disks.keys()): @@ -51,6 +51,7 @@ class PartitionedMount(Mount): self.mountOrder = [] self.unmountOrder = [] self.partition_layout = partition_layout + self.bootloader = bootloader self.has_extended = False # Has extended partition layout def add_partition(self, size, disk, mountpoint, fstype = None): @@ -263,7 +264,7 @@ class PartitionedMount(Mount): self.__calculate_mountorder() boot_flag_mp = "/boot" - if "/boot/efi" in self.mountOrder: + if "/boot/efi" in self.mountOrder and self.bootloader == "grub2": boot_flag_mp = "/boot/efi" From 2265560b4bca24e19452a34ab8e0acf235aabfa0 Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Apr 26 2020 18:56:42 +0000 Subject: [PATCH 11/11] Other packages to detect grub2, and additional params for grub2-install --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index ed74f54..38a2a40 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -73,6 +73,7 @@ class ApplianceImageCreator(ImageCreator): # This determines which partition layout we'll be using self.bootloader = None + self.grub2inst_params = [] def _get_fstab(self): s = "" @@ -183,7 +184,16 @@ class ApplianceImageCreator(ImageCreator): else: logging.warning("WARNING! syslinux-extlinux package not found.") if self.bootloader is None: - if 'grub2' in packages: + if 'grub2-efi-arm' in packages: + self.bootloader = 'grub2' + self.grub2inst_params = ["--target=arm-efi", "--removable"] + elif 'grub2-efi-aa64' in packages: + self.bootloader = 'grub2' + elif 'grub2-efi-ia32' in packages: + self.bootloader = 'grub2' + elif 'grub2-efi-x64' in packages: + self.bootloader = 'grub2' + elif 'grub2' in packages or 'grub2-pc' in packages: self.bootloader = 'grub2' elif 'grub' in packages: self.bootloader = 'grub' @@ -449,7 +459,7 @@ class ApplianceImageCreator(ImageCreator): # mount full /dev filesystem subprocess.call(["mount", "--bind", "/dev", self._instroot + "/dev"]) - rc = subprocess.call(["chroot", self._instroot, "grub2-install", "--no-floppy", "--grub-mkdevicemap=/boot/grub2/device.map", loopdev]) + rc = subprocess.call(["chroot", self._instroot, "grub2-install", "--no-floppy", "--grub-mkdevicemap=/boot/grub2/device.map"] + self.grub2inst_params + [loopdev]) if rc != 0: subprocess.call(["umount", self._instroot + "/dev"])