def mount_root(self): """Mounts selected root and runs scripts.""" # mount root fs try: mount_existing_system(self._storage.fsset, self.root.device, read_only=self.ro) log.info("System has been mounted under: %s", iutil.getSysroot()) except StorageError as e: log.error("Mounting system under %s failed: %s", iutil.getSysroot(), e) self.status = RescueModeStatus.MOUNT_FAILED return False # turn on swap if not flags.imageInstall or not self.ro: try: self._storage.turn_on_swap() except StorageError: log.error("Error enabling swap.") # turn on selinux also if flags.selinux: # we have to catch the possible exception, because we # support read-only mounting try: fd = open("%s/.autorelabel" % iutil.getSysroot(), "w+") fd.close() except IOError as e: log.warning("Error turning on selinux: %s", e) # set a libpath to use mounted fs libdirs = os.environ.get("LD_LIBRARY_PATH", "").split(":") mounted = ["/mnt/sysimage%s" % ldir for ldir in libdirs] iutil.setenv("LD_LIBRARY_PATH", ":".join(libdirs + mounted)) # do we have bash? try: if os.access("/usr/bin/bash", os.R_OK): os.symlink("/usr/bin/bash", "/bin/bash") except OSError as e: log.error("Error symlinking bash: %s", e) # make resolv.conf in chroot if not self.ro: self._storage.make_mtab() try: makeResolvConf(iutil.getSysroot()) except (OSError, IOError) as e: log.error("Error making resolv.conf: %s", e) # create /etc/fstab in ramdisk so it's easier to work with RO mounted fs makeFStab() # run %post if we've mounted everything if not self.ro and self._scripts: runPostScripts(self._scripts) self.status = RescueModeStatus.MOUNTED return True
def setup_kexec(): """ Setup kexec to use the new kernel and default bootloader entry This uses grubby to determine the bootloader arguments from the default entry, and then sets up kexec so that reboot will use the new kernel and initrd instead of doing a full reboot. .. note:: Once kexec is called there is nothing else to do, the reboot code already handles having kexec setup. """ try: boot_info = run_grubby() except GrubbyInfoError: # grubby couldn't find a default entry, use the first one instead try: boot_info = run_grubby(["--info", "ALL"]) except GrubbyInfoError: # Grubby can't get the bootloader's info, kexec won't work. log.error("kexec reboot setup failed, grubby could not get bootloader info.") return # Copy the kernel and initrd to /tmp/ shutil.copy2(getSysroot() + boot_info.kernel, "/tmp/vmlinuz-kexec-reboot") shutil.copy2(getSysroot() + boot_info.initrd, "/tmp/initrd-kexec-reboot") append = "root=%s %s" % (boot_info.root, boot_info.args) args = ["--initrd", "/tmp/initrd-kexec-reboot", "--append", append, "-l", "/tmp/vmlinuz-kexec-reboot"] try: rc = execWithRedirect("kexec", args) except OSError as e: log.error("setup_kexec failed: %s", e) if rc != 0: log.error("setup_kexec failed with rc=%d: See program.log for output", rc)
def writeStorageLate(self): """Some packaging payloads require that the storage configuration be written out after doing installation. Right now, this is basically every payload except for dnf. Payloads should only implement one of these methods by overriding the unneeded one with a pass. """ if not flags.dirInstall: if iutil.getSysroot() != iutil.getTargetPhysicalRoot(): setSysroot(iutil.getTargetPhysicalRoot(), iutil.getSysroot()) # Now that we have the FS layout in the target, umount # things that were in the legacy sysroot, and put them in # the target root, except for the physical /. First, # unmount all target filesystems. self.storage.umountFilesystems() # Explicitly mount the root on the physical sysroot rootmnt = self.storage.mountpoints.get('/') rootmnt.setup() rootmnt.format.setup(options=rootmnt.format.options, chroot=iutil.getTargetPhysicalRoot()) self.prepareMountTargets(self.storage) # Everything else goes in the target root, including /boot # since the bootloader code will expect to find /boot # inside the chroot. self.storage.mountFilesystems(skipRoot=True) self.storage.write()
def _copyBootloaderData(self): # Copy bootloader data files from the deployment # checkout to the target root. See # https://bugzilla.gnome.org/show_bug.cgi?id=726757 This # happens once, at installation time. # extlinux ships its modules directly in the RPM in /boot. # For GRUB2, Anaconda installs device.map there. We may need # to add other bootloaders here though (if they can't easily # be fixed to *copy* data into /boot at install time, instead # of shipping it in the RPM). physboot = iutil.getTargetPhysicalRoot() + '/boot' ostree_boot_source = iutil.getSysroot() + '/usr/lib/ostree-boot' if not os.path.isdir(ostree_boot_source): ostree_boot_source = iutil.getSysroot() + '/boot' for fname in os.listdir(ostree_boot_source): srcpath = os.path.join(ostree_boot_source, fname) destpath = os.path.join(physboot, fname) # We're only copying directories if not os.path.isdir(srcpath): continue # Special handling for EFI, as it's a mount point that's # expected to already exist (so if we used copytree, we'd # traceback). If it doesn't, we're not on a UEFI system, # so we don't want to copy the data. if fname == 'efi' and os.path.isdir(destpath): for subname in os.listdir(srcpath): sub_srcpath = os.path.join(srcpath, subname) sub_destpath = os.path.join(destpath, subname) self._safeExecWithRedirect('cp', ['-r', '-p', sub_srcpath, sub_destpath]) else: log.info("Copying bootloader data: " + fname) self._safeExecWithRedirect('cp', ['-r', '-p', srcpath, destpath])
def prepareMountTargets(self, storage): ostreesetup = self.data.ostreesetup varroot = iutil.getTargetPhysicalRoot() + '/ostree/deploy/' + ostreesetup.osname + '/var' # Set up bind mounts as if we've booted the target system, so # that %post script work inside the target. binds = [(iutil.getTargetPhysicalRoot(), iutil.getSysroot() + '/sysroot'), (varroot, iutil.getSysroot() + '/var'), (iutil.getSysroot() + '/usr', None)] for (src, dest) in binds: self._safeExecWithRedirect("mount", ["--bind", src, dest if dest else src]) if dest is None: self._safeExecWithRedirect("mount", ["--bind", "-o", "ro", src, src]) # Now, ensure that all other potential mount point directories such as # (/home) are created. We run through the full tmpfiles here in order # to also allow Anaconda and %post scripts to write to directories like # /root. We don't iterate *all* tmpfiles because we don't have the # matching NSS configuration inside Anaconda, and we can't "chroot" to # get it because that would require mounting the API filesystems in the # target. for varsubdir in ('home', 'roothome', 'lib/rpm', 'opt', 'srv', 'usrlocal', 'mnt', 'media', 'spool/mail'): self._safeExecWithRedirect("systemd-tmpfiles", ["--create", "--boot", "--root=" + iutil.getSysroot(), "--prefix=/var/" + varsubdir])
def execute(self, storage, ksdata, instClass, users, payload): """ Execute the addon :param storage: Blivet storage object :param ksdata: Kickstart data object :param instClass: Anaconda installclass object :param users: Anaconda users object :param payload: object managing packages and environment groups for the installation """ if not self.enabled: return log.info("Executing docker addon") # This gets called after installation, before initramfs regeneration and kickstart %post scripts. execWithRedirect("mount", ["-o", "bind", getSysroot()+"/var/lib/docker", "/var/lib/docker"]) execWithRedirect("mount", ["-o", "bind", getSysroot()+"/etc/docker", "/etc/docker"]) # Start up the docker daemon log.debug("Starting docker daemon") docker_cmd = ["docker", "daemon"] if ksdata.selinux.selinux: docker_cmd += ["--selinux-enabled"] # Add storage specific arguments to the command docker_cmd += self.storage.docker_cmd(storage, ksdata, instClass, users) docker_cmd += ["--ip-forward=false", "--iptables=false"] docker_cmd += self.extra_args docker_proc = startProgram(docker_cmd, stdout=open("/tmp/docker-daemon.log", "w"), reset_lang=True) log.debug("Running docker commands") script = AnacondaKSScript(self.content, inChroot=False, logfile="/tmp/docker-addon.log") script.run("/") # Kill the docker process log.debug("Shutting down docker daemon") docker_proc.kill() log.debug("Writing docker configs") self.storage.write_configs(storage, ksdata, instClass, users) # Rewrite the OPTIONS entry with the extra args and/or storage specific changes try: docker_cfg = SimpleConfigFile(getSysroot()+"/etc/sysconfig/docker") docker_cfg.read() options = self.storage.options(docker_cfg.get("OPTIONS")) if self.save_args: log.info("Adding extra args to docker OPTIONS") options += " " + " ".join(self.extra_args) docker_cfg.set(("OPTIONS", options)) docker_cfg.write() except IOError as e: log.error("Error updating OPTIONS in /etc/sysconfig/docker: %s", e) # Copy the log files to the system dstdir = "/var/log/anaconda/" os.makedirs(dstdir, exist_ok=True) for l in ["docker-daemon.log", "docker-addon.log"]: shutil.copy2("/tmp/"+l, dstdir+l)
def prepareMountTargets(self, storage): ostreesetup = self.data.ostreesetup varroot = iutil.getTargetPhysicalRoot( ) + '/ostree/deploy/' + ostreesetup.osname + '/var' # Set up bind mounts as if we've booted the target system, so # that %post script work inside the target. binds = [(iutil.getTargetPhysicalRoot(), iutil.getSysroot() + '/sysroot'), (varroot, iutil.getSysroot() + '/var'), (iutil.getSysroot() + '/usr', None)] for (src, dest) in binds: self._safeExecWithRedirect("mount", ["--bind", src, dest if dest else src]) if dest is None: self._safeExecWithRedirect("mount", ["--bind", "-o", "ro", src, src]) # Now, ensure that all other potential mount point directories such as # (/home) are created. We run through the full tmpfiles here in order # to also allow Anaconda and %post scripts to write to directories like # /root. We don't iterate *all* tmpfiles because we don't have the # matching NSS configuration inside Anaconda, and we can't "chroot" to # get it because that would require mounting the API filesystems in the # target. for varsubdir in ('home', 'roothome', 'lib/rpm', 'opt', 'srv', 'usrlocal', 'mnt', 'media', 'spool/mail'): self._safeExecWithRedirect("systemd-tmpfiles", [ "--create", "--boot", "--root=" + iutil.getSysroot(), "--prefix=/var/" + varsubdir ])
def prepareMountTargets(self, storage): """ Prepare the ostree root """ ostreesetup = self.data.ostreesetup # Currently, blivet sets up mounts in the physical root. # We used to unmount them and remount them in the sysroot, but # since 664ef7b43f9102aa9332d0db5b7d13f8ece436f0 we now just set up # bind mounts. # Make /usr readonly like ostree does at runtime normally self._setupInternalBindmount('/usr', bind_ro=True, src_physical=False) # Explicitly do API mounts; some of these may be tracked by blivet, but # we'll skip them below. api_mounts = ["/dev", "/proc", "/run", "/sys"] for path in api_mounts: self._setupInternalBindmount(path) # Handle /var; if the admin didn't specify a mount for /var, we need # to do the default ostree one. # https://github.com/ostreedev/ostree/issues/855 varroot = '/ostree/deploy/' + ostreesetup.osname + '/var' if storage.mountpoints.get("/var") is None: self._setupInternalBindmount(varroot, dest='/var', recurse=False) else: # Otherwise, bind it self._setupInternalBindmount('/var', recurse=False) # Now that we have /var, start filling in any directories that may be # required later there. We explicitly make /var/lib, since # systemd-tmpfiles doesn't have a --prefix-only=/var/lib. We rely on # 80-setfilecons.ks to set the label correctly. iutil.mkdirChain(iutil.getSysroot() + '/var/lib') # Next, run tmpfiles to make subdirectories of /var. We need this for # both mounts like /home (really /var/home) and %post scripts might # want to write to e.g. `/srv`, `/root`, `/usr/local`, etc. The # /var/lib/rpm symlink is also critical for having e.g. `rpm -qa` work # in %post. We don't iterate *all* tmpfiles because we don't have the # matching NSS configuration inside Anaconda, and we can't "chroot" to # get it because that would require mounting the API filesystems in the # target. for varsubdir in ('home', 'roothome', 'lib/rpm', 'opt', 'srv', 'usrlocal', 'mnt', 'media', 'spool', 'spool/mail'): self._safeExecWithRedirect("systemd-tmpfiles", ["--create", "--boot", "--root=" + iutil.getSysroot(), "--prefix=/var/" + varsubdir]) # Handle mounts like /boot (except avoid /boot/efi; we just need the # toplevel), and any admin-specified points like /home (really # /var/home). Note we already handled /var above. Avoid recursion since # sub-mounts will be in the list too. We sort by length as a crude # hack to try to simulate the tree relationship; it looks like this # is handled in blivet in a different way. for mount in sorted(storage.mountpoints, key=len): if mount in ('/', '/var') or mount in api_mounts: continue self._setupInternalBindmount(mount, recurse=False) # And finally, do a nonrecursive bind for the sysroot self._setupInternalBindmount("/", dest="/sysroot", recurse=False)
def execute(self, storage, ksdata, instClass, users): """ Execute the addon :param storage: Blivet storage object :param ksdata: Kickstart data object :param instClass: Anaconda installclass object :param users: Anaconda users object """ log.info("Executing docker addon") # This gets called after installation, before initramfs regeneration and kickstart %post scripts. execWithRedirect("mount", ["-o", "bind", getSysroot()+"/var/lib/docker", "/var/lib/docker"]) execWithRedirect("mount", ["-o", "bind", getSysroot()+"/etc/docker", "/etc/docker"]) # Start up the docker daemon log.debug("Starting docker daemon") dm_fs = "dm.fs=%s" % self.fstype pool_name = "dm.thinpooldev=/dev/mapper/%s-docker--pool" % self.vgname docker_cmd = ["docker", "daemon"] if ksdata.selinux.selinux: docker_cmd += ["--selinux-enabled"] docker_cmd += ["--storage-driver", "devicemapper", "--storage-opt", dm_fs, "--storage-opt", pool_name, "--ip-forward=false", "--iptables=false"] docker_cmd += self.extra_args docker_proc = startProgram(docker_cmd, stdout=open("/tmp/docker-daemon.log", "w"), reset_lang=True) log.debug("Running docker commands") script = AnacondaKSScript(self.content, inChroot=False, logfile="/tmp/docker-addon.log") script.run("/") # Kill the docker process log.debug("Shutting down docker daemon") docker_proc.kill() log.debug("Writing docker configs") with open(getSysroot()+"/etc/sysconfig/docker-storage", "w") as fp: fp.write('DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper ' '--storage-opt %s --storage-opt %s"\n' % (dm_fs, pool_name)) with open(getSysroot()+"/etc/sysconfig/docker-storage-setup", "a") as fp: fp.write("VG=%s\n" % self.vgname) # Rewrite the OPTIONS entry with the extra args, if requested. if self.extra_args and self.save_args: try: docker_cfg = SimpleConfigFile(getSysroot()+"/etc/sysconfig/docker") docker_cfg.read() options = docker_cfg.get("OPTIONS")+" " + " ".join(self.extra_args) docker_cfg.set(("OPTIONS", options)) docker_cfg.write() except IOError as e: log.error("Error updating OPTIONS in /etc/sysconfig/docker: %s", e) # Copy the log files to the system dstdir = "/var/log/anaconda/" os.makedirs(dstdir, exist_ok=True) for l in ["docker-daemon.log", "docker-addon.log"]: shutil.copy2("/tmp/"+l, dstdir+l)
def _initTargetRPM(self): self.etcrpm_dir = iutil.getSysroot() + "/etc/rpm" self.librpm_dir = iutil.getSysroot() + "/var/lib/rpm" # Configure /etc/rpm iutil.mkdirChain(self.etcrpm_dir) # For rpm-extra-macros._tmppath iutil.mkdirChain(iutil.getSysroot() + "/install/tmp") # Setup /etc/rpm/platform shutil.copy("/etc/rpm/platform", self.etcrpm_dir) # Setup /etc/rpm/sysinfo/Dirnames iutil.mkdirChain(self.etcrpm_dir + "/sysinfo") fd = open(self.etcrpm_dir + "/sysinfo/Dirnames", "w") fd.write("/\n") fd.close() # Setup provides if needed # Setup /var/lib/rpm iutil.mkdirChain(self.librpm_dir) iutil.mkdirChain(self.librpm_dir + "/log") # Touch the log file fd = open(self.librpm_dir + "/log/log.0000000001", "w") fd.close() # Configure the DB_CONFIG buf = """ # ================ Environment set_data_dir . set_create_dir . set_lg_dir ./log set_tmp_dir ./tmp set_flags db_log_autoremove on # -- thread_count must be >= 8 set_thread_count 64 # ================ Logging # ================ Memory Pool set_cachesize 0 1048576 0 set_mp_mmapsize 268435456 # ================ Locking set_lk_max_locks 16384 set_lk_max_lockers 16384 set_lk_max_objects 16384 mutex_set_max 163840 # ================ Replication """ fd = open(self.librpm_dir + "/DB_CONFIG", "w") fd.write(buf) fd.close()
def prepareMountTargets(self, storage): """ Prepare the ostree root """ ostreesetup = self.data.ostreesetup # Currently, blivet sets up mounts in the physical root. # We used to unmount them and remount them in the sysroot, but # since 664ef7b43f9102aa9332d0db5b7d13f8ece436f0 we now just set up # bind mounts. # Make /usr readonly like ostree does at runtime normally self._setupInternalBindmount('/usr', bind_ro=True, src_physical=False) # Explicitly do API mounts; some of these may be tracked by blivet, but # we'll skip them below. api_mounts = ["/dev", "/proc", "/run", "/sys"] for path in api_mounts: self._setupInternalBindmount(path) # Handle /var; if the admin didn't specify a mount for /var, we need # to do the default ostree one. # https://github.com/ostreedev/ostree/issues/855 varroot = '/ostree/deploy/' + ostreesetup.osname + '/var' if storage.mountpoints.get("/var") is None: self._setupInternalBindmount(varroot, dest='/var', recurse=False) else: # Otherwise, bind it self._setupInternalBindmount('/var', recurse=False) # Now that we have /var, start filling in any directories that may be # required later there. We explicitly make /var/lib, since # systemd-tmpfiles doesn't have a --prefix-only=/var/lib. We rely on # 80-setfilecons.ks to set the label correctly. iutil.mkdirChain(iutil.getSysroot() + '/var/lib') # Next, run tmpfiles to make subdirectories of /var. We need this for # both mounts like /home (really /var/home) and %post scripts might # want to write to e.g. `/srv`, `/root`, `/usr/local`, etc. The # /var/lib/rpm symlink is also critical for having e.g. `rpm -qa` work # in %post. We don't iterate *all* tmpfiles because we don't have the # matching NSS configuration inside Anaconda, and we can't "chroot" to # get it because that would require mounting the API filesystems in the # target. for varsubdir in ('home', 'roothome', 'lib/rpm', 'opt', 'srv', 'usrlocal', 'mnt', 'media', 'spool', 'spool/mail'): self._safeExecWithRedirect("systemd-tmpfiles", [ "--create", "--boot", "--root=" + iutil.getSysroot(), "--prefix=/var/" + varsubdir ]) # Handle mounts like /boot, and any admin-specified points like # /home (really /var/home). Note we already handled /var above. for mount in storage.mountpoints: if mount in ('/', '/var') or mount in api_mounts: continue self._setupInternalBindmount(mount) # And finally, do a nonrecursive bind for the sysroot self._setupInternalBindmount("/", dest="/sysroot", recurse=False)
def mount_root(self): """Mounts selected root and runs scripts.""" # mount root fs try: mount_existing_system(self._storage.fsset, self.root.device, read_only=self.ro) log.info("System has been mounted under: %s", iutil.getSysroot()) except StorageError as e: log.error("Mounting system under %s failed: %s", iutil.getSysroot(), e) self.status = RescueModeStatus.MOUNT_FAILED return False # turn on swap if not flags.imageInstall or not self.ro: try: self._storage.turn_on_swap() except StorageError: log.error("Error enabling swap.") # turn on selinux also if flags.selinux: # we have to catch the possible exception, because we # support read-only mounting try: fd = open("%s/.autorelabel" % iutil.getSysroot(), "w+") fd.close() except IOError as e: log.warning("Error turning on selinux: %s", e) # set a libpath to use mounted fs libdirs = os.environ.get("LD_LIBRARY_PATH", "").split(":") mounted = ["/mnt/sysimage%s" % ldir for ldir in libdirs] iutil.setenv("LD_LIBRARY_PATH", ":".join(libdirs + mounted)) # do we have bash? try: if os.access("/usr/bin/bash", os.R_OK): os.symlink("/usr/bin/bash", "/bin/bash") except OSError as e: log.error("Error symlinking bash: %s", e) # make resolv.conf in chroot if not self.ro: self._storage.make_mtab() try: makeResolvConf(iutil.getSysroot()) except(OSError, IOError) as e: log.error("Error making resolv.conf: %s", e) # create /etc/fstab in ramdisk so it's easier to work with RO mounted fs makeFStab() # run %post if we've mounted everything if not self.ro and self._scripts: runPostScripts(self._scripts) self.status = RescueModeStatus.MOUNTED return True
def postInstall(self): super(RPMOSTreePayload, self).postInstall() from gi.repository import OSTree cancellable = None sysroot = OSTree.Sysroot.new(self._sysroot_path) sysroot.load(cancellable) repo = sysroot.get_repo(None)[1] # CentOS specific patch (for now) - pull the remote config from usr/etc if it exists. # The OSTree handling here was buggy in that it wasn't looking in the sysroot # for existing remotes. default_remote_path = iutil.getSysroot( ) + '/usr/etc/ostree/remotes.d/' + self.data.ostreesetup.osname + '.conf' if os.path.isfile(default_remote_path): destpath = iutil.getSysroot( ) + '/etc/ostree/remotes.d/' + os.path.basename( default_remote_path) self._safeExecWithRedirect( 'cp', ['-r', '-p', default_remote_path, destpath]) else: # Following up on the "remote delete" above, we removed the # remote from /ostree/repo/config. But we want it in /etc, so # re-add it to /etc/ostree/remotes.d, using the sysroot path. # # However, we ignore the case where the remote already exists, # which occurs when the content itself provides the remote # config file. repo.remote_change(Gio.File.new_for_path(iutil.getSysroot()), OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS, self.data.ostreesetup.remote, self.data.ostreesetup.url, GLib.Variant('a{sv}', self._remoteOptions), cancellable) boot = iutil.getSysroot() + '/boot' # If we're using GRUB2, move its config file, also with a # compatibility symlink. boot_grub2_cfg = boot + '/grub2/grub.cfg' if os.path.isfile(boot_grub2_cfg): boot_loader = boot + '/loader' target_grub_cfg = boot_loader + '/grub.cfg' log.info("Moving %s -> %s", boot_grub2_cfg, target_grub_cfg) os.rename(boot_grub2_cfg, target_grub_cfg) os.symlink('../loader/grub.cfg', boot_grub2_cfg) # OSTree owns the bootloader configuration, so here we give it # the argument list we computed from storage, architecture and # such. set_kargs_args = ["admin", "instutil", "set-kargs"] set_kargs_args.extend(self.storage.bootloader.boot_args) set_kargs_args.append("root=" + self.storage.rootDevice.fstabSpec) self._safeExecWithRedirect("ostree", set_kargs_args, root=iutil.getSysroot())
def install(self): """ Install the payload. """ if self.source_size <= 0: raise PayloadInstallError("Nothing to install") self.pct_lock = Lock() self.pct = 0 threadMgr.add( AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress)) cmd = "rsync" # preserve: permissions, owners, groups, ACL's, xattrs, times, # symlinks, hardlinks # go recursively, include devices and special files, don't cross # file system boundaries args = [ "-pogAXtlHrDx", "--exclude", "/dev/", "--exclude", "/proc/", "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*", "--exclude", "/etc/machine-id", INSTALL_TREE + "/", iutil.getSysroot() ] try: rc = iutil.execWithRedirect(cmd, args) except (OSError, RuntimeError) as e: msg = None err = str(e) log.error(err) else: err = None msg = "%s exited with code %d" % (cmd, rc) log.info(msg) if err or rc == 12: exn = PayloadInstallError(err or msg) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Wait for progress thread to finish with self.pct_lock: self.pct = 100 threadMgr.wait(THREAD_LIVE_PROGRESS) # Live needs to create the rescue image before bootloader is written if not os.path.exists(iutil.getSysroot() + "/usr/sbin/new-kernel-pkg"): log.error( "new-kernel-pkg does not exist - grubby wasn't installed? skipping" ) return for kernel in self.kernelVersionList: log.info("Generating rescue image for %s", kernel) iutil.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
def postInstall(self): super(RPMOSTreePayload, self).postInstall() gi.require_version("OSTree", "1.0") from gi.repository import OSTree cancellable = None # Following up on the "remote delete" above, we removed the # remote from /ostree/repo/config. But we want it in /etc, so # re-add it to /etc/ostree/remotes.d, using the sysroot path. # # However, we ignore the case where the remote already exists, # which occurs when the content itself provides the remote # config file. # Note here we use the deployment as sysroot, because it's # that version of /etc that we want. sysroot_file = Gio.File.new_for_path(iutil.getSysroot()) sysroot = OSTree.Sysroot.new(sysroot_file) sysroot.load(cancellable) repo = sysroot.get_repo(None)[1] repo.remote_change(sysroot_file, OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS, self.data.ostreesetup.remote, self.data.ostreesetup.url, GLib.Variant('a{sv}', self._remoteOptions), cancellable) boot = iutil.getSysroot() + '/boot' # If we're using GRUB2, move its config file, also with a # compatibility symlink. boot_grub2_cfg = boot + '/grub2/grub.cfg' if os.path.isfile(boot_grub2_cfg): boot_loader = boot + '/loader' target_grub_cfg = boot_loader + '/grub.cfg' log.info("Moving %s -> %s", boot_grub2_cfg, target_grub_cfg) os.rename(boot_grub2_cfg, target_grub_cfg) os.symlink('../loader/grub.cfg', boot_grub2_cfg) # Skip kernel args setup for dirinstall, there is no bootloader or rootDevice setup. if not flags.dirInstall: # OSTree owns the bootloader configuration, so here we give it # the argument list we computed from storage, architecture and # such. set_kargs_args = ["admin", "instutil", "set-kargs"] set_kargs_args.extend(self.storage.bootloader.boot_args) set_kargs_args.append("root=" + self.storage.root_device.fstab_spec) self._safeExecWithRedirect("ostree", set_kargs_args, root=iutil.getSysroot())
def _writeModuleBlacklist(self): """ Copy modules from modprobe.blacklist=<module> on cmdline to /etc/modprobe.d/anaconda-blacklist.conf so that modules will continue to be blacklisted when the system boots. """ if "modprobe.blacklist" not in flags.cmdline: return iutil.mkdirChain(iutil.getSysroot() + "/etc/modprobe.d") with open(iutil.getSysroot() + "/etc/modprobe.d/anaconda-blacklist.conf", "w") as f: f.write("# Module blacklists written by anaconda\n") for module in flags.cmdline["modprobe.blacklist"].split(): f.write("blacklist %s\n" % module)
def write(self): """Write the desktop & default target settings to disk.""" if self.desktop: with open(iutil.getSysroot() + "/etc/sysconfig/desktop", "w") as f: f.write("DESKTOP=%s\n" % self.desktop) if not os.path.isdir(iutil.getSysroot() + '/etc/systemd/system'): log.warning("There is no /etc/systemd/system directory, cannot update default.target!") return default_target = iutil.getSysroot() + '/etc/systemd/system/default.target' if os.path.islink(default_target): os.unlink(default_target) os.symlink('/lib/systemd/system/%s' % self.default_target, default_target)
def write(self): if self.desktop: with open(iutil.getSysroot() + "/etc/sysconfig/desktop", "w") as f: f.write("DESKTOP=%s\n" % self.desktop) if not os.path.isdir(iutil.getSysroot() + '/etc/systemd/system'): log.warning("there is no /etc/systemd/system directory, cannot update default.target!") return default_target = iutil.getSysroot() + '/etc/systemd/system/default.target' if os.path.islink(default_target): os.unlink(default_target) os.symlink('/lib/systemd/system/%s' % RUNLEVELS[self.runlevel], default_target)
def write_configs(self, storage, ksdata, instClass, users): """ Write configuration file(s) :param storage: Blivet storage object :param ksdata: Kickstart data object :param instClass: Anaconda installclass object :param users: Anaconda users object """ with open(getSysroot()+"/etc/sysconfig/docker-storage", "w") as fp: fp.write('DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper ' '--storage-opt %s --storage-opt %s"\n' % (self.dm_fs, self.pool_name)) with open(getSysroot()+"/etc/sysconfig/docker-storage-setup", "a") as fp: fp.write("VG=%s\n" % self.addon.vgname)
def execute(self, storage, ksdata, instclass, users, payload): """ The execute method that should make changes to the installed system. It is called only once in the post-install setup phase. :see: setup :param users: information about created users :type users: pyanaconda.users.Users instance """ if self.dry_run or not self.profile_id: # nothing more to be done in the dry-run mode or if no profile is # selected return target_content_dir = utils.join_paths(getSysroot(), common.TARGET_CONTENT_DIR) utils.ensure_dir_exists(target_content_dir) if self.content_type == "datastream": shutil.copy2(self.preinst_content_path, target_content_dir) elif self.content_type == "rpm": # copy the RPM to the target system shutil.copy2(self.raw_preinst_content_path, target_content_dir) # and install it with yum ret = iutil.execInSysroot( "yum", ["-y", "--nogpg", "install", self.raw_postinst_content_path]) if ret != 0: raise common.ExtractionError("Failed to install content " "RPM to the target system") elif self.content_type == "scap-security-guide": # nothing needed pass else: utils.universal_copy( utils.join_paths(common.INSTALLATION_CONTENT_DIR, "*"), target_content_dir) if os.path.exists(self.preinst_tailoring_path): shutil.copy2(self.preinst_tailoring_path, target_content_dir) common.run_oscap_remediate(self.profile_id, self.postinst_content_path, self.datastream_id, self.xccdf_id, self.postinst_tailoring_path, chroot=getSysroot())
def refresh(self, args=None): NormalTUISpoke.refresh(self, args) umount_msg = _("Run %s to unmount the system when you are finished." ) % ANACONDA_CLEANUP exit_reboot_msg = _( "When finished, please exit from the shell and your " "system will reboot.\n") text = None if self._rescue.mount: status = self._rescue.status if status == RescueModeStatus.MOUNTED: if self._rescue.reboot: finish_msg = exit_reboot_msg else: finish_msg = umount_msg text = TextWidget( _("Your system has been mounted under %(mountpoint)s.\n\n" "If you would like to make the root of your system the " "root of the active system, run the command:\n\n" "\tchroot %(mountpoint)s\n") % {"mountpoint": iutil.getSysroot()} + finish_msg) elif status == RescueModeStatus.MOUNT_FAILED: if self._rescue.reboot: finish_msg = exit_reboot_msg else: finish_msg = umount_msg text = TextWidget( _("An error occurred trying to mount some or all of " "your system. Some of it may be mounted under %s\n\n") % iutil.getSysroot() + finish_msg) elif status == RescueModeStatus.ROOT_NOT_FOUND: if self._rescue.reboot: finish_msg = _("Rebooting.") else: finish_msg = "" text = TextWidget( _("You don't have any Linux partitions. %s\n") % finish_msg) else: if self._rescue.reboot: finish_msg = exit_reboot_msg else: finish_msg = "" text = TextWidget(_("Not mounting the system.\n") + finish_msg) self.window.add(text) return InputState.PROCESSED
def install(self): """ Install the payload. """ if self.source_size <= 0: raise PayloadInstallError("Nothing to install") self.pct_lock = Lock() self.pct = 0 threadMgr.add(AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress)) cmd = "rsync" # preserve: permissions, owners, groups, ACL's, xattrs, times, # symlinks, hardlinks # go recursively, include devices and special files, don't cross # file system boundaries args = ["-pogAXtlHrDx", "--exclude", "/dev/", "--exclude", "/proc/", "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*", "--exclude", "/etc/machine-id", INSTALL_TREE+"/", iutil.getSysroot()] try: rc = iutil.execWithRedirect(cmd, args) except (OSError, RuntimeError) as e: msg = None err = str(e) log.error(err) else: err = None msg = "%s exited with code %d" % (cmd, rc) log.info(msg) if err or rc == 12: exn = PayloadInstallError(err or msg) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Wait for progress thread to finish with self.pct_lock: self.pct = 100 threadMgr.wait(THREAD_LIVE_PROGRESS) # Live needs to create the rescue image before bootloader is written if not os.path.exists(iutil.getSysroot() + "/usr/sbin/new-kernel-pkg"): log.error("new-kernel-pkg does not exist - grubby wasn't installed? skipping") return for kernel in self.kernelVersionList: log.info("Generating rescue image for %s", kernel) iutil.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
def createGroup(self, group_name, **kwargs): """Create a new user on the system with the given name. Optional kwargs: :keyword int gid: The GID for the new user. If none is given, the next available one is used. :keyword str root: The directory of the system to create the new user in. homedir will be interpreted relative to this. Defaults to iutil.getSysroot(). """ root = kwargs.get("root", iutil.getSysroot()) if self._getgrnam(group_name, root): raise ValueError("Group %s already exists" % group_name) args = ["-R", root] if kwargs.get("gid") is not None: args.extend(["-g", str(kwargs["gid"])]) args.append(group_name) with self._ensureLoginDefs(root): status = iutil.execWithRedirect("groupadd", args) if status == 4: raise ValueError("GID %s already exists" % kwargs.get("gid")) elif status == 9: raise ValueError("Group %s already exists" % group_name) elif status != 0: raise OSError("Unable to create group %s: status=%s" % (group_name, status))
def write_out_config_file(self, config_path=None): """Write the user interaction config file to persistent storage. - we always read the config file from the top level filesystem, as: -> on live media the file will be there -> on non-live media the config file (if any) will be injected to the top level -> filesystem by image generation tools or by an updates/product image - on the other hand the "output" config file needs to always end on the installed system, so that post installation setup tools (such as Initial Setup or Gnome Initial Setup) can use it -> therefore we always write the config file to the sysroot path """ if config_path is None: config_path = iutil.getSysroot() + CONFIG_FILE_PATH with self._lock: new_config_file = not os.path.exists(config_path) try: with open(config_path, "wt") as f: if new_config_file: # we are creating a new file, so add a header that it was created by Anaconda, # including its version number f.write(self._get_new_config_header()) self._config.write(f) except OSError: log.exception("Can't write user interaction config file.")
def recreateInitrds(self): """ Recreate the initrds by calling new-kernel-pkg This needs to be done after all configuration files have been written, since dracut depends on some of them. :returns: None """ if not os.path.exists(iutil.getSysroot() + "/usr/sbin/new-kernel-pkg"): log.error("new-kernel-pkg does not exist - grubby wasn't installed? skipping") return for kernel in self.kernelVersionList: log.info("recreating initrd for %s", kernel) if not flags.imageInstall: iutil.execInSysroot("new-kernel-pkg", ["--mkinitrd", "--dracut", "--depmod", "--update", kernel]) else: # hostonly is not sensible for disk image installations # using /dev/disk/by-uuid/ is necessary due to disk image naming iutil.execInSysroot("dracut", ["-N", "--persistent-policy", "by-uuid", "-f", "/boot/initramfs-%s.img" % kernel, kernel])
def createGroup(self, group_name, **kwargs): """Create a new user on the system with the given name. Optional kwargs: gid -- The GID for the new user. If none is given, the next available one is used. root -- The directory of the system to create the new user in. homedir will be interpreted relative to this. Defaults to /mnt/sysimage. """ childpid = self._prepareChroot(kwargs.get("root", iutil.getSysroot())) if childpid == 0: if self.admin.lookupGroupByName(group_name): log.error("Group %s already exists, not creating.", group_name) os._exit(1) groupEnt = self.admin.initGroup(group_name) if kwargs.get("gid", -1) >= 0: groupEnt.set(libuser.GIDNUMBER, kwargs["gid"]) try: self.admin.addGroup(groupEnt) except RuntimeError as e: log.critical("Error when creating new group: %s", e) os._exit(1) os._exit(0) else: return self._finishChroot(childpid)
def progress(self): """Monitor the amount of disk space used on the target and source and update the hub's progress bar. """ mountpoints = self.storage.mountpoints.copy() last_pct = -1 while self.pct < 100: dest_size = 0 for mnt in mountpoints: mnt_stat = iutil.eintr_retry_call(os.statvfs, iutil.getSysroot() + mnt) dest_size += mnt_stat.f_frsize * (mnt_stat.f_blocks - mnt_stat.f_bfree) if dest_size >= self._adj_size: dest_size -= self._adj_size pct = int(100 * dest_size / self.source_size) if pct != last_pct: with self.pct_lock: self.pct = pct last_pct = pct progressQ.send_message( _("Installing software") + (" %d%%") % (min(100, self.pct), )) sleep(0.777)
def setUserSshKey(self, username, key, **kwargs): childpid = self._prepareChroot(kwargs.get("root", iutil.getSysroot())) if childpid == 0: user = self.admin.lookupUserByName(username) if not user: log.error("setUserSshKey: user %s does not exist", username) os._exit(1) homedir = user.get(libuser.HOMEDIRECTORY)[0] if not os.path.exists(homedir): log.error("setUserSshKey: home directory for %s does not exist", username) os._exit(1) sshdir = os.path.join(homedir, ".ssh") if not os.path.isdir(sshdir): os.mkdir(sshdir, 0o700) iutil.eintr_retry_call(os.chown, sshdir, user.get(libuser.UIDNUMBER)[0], user.get(libuser.GIDNUMBER)[0]) authfile = os.path.join(sshdir, "authorized_keys") authfile_existed = os.path.exists(authfile) with open(authfile, "a") as f: f.write(key + "\n") # Only change mode and ownership if we created it if not authfile_existed: iutil.eintr_retry_call(os.chmod, authfile, 0o600) iutil.eintr_retry_call(os.chown, authfile, user.get(libuser.UIDNUMBER)[0], user.get(libuser.GIDNUMBER)[0]) iutil.execWithRedirect("restorecon", ["-r", sshdir]) os._exit(0) else: return self._finishChroot(childpid)
def enable_installer_mode(): """ Configure the module for use by anaconda (OS installer). """ global iutil global ROOT_PATH global _storageRoot global _sysroot global shortProductName global get_bootloader global errorHandler global ERROR_RAISE from pyanaconda import iutil # pylint: disable=redefined-outer-name from pyanaconda.constants import shortProductName # pylint: disable=redefined-outer-name from pyanaconda.bootloader import get_bootloader # pylint: disable=redefined-outer-name from pyanaconda.errors import errorHandler # pylint: disable=redefined-outer-name from pyanaconda.errors import ERROR_RAISE # pylint: disable=redefined-outer-name if hasattr(iutil, 'getTargetPhysicalRoot'): # For anaconda versions > 21.43 _storageRoot = iutil.getTargetPhysicalRoot() # pylint: disable=no-name-in-module _sysroot = iutil.getSysroot() else: # For prior anaconda versions from pyanaconda.constants import ROOT_PATH # pylint: disable=redefined-outer-name,no-name-in-module _storageRoot = _sysroot = ROOT_PATH from pyanaconda.anaconda_log import program_log_lock util.program_log_lock = program_log_lock flags.installer_mode = True
def setUserSshKey(self, username, key, **kwargs): root = kwargs.get("root", iutil.getSysroot()) pwent = self._getpwnam(username, root) if not pwent: raise ValueError("setUserSshKey: user %s does not exist" % username) homedir = root + pwent[5] if not os.path.exists(homedir): log.error("setUserSshKey: home directory for %s does not exist", username) raise ValueError( "setUserSshKey: home directory for %s does not exist" % username) uid = pwent[2] gid = pwent[3] sshdir = os.path.join(homedir, ".ssh") if not os.path.isdir(sshdir): os.mkdir(sshdir, 0o700) os.chown(sshdir, int(uid), int(gid)) authfile = os.path.join(sshdir, "authorized_keys") authfile_existed = os.path.exists(authfile) with iutil.open_with_perm(authfile, "a", 0o600) as f: f.write(key + "\n") # Only change ownership if we created it if not authfile_existed: os.chown(authfile, int(uid), int(gid)) iutil.execWithRedirect("restorecon", ["-r", sshdir])
def run_command(self, command, stdin=None, ignore_failure=False): process_error = None try: sys_root = iutil.getSysroot() cmd = iutil.startProgram(command, stderr=subprocess.PIPE, stdin=stdin, root=sys_root) (stdout, stderr) = cmd.communicate() stdout = stdout.decode("utf-8") stderr = stderr.decode("utf-8") if not ignore_failure and cmd.returncode != 0: process_error = "{} failed:\nstdout: \"{}\"\nstderr: \"{}\"".format( command, stdout, stderr) except Exception as e: process_error = str(e) if process_error: self.logger.error(process_error) raise Exception(process_error) return (stdout, stderr)
def setUserSshKey(self, username, key, **kwargs): root = kwargs.get("root", iutil.getSysroot()) pwent = self._getpwnam(username, root) if not pwent: raise ValueError("setUserSshKey: user %s does not exist" % username) homedir = root + pwent[5] if not os.path.exists(homedir): log.error("setUserSshKey: home directory for %s does not exist", username) raise ValueError("setUserSshKey: home directory for %s does not exist" % username) uid = pwent[2] gid = pwent[3] sshdir = os.path.join(homedir, ".ssh") if not os.path.isdir(sshdir): os.mkdir(sshdir, 0o700) os.chown(sshdir, int(uid), int(gid)) authfile = os.path.join(sshdir, "authorized_keys") authfile_existed = os.path.exists(authfile) with iutil.open_with_perm(authfile, "a", 0o600) as f: f.write(key + "\n") # Only change ownership if we created it if not authfile_existed: os.chown(authfile, int(uid), int(gid)) iutil.execWithRedirect("restorecon", ["-r", sshdir])
def check(self): """Check configured storage against software selections. When this method is complete (which should be pretty quickly), the following attributes are available for inspection: success -- A simple boolean defining whether there's enough space or not. deficit -- If unsuccessful, how much space the system is short for current software selections. error_message -- If unsuccessful, an error message describing the situation. This message is suitable for putting in the info bar at the bottom of a Hub. """ self.reset() stat = os.statvfs(iutil.getSysroot()) free = Size(stat.f_bsize * stat.f_bfree) needed = self.payload.spaceRequired log.info("fs space: %s needed: %s", free, needed) self.success = (free > needed) if not self.success: dev_required_size = self.payload.requiredDeviceSize(self.storage.root_device.format) self.deficit = dev_required_size - self.storage.root_device.size self.error_message = _(self.error_template) % self.deficit return self.success
def refresh(self, args=None): NormalTUISpoke.refresh(self, args) msg = _("The rescue environment will now attempt " "to find your Linux installation and mount it under " "the directory : %s. You can then make any changes " "required to your system. Choose '1' to proceed with " "this step.\nYou can choose to mount your file " "systems read-only instead of read-write by choosing " "'2'.\nIf for some reason this process does not work " "choose '3' to skip directly to a shell.\n\n") % ( iutil.getSysroot()) self.window.add_with_separator(TextWidget(msg)) self._container = ListColumnContainer(1) self._container.add(TextWidget(_("Continue")), self._read_write_mount_callback) self._container.add(TextWidget(_("Read-only mount")), self._read_only_mount_callback) self._container.add(TextWidget(_("Skip to shell")), self._skip_to_shell_callback) self._container.add(TextWidget(_("Quit (Reboot)")), self._quit_callback) self.window.add_with_separator(self._container)
def check(self): """Check configured storage against software selections. When this method is complete (which should be pretty quickly), the following attributes are available for inspection: success -- A simple boolean defining whether there's enough space or not. deficit -- If unsuccessful, how much space the system is short for current software selections. error_message -- If unsuccessful, an error message describing the situation. This message is suitable for putting in the info bar at the bottom of a Hub. """ self.reset() stat = iutil.eintr_retry_call(os.statvfs, iutil.getSysroot()) free = Size(stat.f_bsize * stat.f_bfree) needed = self.payload.spaceRequired log.info("fs space: %s needed: %s", free, needed) self.success = (free > needed) if not self.success: dev_required_size = self.payload.requiredDeviceSize(self.storage.rootDevice.format) self.deficit = dev_required_size - self.storage.rootDevice.size self.error_message = _(self.error_template) % self.deficit return self.success
def recreateInitrds(self): """ Recreate the initrds by calling new-kernel-pkg This needs to be done after all configuration files have been written, since dracut depends on some of them. :returns: None """ if not os.path.exists(iutil.getSysroot() + "/usr/sbin/new-kernel-pkg"): log.error( "new-kernel-pkg does not exist - grubby wasn't installed? skipping" ) return for kernel in self.kernelVersionList: log.info("recreating initrd for %s", kernel) if not flags.imageInstall: iutil.execInSysroot( "new-kernel-pkg", ["--mkinitrd", "--dracut", "--depmod", "--update", kernel]) else: # hostonly is not sensible for disk image installations # using /dev/disk/by-uuid/ is necessary due to disk image naming iutil.execInSysroot("dracut", [ "-N", "--persistent-policy", "by-uuid", "-f", "/boot/initramfs-%s.img" % kernel, kernel ])
def initExceptionHandling(anaconda): fileList = [ "/tmp/anaconda.log", "/tmp/packaging.log", "/tmp/program.log", "/tmp/storage.log", "/tmp/ifcfg.log", "/tmp/dnf.log", "/tmp/dnf.rpm.log", "/tmp/yum.log", iutil.getSysroot() + "/root/install.log", "/proc/cmdline" ] if os.path.exists("/tmp/syslog"): fileList.extend(["/tmp/syslog"]) if anaconda.opts and anaconda.opts.ksfile: fileList.extend([anaconda.opts.ksfile]) conf = Config( programName="anaconda", programVersion=startup_utils.get_anaconda_version_string(), programArch=os.uname()[4], attrSkipList=[ "_intf._actions", "_intf._currentAction._xklwrapper", "_intf._currentAction._spokes[\"KeyboardSpoke\"]._xkl_wrapper", "_intf._currentAction._storage_playground", "_intf._currentAction._spokes[\"CustomPartitioningSpoke\"]._storage_playground", "_intf._currentAction.language.translations", "_intf._currentAction.language.locales", "_intf._currentAction._spokes[\"PasswordSpoke\"]._oldweak", "_intf._currentAction._spokes[\"PasswordSpoke\"]._password", "_intf._currentAction._spokes[\"UserSpoke\"]._password", "_intf._currentAction._spokes[\"UserSpoke\"]._oldweak", "_intf.storage.bootloader.password", "_intf.storage.data", "_intf.storage.encryptionPassphrase", "_bootloader.encrypted_password", "_bootloader.password", "payload._groups", "payload._yum" ], localSkipList=["passphrase", "password", "_oldweak", "_password"], fileList=fileList) conf.register_callback("lsblk_output", lsblk_callback, attchmnt_only=True) conf.register_callback("nmcli_dev_list", nmcli_dev_list_callback, attchmnt_only=True) conf.register_callback("type", lambda: "anaconda", attchmnt_only=True) conf.register_callback("addons", list_addons_callback, attchmnt_only=False) if "/tmp/syslog" not in fileList: # no syslog, grab output from journalctl and put it also to the # anaconda-tb file conf.register_callback("journalctl", journalctl_callback, attchmnt_only=False) interactive = not anaconda.displayMode == 'c' handler = AnacondaExceptionHandler(conf, anaconda.intf.meh_interface, ReverseExceptionDump, anaconda.intf.tty_num, anaconda.gui_initialized, interactive) handler.install(anaconda) return conf
def do_run(self): """Resolve the sysroot path only right before doing the copy operatio. If we just added the sysroot path as an argument, it would be resolved when the task queue was created, not when the task is actually executed, which could theoretically result in an incorrect path. """ network.copyFileToPath("/etc/resolv.conf", iutil.getSysroot())
def _copyBootloaderData(self): # Copy bootloader data files from the deployment # checkout to the target root. See # https://bugzilla.gnome.org/show_bug.cgi?id=726757 This # happens once, at installation time. # extlinux ships its modules directly in the RPM in /boot. # For GRUB2, Anaconda installs device.map there. We may need # to add other bootloaders here though (if they can't easily # be fixed to *copy* data into /boot at install time, instead # of shipping it in the RPM). is_efi = isinstance(self.storage.bootloader, EFIBase) physboot = iutil.getTargetPhysicalRoot() + '/boot' ostree_boot_source = iutil.getSysroot() + '/usr/lib/ostree-boot' if not os.path.isdir(ostree_boot_source): ostree_boot_source = iutil.getSysroot() + '/boot' for fname in os.listdir(ostree_boot_source): srcpath = os.path.join(ostree_boot_source, fname) destpath = os.path.join(physboot, fname) # We're only copying directories if not os.path.isdir(srcpath): continue # Special handling for EFI; first, we only want to copy # the data if the system is actually EFI (simulating grub2-efi # being installed). Second, as it's a mount point that's # expected to already exist (so if we used copytree, we'd # traceback). If it doesn't, we're not on a UEFI system, # so we don't want to copy the data. if fname == 'efi': if is_efi: for subname in os.listdir(srcpath): sub_srcpath = os.path.join(srcpath, subname) sub_destpath = os.path.join(destpath, subname) self._safeExecWithRedirect( 'cp', ['-r', '-p', sub_srcpath, sub_destpath]) else: log.info("Copying bootloader data: " + fname) self._safeExecWithRedirect('cp', ['-r', '-p', srcpath, destpath]) # Unfortunate hack, see https://github.com/rhinstaller/anaconda/issues/1188 efi_grubenv_link = physboot + '/grub2/grubenv' if not is_efi and os.path.islink(efi_grubenv_link): os.unlink(efi_grubenv_link)
def initExceptionHandling(anaconda): fileList = ["/tmp/anaconda.log", "/tmp/packaging.log", "/tmp/program.log", "/tmp/storage.log", "/tmp/ifcfg.log", "/tmp/dnf.librepo.log", "/tmp/hawkey.log", "/tmp/lvm.log", iutil.getSysroot() + "/root/install.log", "/proc/cmdline"] if os.path.exists("/tmp/syslog"): fileList.extend(["/tmp/syslog"]) if anaconda.opts and anaconda.opts.ksfile: fileList.extend([anaconda.opts.ksfile]) conf = Config(programName="anaconda", programVersion=startup_utils.get_anaconda_version_string(), programArch=os.uname()[4], attrSkipList=["_intf._actions", "_intf._currentAction._xklwrapper", "_intf._currentAction._spokes[\"KeyboardSpoke\"]._xkl_wrapper", "_intf._currentAction._storage_playground", "_intf._currentAction._spokes[\"CustomPartitioningSpoke\"]._storage_playground", "_intf._currentAction.language.translations", "_intf._currentAction.language.locales", "_intf._currentAction._spokes[\"PasswordSpoke\"]._oldweak", "_intf._currentAction._spokes[\"PasswordSpoke\"]._password", "_intf._currentAction._spokes[\"UserSpoke\"]._password", "_intf._currentAction._spokes[\"UserSpoke\"]._oldweak", "_intf.storage.bootloader.password", "_intf.storage.data", "_intf.storage.ksdata", "_intf.storage.encryption_passphrase", "_intf.data", "_bootloader.encrypted_password", "_bootloader.password", "payload._groups"], localSkipList=["passphrase", "password", "_oldweak", "_password", "try_passphrase"], fileList=fileList) conf.register_callback("lsblk_output", lsblk_callback, attchmnt_only=True) conf.register_callback("nmcli_dev_list", nmcli_dev_list_callback, attchmnt_only=True) conf.register_callback("type", lambda: "anaconda", attchmnt_only=True) conf.register_callback("addons", list_addons_callback, attchmnt_only=False) if "/tmp/syslog" not in fileList: # no syslog, grab output from journalctl and put it also to the # anaconda-tb file conf.register_callback("journalctl", journalctl_callback, attchmnt_only=False) interactive = not anaconda.displayMode == 'c' handler = AnacondaExceptionHandler(conf, anaconda.intf.meh_interface, AnacondaReverseExceptionDump, anaconda.intf.tty_num, anaconda.gui_initialized, interactive) handler.install(anaconda) return conf
def postWriteHook(self, dump_info): anaconda = dump_info.object # See if there is a /root present in the root path and put exception there as well if os.access(iutil.getSysroot() + "/root", os.X_OK): try: dest = iutil.getSysroot() + "/root/%s" % os.path.basename(self.exnFile) shutil.copyfile(self.exnFile, dest) except (shutil.Error, IOError): log.error("Failed to copy %s to %s/root", self.exnFile, iutil.getSysroot()) # run kickstart traceback scripts (if necessary) try: kickstart.runTracebackScripts(anaconda.ksdata.scripts) # pylint: disable=bare-except except: pass iutil.ipmi_report(IPMI_FAILED)
def postInstall(self): """ Perform post-installation tasks. """ progressQ.send_message(_("Performing post-installation setup tasks")) blivet.util.umount(INSTALL_TREE) super(LiveImagePayload, self).postInstall() # Make sure the new system has a machine-id, it won't boot without it if not os.path.exists(iutil.getSysroot() + "/etc/machine-id"): iutil.execInSysroot("systemd-machine-id-setup", [])
def write_configs(self, storage, ksdata, instClass, users): """ Write configuration file(s) :param storage: Blivet storage object :param ksdata: Kickstart data object :param instClass: Anaconda installclass object :param users: Anaconda users object """ with open(getSysroot()+"/etc/sysconfig/docker-storage", "w") as fp: fp.write('DOCKER_STORAGE_OPTIONS="--storage-driver btrfs"\n')
def _copyBootloaderData(self): # Copy bootloader data files from the deployment # checkout to the target root. See # https://bugzilla.gnome.org/show_bug.cgi?id=726757 This # happens once, at installation time. # extlinux ships its modules directly in the RPM in /boot. # For GRUB2, Anaconda installs device.map there. We may need # to add other bootloaders here though (if they can't easily # be fixed to *copy* data into /boot at install time, instead # of shipping it in the RPM). is_efi = isinstance(self.storage.bootloader, EFIBase) physboot = iutil.getTargetPhysicalRoot() + '/boot' ostree_boot_source = iutil.getSysroot() + '/usr/lib/ostree-boot' if not os.path.isdir(ostree_boot_source): ostree_boot_source = iutil.getSysroot() + '/boot' for fname in os.listdir(ostree_boot_source): srcpath = os.path.join(ostree_boot_source, fname) destpath = os.path.join(physboot, fname) # We're only copying directories if not os.path.isdir(srcpath): continue # Special handling for EFI; first, we only want to copy # the data if the system is actually EFI (simulating grub2-efi # being installed). Second, as it's a mount point that's # expected to already exist (so if we used copytree, we'd # traceback). If it doesn't, we're not on a UEFI system, # so we don't want to copy the data. if fname == 'efi': if is_efi: for subname in os.listdir(srcpath): sub_srcpath = os.path.join(srcpath, subname) sub_destpath = os.path.join(destpath, subname) self._safeExecWithRedirect('cp', ['-r', '-p', sub_srcpath, sub_destpath]) else: log.info("Copying bootloader data: " + fname) self._safeExecWithRedirect('cp', ['-r', '-p', srcpath, destpath]) # Unfortunate hack, see https://github.com/rhinstaller/anaconda/issues/1188 efi_grubenv_link = physboot + '/grub2/grubenv' if not is_efi and os.path.islink(efi_grubenv_link): os.unlink(efi_grubenv_link)
def _copyDriverDiskFiles(self): # Multiple driver disks may be loaded, so we need to glob for all # the firmware files in the common DD firmware directory for f in glob(DD_FIRMWARE+"/*"): try: shutil.copyfile(f, "%s/lib/firmware/" % iutil.getSysroot()) except IOError as e: log.error("Could not copy firmware file %s: %s", f, e.strerror) #copy RPMS for d in glob(DD_RPMS): shutil.copytree(d, iutil.getSysroot() + "/root/" + os.path.basename(d)) #copy modules and firmware into root's home directory if os.path.exists(DD_ALL): try: shutil.copytree(DD_ALL, iutil.getSysroot() + "/root/DD") except IOError as e: log.error("failed to copy driver disk files: %s", e.strerror)
def postInstall(self): """ Perform post-installation tasks. """ progressQ.send_message(_("Performing post-installation setup tasks")) blivet.util.umount(INSTALL_TREE) super(LiveImagePayload, self).postInstall() # Make sure the new system has a machine-id, it won't boot without it if not os.path.exists(iutil.getSysroot()+"/etc/machine-id"): iutil.execInSysroot("systemd-machine-id-setup", [])
def execute(self, storage, ksdata, instclass, users): """ The execute method that should make changes to the installed system. It is called only once in the post-install setup phase. :see: setup :param users: information about created users :type users: pyanaconda.users.Users instance """ if self.dry_run: # nothing to be done in the dry-run mode return target_content_dir = utils.join_paths(getSysroot(), common.TARGET_CONTENT_DIR) utils.ensure_dir_exists(target_content_dir) if self.content_type == "datastream": shutil.copy2(self.preinst_content_path, target_content_dir) elif self.content_type == "rpm": # copy the RPM to the target system shutil.copy2(self.raw_preinst_content_path, target_content_dir) # and install it with yum ret = iutil.execInSysroot("yum", ["-y", "install", self.raw_postinst_content_path]) if ret != 0: raise common.ExtractionError("Failed to install content " "RPM to the target system") elif self.content_type == "scap-security-guide": # nothing needed pass else: utils.universal_copy(utils.join_paths(common.INSTALLATION_CONTENT_DIR, "*"), target_content_dir) common.run_oscap_remediate(self.profile_id, self.postinst_content_path, self.datastream_id, self.xccdf_id, self.postinst_tailoring_path, chroot=getSysroot())
def execute(self, storage, ksdata, instClass, users): # the KdumpSpoke should run only if requested if not flags.cmdline.getbool("kdump_addon", default=False): return if self.enabled: action = "enable" else: action = "disable" iutil.execWithRedirect("systemctl", [action, "kdump.service"], root=iutil.getSysroot())