def _add_single_efi_boot_target(self, partition): boot_disk = partition.disk boot_part_num = str(partition.parted_partition.number) rc = self.efibootmgr( "-c", "-w", "-L", productName.split("-")[0], # pylint: disable=no-member "-d", boot_disk.path, "-p", boot_part_num, "-l", self.efi_dir_as_efifs_dir + self._efi_binary, # pylint: disable=no-member root=conf.target.system_root ) if rc: raise BootLoaderError("Failed to set new efi boot target. This is most " "likely a kernel or firmware bug.")
def _add_single_efi_boot_target(self, partition): boot_disk = partition.disk boot_part_num = str(partition.parted_partition.number) rc = self.efibootmgr( "-c", "-w", "-L", productName.split("-")[0], # pylint: disable=no-member "-d", boot_disk.path, "-p", boot_part_num, "-l", self.efi_dir_as_efifs_dir + self._efi_binary, # pylint: disable=no-member root=util.getSysroot() ) if rc: raise BootLoaderError("Failed to set new efi boot target. This is most " "likely a kernel or firmware bug.")
def remove_efi_boot_target(self): buf = self.efibootmgr(capture=True) for line in buf.splitlines(): try: (slot, _product) = line.split(None, 1) except ValueError: continue if _product == productName.split("-")[0]: # pylint: disable=no-member slot_id = slot[4:8] # slot_id is hex, we can't use .isint and use this regex: if not re.match("^[0-9a-fA-F]+$", slot_id): log.warning("failed to parse efi boot slot (%s)", slot) continue rc = self.efibootmgr("-b", slot_id, "-B") if rc: raise BootLoaderError("Failed to remove old efi boot entry. This is most " "likely a kernel or firmware bug.")
def remove_efi_boot_target(self): buf = self.efibootmgr(capture=True) for line in buf.splitlines(): try: (slot, _product) = line.split(None, 1) except ValueError: continue if _product == productName.split("-")[0]: # pylint: disable=no-member slot_id = slot[4:8] # slot_id is hex, we can't use .isint and use this regex: if not re.match("^[0-9a-fA-F]+$", slot_id): log.warning("failed to parse efi boot slot (%s)", slot) continue rc = self.efibootmgr("-b", slot_id, "-B") if rc: raise BootLoaderError("Failed to remove old efi boot entry. This is most " "likely a kernel or firmware bug.")
class PackagePayload(Payload): """ A PackagePayload installs a set of packages onto the target system. """ DEFAULT_REPOS = [productName.split('-')[0].lower(), "rawhide"] def __init__(self, data): if self.__class__ is PackagePayload: raise TypeError("PackagePayload is an abstract class") super(PackagePayload, self).__init__(data) self.install_device = None self._rpm_macros = [] self.requiredPackages = [] self.requiredGroups = [] # Used to determine which add-ons to display for each environment. # The dictionary keys are environment IDs. The dictionary values are two-tuples # consisting of lists of add-on group IDs. The first list is the add-ons specific # to the environment, and the second list is the other add-ons possible for the # environment. self._environmentAddons = {} def preInstall(self, packages=None, groups=None): super(PackagePayload, self).preInstall() # Set rpm-specific options # nofsync speeds things up at the risk of rpmdb data loss in a crash. # But if we crash mid-install you're boned anyway, so who cares? self.rpmMacros.append( ('__dbi_htconfig', 'hash nofsync %{__dbi_other} %{__dbi_perms}')) if self.data.packages.excludeDocs: self.rpmMacros.append(('_excludedocs', '1')) if self.data.packages.instLangs is not None: # Use nil if instLangs is empty self.rpmMacros.append( ('_install_langs', self.data.packages.instLangs or '%{nil}')) if flags.selinux: for d in [ "/tmp/updates", "/etc/selinux/targeted/contexts/files", "/etc/security/selinux/src/policy", "/etc/security/selinux" ]: f = d + "/file_contexts" if os.access(f, os.R_OK): self.rpmMacros.append(('__file_context_path', f)) break else: self.rpmMacros.append(('__file_context_path', '%{nil}')) # Add platform specific group groupid = iutil.get_platform_groupid() if groupid and groupid in self.groups: if isinstance(groups, list): log.info("Adding platform group %s", groupid) groups.append(groupid) else: log.warning("Could not add %s to groups, not a list.", groupid) elif groupid: log.warning("Platform group %s not available.", groupid) @property def kernelPackages(self): if "kernel" in self.data.packages.excludedList: return [] kernels = ["kernel"] if isys.isPaeAvailable(): kernels.insert(0, "kernel-PAE") # most ARM systems use platform-specific kernels if blivet.arch.isARM(): if platform.armMachine is not None: kernels = ["kernel-%s" % platform.armMachine] if isys.isLpaeAvailable(): kernels.insert(0, "kernel-lpae") return kernels @property def kernelVersionList(self): # Find all installed rpms that provide 'kernel' # If a PackagePayload is in use, rpm needs to be available try: import rpm except ImportError: raise PayloadError( "failed to import rpm-python, cannot determine kernel versions" ) files = [] ts = rpm.TransactionSet(iutil.getSysroot()) mi = ts.dbMatch('providename', 'kernel') for hdr in mi: unicode_fnames = (f.decode("utf-8") for f in hdr.filenames) # Find all /boot/vmlinuz- files and strip off vmlinuz- files.extend((f.split("/")[-1][8:] for f in unicode_fnames if fnmatch(f, "/boot/vmlinuz-*") or fnmatch( f, "/boot/efi/EFI/%s/vmlinuz-*" % self.instclass.efi_dir))) return sorted(files, key=functools.cmp_to_key(versionCmp)) @property def rpmMacros(self): """A list of (name, value) pairs to define as macros in the rpm transaction.""" return self._rpm_macros @rpmMacros.setter def rpmMacros(self, value): self._rpm_macros = value def reset(self): self.reset_install_device() def reset_install_device(self): """ Unmount the previous base repo and reset the install_device """ # cdrom: install_device.teardown (INSTALL_TREE) # hd: umount INSTALL_TREE, install_device.teardown (ISO_DIR) # nfs: umount INSTALL_TREE # nfsiso: umount INSTALL_TREE, umount ISO_DIR if os.path.ismount(INSTALL_TREE) and not flags.testing: if self.install_device and \ blivet.util.get_mount_device(INSTALL_TREE) == self.install_device.path: self.install_device.teardown(recursive=True) else: blivet.util.umount(INSTALL_TREE) if os.path.ismount(ISO_DIR) and not flags.testing: if self.install_device and \ blivet.util.get_mount_device(ISO_DIR) == self.install_device.path: self.install_device.teardown(recursive=True) # The below code will fail when nfsiso is the stage2 source # But if we don't do this we may not be able to switch from # one nfsiso repo to another nfsiso repo. We need to have a # way to detect the stage2 state and work around it. # Commenting out the below is a hack for F18. FIXME #else: # # NFS # blivet.util.umount(ISO_DIR) self.install_device = None def _setupMedia(self, device): method = self.data.method if method.method == "harddrive": self._setupDevice(device, mountpoint=ISO_DIR) # check for ISO images in the newly mounted dir path = ISO_DIR if method.dir: path = os.path.normpath("%s/%s" % (path, method.dir)) # XXX it would be nice to streamline this when we're just setting # things back up after storage activation instead of having to # pretend we don't already know which ISO image we're going to # use image = findFirstIsoImage(path) if not image: device.teardown(recursive=True) raise PayloadSetupError("failed to find valid iso image") if path.endswith(".iso"): path = os.path.dirname(path) # this could already be set up the first time through if not os.path.ismount(INSTALL_TREE): # mount the ISO on a loop image = os.path.normpath("%s/%s" % (path, image)) mountImage(image, INSTALL_TREE) if not method.dir.endswith(".iso"): method.dir = os.path.normpath( "%s/%s" % (method.dir, os.path.basename(image))) while method.dir.startswith("/"): # riduculous method.dir = method.dir[1:] # Check to see if the device is already mounted, in which case # we don't need to mount it again elif method.method == "cdrom" and \ blivet.util.get_mount_paths(device.path): return else: device.format.setup(mountpoint=INSTALL_TREE) def _setupInstallDevice(self, storage, checkmount): # XXX FIXME: does this need to handle whatever was set up by dracut? method = self.data.method sslverify = True url = None mirrorlist = None # See if we already have stuff mounted due to dracut isodev = blivet.util.get_mount_device(DRACUT_ISODIR) device = blivet.util.get_mount_device(DRACUT_REPODIR) if method.method == "harddrive": if method.biospart: log.warning("biospart support is not implemented") devspec = method.biospart else: devspec = method.partition needmount = True # See if we used this method for stage2, thus dracut left it if isodev and method.partition and method.partition in isodev \ and DRACUT_ISODIR in device: # Everything should be setup url = "file://" + DRACUT_REPODIR needmount = False # We don't setup an install_device here # because we can't tear it down isodevice = storage.devicetree.resolveDevice(devspec) if needmount: if not isodevice: raise PayloadSetupError( "device for HDISO install %s does not exist" % devspec) self._setupMedia(isodevice) url = "file://" + INSTALL_TREE self.install_device = isodevice elif method.method == "nfs": # There are several possible scenarios here: # 1. dracut could have mounted both the nfs repo and an iso and used # the stage2 from inside the iso to boot from. # isodev and device will be set in this case. # 2. dracut could have mounted the nfs repo and used a stage2 from # the NFS mount w/o mounting the iso. # isodev will be None and device will be the nfs: path # 3. dracut did not mount the nfs (eg. stage2 came from elsewhere) # isodev and device are both None # 4. The repo may not contain an iso, in that case use it as is if isodev: path = iutil.parseNfsUrl('nfs:%s' % isodev)[2] # See if the dir holding the iso is what we want # and also if we have an iso mounted to /run/install/repo if path and path in isodev and DRACUT_ISODIR in device: # Everything should be setup url = "file://" + DRACUT_REPODIR else: # see if the nfs dir is mounted needmount = True if device: _options, host, path = iutil.parseNfsUrl('nfs:%s' % device) if method.server and method.server == host and \ method.dir and method.dir == path: needmount = False path = DRACUT_REPODIR if needmount: # Mount the NFS share on INSTALL_TREE. If it ends up # being nfsiso we will move the mountpoint to ISO_DIR. if method.dir.endswith(".iso"): nfsdir = os.path.dirname(method.dir) else: nfsdir = method.dir self._setupNFS(INSTALL_TREE, method.server, nfsdir, method.opts) path = INSTALL_TREE # check for ISO images in the newly mounted dir if method.dir.endswith(".iso"): # if the given URL includes a specific ISO image file, use it image_file = os.path.basename(method.dir) path = os.path.normpath("%s/%s" % (path, image_file)) image = findFirstIsoImage(path) # An image was found, mount it on INSTALL_TREE if image: if path.startswith(INSTALL_TREE): # move the INSTALL_TREE mount to ISO_DIR so we can # mount the contents of the iso there. # work around inability to move shared filesystems iutil.execWithRedirect("mount", ["--make-rprivate", "/"]) iutil.execWithRedirect( "mount", ["--move", INSTALL_TREE, ISO_DIR]) # The iso is now under ISO_DIR path = ISO_DIR elif path.endswith(".iso"): path = os.path.dirname(path) # mount the ISO on a loop image = os.path.normpath("%s/%s" % (path, image)) mountImage(image, INSTALL_TREE) url = "file://" + INSTALL_TREE else: # Fall back to the mount path instead of a mounted iso url = "file://" + path elif method.method == "url": url = method.url mirrorlist = method.mirrorlist sslverify = not (method.noverifyssl or flags.noverifyssl) elif method.method == "cdrom" or (checkmount and not method.method): # Did dracut leave the DVD or NFS mounted for us? device = blivet.util.get_mount_device(DRACUT_REPODIR) # Check for valid optical media if we didn't boot from one if not verifyMedia(DRACUT_REPODIR): self.install_device = opticalInstallMedia(storage.devicetree) # Only look at the dracut mount if we don't already have a cdrom if device and not self.install_device: self.install_device = storage.devicetree.getDeviceByPath( device) url = "file://" + DRACUT_REPODIR if not method.method: # See if this is a nfs mount if ':' in device: # prepend nfs: to the url as that's what the parser # wants. Note we don't get options from this, but # that's OK for the UI at least. _options, host, path = iutil.parseNfsUrl("nfs:%s" % device) method.method = "nfs" method.server = host method.dir = path else: method.method = "cdrom" else: if self.install_device: if not method.method: method.method = "cdrom" self._setupMedia(self.install_device) url = "file://" + INSTALL_TREE elif method.method == "cdrom": raise PayloadSetupError("no usable optical media found") return url, mirrorlist, sslverify ### ### METHODS FOR WORKING WITH REPOSITORIES ### @property def repos(self): """A list of repo identifiers, not objects themselves.""" raise NotImplementedError() def addDriverRepos(self): """ Add driver repositories and packages """ # Drivers are loaded by anaconda-dracut, their repos are copied # into /run/install/DD-X where X is a number starting at 1. The list of # packages that were selected is in /run/install/dd_packages # Add repositories dir_num = 0 while True: dir_num += 1 repo = "/run/install/DD-%d/" % dir_num if not os.path.isdir(repo): break # Run createrepo if there are rpms and no repodata if not os.path.isdir(repo + "/repodata"): rpms = glob(repo + "/*rpm") if not rpms: continue log.info("Running createrepo on %s", repo) iutil.execWithRedirect("createrepo_c", [repo]) ks_repo = self.data.RepoData(name="DD-%d" % dir_num, baseurl="file://" + repo, enabled=True) self.addRepo(ks_repo) # Add packages if not os.path.exists("/run/install/dd_packages"): return with open("/run/install/dd_packages", "r") as f: for line in f: package = line.strip() if package not in self.requiredPackages: self.requiredPackages.append(package) log.debug("required packages = %s", self.requiredPackages) @property def ISOImage(self): """ The location of a mounted ISO repo, or None. """ if not self.data.method.method == "harddrive": return None # This could either be mounted to INSTALL_TREE or on # DRACUT_ISODIR if dracut did the mount. dev = blivet.util.get_mount_device(INSTALL_TREE) if dev: return dev[len(ISO_DIR) + 1:] dev = blivet.util.get_mount_device(DRACUT_ISODIR) if dev: return dev[len(DRACUT_ISODIR) + 1:] return None ### ### METHODS FOR WORKING WITH ENVIRONMENTS ### @property def environments(self): raise NotImplementedError() def environmentHasOption(self, environmentid, grpid): raise NotImplementedError() def environmentOptionIsDefault(self, environmentid, grpid): raise NotImplementedError() def environmentDescription(self, environmentid): raise NotImplementedError() def selectEnvironment(self, environmentid, excluded=None): if environmentid not in self.environments: raise NoSuchGroup(environmentid) self.data.packages.environment = environmentid if excluded is None: excluded = [] def environmentGroups(self, environmentid, optional=True): raise NotImplementedError() @property def environmentAddons(self): return self._environmentAddons def _isGroupVisible(self, grp): raise NotImplementedError() def _groupHasInstallableMembers(self, grp): raise NotImplementedError() def _refreshEnvironmentAddons(self): log.info("Refreshing environmentAddons") self._environmentAddons = {} for environment in self.environments: self._environmentAddons[environment] = ([], []) # Determine which groups are specific to this environment and which other groups # are available in this environment. for grp in self.groups: if not self._groupHasInstallableMembers(grp): continue elif self.environmentHasOption(environment, grp): self._environmentAddons[environment][0].append(grp) elif self._isGroupVisible(grp): self._environmentAddons[environment][1].append(grp) ### ### METHODS FOR WORKING WITH GROUPS ### @property def groups(self): raise NotImplementedError() def groupDescription(self, groupid): raise NotImplementedError()