def mountImage(isodir, tree): while True: if os.path.isfile(isodir): image = isodir else: image = findFirstIsoImage(isodir) if image is None: exn = MissingImageError() if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: continue image = os.path.normpath("%s/%s" % (isodir, image)) try: blivet.util.mount(image, tree, fstype='iso9660', options="ro") except OSError: exn = MissingImageError() if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: continue else: break
def mountImage(isodir, tree): # FIXME: This is duplicated in SetUpHardDriveSourceTask.run while True: if os.path.isfile(isodir): image = isodir else: image = find_first_iso_image(isodir) if image is None: exn = MissingImageError() if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: continue image = os.path.normpath("%s/%s" % (isodir, image)) try: blivet.util.mount(image, tree, fstype='iso9660', options="ro") except OSError: exn = MissingImageError() if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: continue else: break
def run(self, chroot): """ Run the kickstart script @param chroot directory path to chroot into before execution """ if self.inChroot: scriptRoot = chroot else: scriptRoot = "/" (fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp") os.write(fd, self.script.encode("utf-8")) os.close(fd) os.chmod(path, 0o700) # Always log stdout/stderr from scripts. Using --log just lets you # pick where it goes. The script will also be logged to program.log # because of execWithRedirect. if self.logfile: if self.inChroot: messages = "%s/%s" % (scriptRoot, self.logfile) else: messages = self.logfile d = os.path.dirname(messages) if not os.path.exists(d): os.makedirs(d) else: # Always log outside the chroot, we copy those logs into the # chroot later. messages = "/tmp/%s.log" % os.path.basename(path) with open(messages, "w") as fp: rc = util.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)], stdout=fp, root=scriptRoot) if rc != 0: script_log.error( "Error code %s running the kickstart script at line %s", rc, self.lineno) if self.errorOnFail: err = "" with open(messages, "r") as fp: err = "".join(fp.readlines()) # Show error dialog even for non-interactive flags.ksprompt = True errorHandler.cb(ScriptError(self.lineno, err)) util.ipmi_report(IPMI_ABORTED) sys.exit(0)
def unmountCD(dev): if not dev: return while True: try: dev.format.unmount() except FSError as e: log.error("exception in _unmountCD: %s", e) exn = MediaUnmountError() errorHandler.cb(exn, dev) else: break
def run(self, chroot): """ Run the kickstart script @param chroot directory path to chroot into before execution """ if self.inChroot: scriptRoot = chroot else: scriptRoot = "/" (fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp") os.write(fd, self.script.encode("utf-8")) os.close(fd) os.chmod(path, 0o700) # Always log stdout/stderr from scripts. Using --log just lets you # pick where it goes. The script will also be logged to program.log # because of execWithRedirect. if self.logfile: if self.inChroot: messages = "%s/%s" % (scriptRoot, self.logfile) else: messages = self.logfile d = os.path.dirname(messages) if not os.path.exists(d): os.makedirs(d) else: # Always log outside the chroot, we copy those logs into the # chroot later. messages = "/tmp/%s.log" % os.path.basename(path) with open(messages, "w") as fp: rc = util.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)], stdout=fp, root=scriptRoot) if rc != 0: script_log.error("Error code %s running the kickstart script at line %s", rc, self.lineno) if self.errorOnFail: err = "" with open(messages, "r") as fp: err = "".join(fp.readlines()) # Show error dialog even for non-interactive flags.ksprompt = True errorHandler.cb(ScriptError(self.lineno, err)) util.ipmi_report(IPMI_ABORTED) sys.exit(0)
def reset_storage(storage, scan_all=False, retry=True): """Reset the storage model. :param storage: an instance of the Blivet's storage object :param scan_all: should we scan all devices in the system? :param retry: should we allow to retry the reset? """ # Clear the exclusive disks to scan all devices in the system. if scan_all: disk_select_proxy = STORAGE.get_proxy(DISK_SELECTION) disk_select_proxy.SetExclusiveDisks([]) # Do the reset. while True: try: _reset_storage(storage) except StorageError as e: # Is the retry allowed? if not retry: raise # Does the user want to retry? elif error_handler.cb(e) == ERROR_RAISE: raise # Retry the storage reset. else: continue else: # No need to retry. break
def turn_on_swap(self, root_path=""): """Activate the system's swap space.""" for device in self.swap_devices: if isinstance(device, FileDevice): # set up FileDevices' parents now that they are accessible target_dir = "%s/%s" % (root_path, device.path) parent = get_containing_device(target_dir, self.devicetree) if not parent: log.error("cannot determine which device contains " "directory %s", device.path) device.parents = [] self.devicetree._remove_device(device) continue else: device.parents = [parent] while True: if device.status and device.format.status: break try: device.setup() device.format.setup() except (blockdev.SwapOldError, blockdev.SwapSuspendError, blockdev.SwapUnknownError, blockdev.SwapPagesizeError) as e: log.error("Failed to activate swap on '%s': %s", device.name, str(e)) break except (StorageError, blockdev.BlockDevError) as e: if error_handler.cb(e) == ERROR_RAISE: raise else: break
def reset_storage(scan_all=False, retry=True): """Reset the storage model. :param scan_all: should we scan all devices in the system? :param retry: should we allow to retry the reset? """ # Clear the exclusive disks to scan all devices in the system. if scan_all: disk_select_proxy = STORAGE.get_proxy(DISK_SELECTION) disk_select_proxy.SetExclusiveDisks([]) # Scan the devices. storage_proxy = STORAGE.get_proxy() while True: try: task_path = storage_proxy.ScanDevicesWithTask() task_proxy = STORAGE.get_proxy(task_path) sync_run_task(task_proxy) except DBusError as e: # Is the retry allowed? if not retry: raise # Does the user want to retry? elif error_handler.cb(e) == ERROR_RAISE: raise # Retry the storage reset. else: continue else: # No need to retry. break # Reset the partitioning. storage_proxy.ResetPartitioning()
def setup(self): super().setup() # Mount the live device and copy from it instead of the overlay at / osimg_spec = self._get_live_os_image() if not osimg_spec: raise PayloadSetupError("No live image found!") osimg = payload_utils.resolve_device(osimg_spec) if not osimg: raise PayloadInstallError("Unable to find osimg for {}".format(osimg_spec)) osimg_path = payload_utils.get_device_path(osimg) if not stat.S_ISBLK(os.stat(osimg_path)[stat.ST_MODE]): exn = PayloadSetupError("{} is not a valid block device".format(osimg_spec)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn rc = payload_utils.mount(osimg_path, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: raise PayloadInstallError("Failed to mount the install tree") # Grab the kernel version list now so it's available after umount self._update_kernel_version_list() source = os.statvfs(INSTALL_TREE) self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
def install(self): """ Install the payload. """ 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+"/", ROOT_PATH] 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)
def setup(self, storage, instClass): super().setup(storage, instClass) # Mount the live device and copy from it instead of the overlay at / osimg = storage.devicetree.get_device_by_path( self.data.method.partition) if not osimg: raise PayloadInstallError("Unable to find osimg for %s" % self.data.method.partition) if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]): exn = PayloadSetupError("%s is not a valid block device" % (self.data.method.partition, )) if errorHandler.cb(exn) == ERROR_RAISE: raise exn rc = blivet.util.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro") 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 = os.statvfs(INSTALL_TREE) self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
def turn_on_swap(self, root_path=""): """Activate the system's swap space.""" for device in self.swap_devices: if isinstance(device, FileDevice): # set up FileDevices' parents now that they are accessible target_dir = "%s/%s" % (root_path, device.path) parent = get_containing_device(target_dir, self.devicetree) if not parent: log.error( "cannot determine which device contains " "directory %s", device.path) device.parents = [] self.devicetree._remove_device(device) continue else: device.parents = [parent] while True: if device.status and device.format.status: break try: device.setup() device.format.setup() except (blockdev.SwapOldError, blockdev.SwapSuspendError, blockdev.SwapUnknownError, blockdev.SwapPagesizeError) as e: log.error("Failed to activate swap on '%s': %s", device.name, str(e)) break except (StorageError, blockdev.BlockDevError) as e: if error_handler.cb(e) == ERROR_RAISE: raise else: break
def mountImageDirectory(method, storage): # No need to mount it again. if os.path.ismount(ISO_DIR): return if method.method == "harddrive": if method.biospart: log.warning("biospart support is not implemented") devspec = method.biospart else: devspec = method.partition # FIXME: teach DeviceTree.resolveDevice about biospart device = storage.devicetree.resolveDevice(devspec) while True: try: device.setup() device.format.setup(mountpoint=ISO_DIR) except StorageError as e: log.error("couldn't mount ISO source directory: %s", e) exn = MediaMountError(str(e), device) if errorHandler.cb(exn) == ERROR_RAISE: raise exn elif method.method.startswith("nfsiso:"): # XXX what if we mount it on ISO_DIR and then create a symlink # if there are no isos instead of the remount? # mount the specified directory path = method.dir if method.dir.endswith(".iso"): path = os.path.dirname(method.dir) url = "%s:%s" % (method.server, path) while True: try: blivet.util.mount(url, ISO_DIR, fstype="nfs", options=method.options) except OSError as e: log.error("couldn't mount ISO source directory: %s", e) exn = MediaMountError(str(e), device) if errorHandler.cb(exn) == ERROR_RAISE: raise exn
def _run(self): """Runs the task (callable) assigned to this Task class instance.""" try: # Run the task. self._task_cb(*self._task_args, **self._task_kwargs) except Exception as e: # pylint: disable=broad-except # Handle an error. if errorHandler.cb(e) == ERROR_RAISE: raise
def setup(self, storage, instClass): super(LiveImagePayload, self).setup(storage, instClass) # Mount the live device and copy from it instead of the overlay at / osimg = storage.devicetree.getDeviceByPath(self.data.method.partition) if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]): exn = PayloadSetupError("%s is not a valid block device" % (self.data.method.partition,)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn blivet.util.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro")
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 + "/", util.getSysroot() ] try: rc = util.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(util.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) util.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
def cryptPassword(password, algo=None): salts = {'md5': '$1$', 'sha256': '$5$', 'sha512': '$6$'} if algo not in salts: algo = 'sha512' cryptpw = iutil.encrypt_password(password, salts[algo], 16) if cryptpw is None: exn = PasswordCryptError(algo=algo) if errorHandler.cb(exn) == ERROR_RAISE: raise exn return cryptpw
def install(self, args=None): buf = util.execWithCapture("zipl", [], root=util.getSysroot()) for line in buf.splitlines(): if line.startswith("Preparing boot device: "): # Output here may look like: # Preparing boot device: dasdb (0200). # Preparing boot device: dasdl. # We want to extract the device name and pass that. name = re.sub(r".+?: ", "", line) self.stage1_name = re.sub(r"(\s\(.+\))?\.$", "", name) # a limitation of s390x is that the kernel parameter list must not # exceed 896 bytes; there is nothing we can do about this, so just # catch the error and show it to the user instead of crashing elif line.startswith("Error: The length of the parameters "): errorHandler.cb(ZIPLError(line)) if not self.stage1_name: raise BootLoaderError("could not find IPL device") # do the reipl util.reIPL(self.stage1_name)
def install(self, args=None): buf = util.execWithCapture("zipl", [], root=conf.target.system_root) for line in buf.splitlines(): if line.startswith("Preparing boot device: "): # Output here may look like: # Preparing boot device: dasdb (0200). # Preparing boot device: dasdl. # We want to extract the device name and pass that. name = re.sub(r".+?: ", "", line) self.stage1_name = re.sub(r"(\s\(.+\))?\.$", "", name) # a limitation of s390x is that the kernel parameter list must not # exceed 896 bytes; there is nothing we can do about this, so just # catch the error and show it to the user instead of crashing elif line.startswith("Error: The length of the parameters "): errorHandler.cb(ZIPLError(line)) if not self.stage1_name: raise BootLoaderError("could not find IPL device") # do the reipl util.reIPL(self.stage1_name)
def install(self): """ Install the payload if it is a tar. Otherwise fall back to rsync of INSTALL_TREE """ # If it doesn't look like a tarfile use the super's install() if not self.is_tarfile: super().install() return # Use 2x the archive's size to estimate the size of the install # This is used to drive the progress display self.source_size = os.stat(self.image_path)[stat.ST_SIZE] * 2 self.pct_lock = Lock() self.pct = 0 threadMgr.add( AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress)) cmd = "tar" # preserve: ACL's, xattrs, and SELinux context args = [ "--selinux", "--acls", "--xattrs", "--xattrs-include", "*", "--exclude", "/dev/", "--exclude", "/proc/", "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*", "--exclude", "/etc/machine-id", "-xaf", self.image_path, "-C", util.getSysroot() ] try: rc = util.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: 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 for kernel in self.kernelVersionList: log.info("Generating rescue image for %s", kernel) util.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
def install(self): """ Install the payload if it is a tar. Otherwise fall back to rsync of INSTALL_TREE """ # If it doesn't look like a tarfile use the super's install() if not self.is_tarfile: super(LiveImageKSPayload, self).install() return # Use 2x the archive's size to estimate the size of the install # This is used to drive the progress display self.source_size = os.stat(self.image_path)[stat.ST_SIZE] * 2 self.pct_lock = Lock() self.pct = 0 threadMgr.add(AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress)) cmd = "tar" # preserve: ACL's, xattrs, and SELinux context args = ["--selinux", "--acls", "--xattrs", "--xattrs-include", "*", "--exclude", "/dev/", "--exclude", "/proc/", "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*", "--exclude", "/etc/machine-id", "-xaf", self.image_path, "-C", 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: 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 for kernel in self.kernelVersionList: log.info("Generating rescue image for %s", kernel) iutil.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
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 run_task(self): """Run the DBus task.""" try: # Report the progress messages. self._task_proxy.ProgressChanged.connect(self._show_message) # Run the task. sync_run_task(self._task_proxy) except DBusError as e: # Handle a remote error. if errorHandler.cb(e) == ERROR_RAISE: raise finally: # Disconnect from the signal. self._task_proxy.ProgressChanged.disconnect()
def cryptPassword(password, algo=None): salts = {'md5': crypt.METHOD_MD5, 'sha256': crypt.METHOD_SHA256, 'sha512': crypt.METHOD_SHA512} if algo not in salts: algo = 'sha512' cryptpw = crypt.crypt(password, salts[algo]) if cryptpw is None: exn = PasswordCryptError(algo=algo) if errorHandler.cb(exn) == ERROR_RAISE: raise exn return cryptpw
def install(self): """ Install the payload if it is a tar. Otherwise fall back to rsync of INSTALL_TREE """ # If it doesn't look like a tarfile use the super's install() if not self.is_tarfile: super().install() return # Use 2x the archive's size to estimate the size of the install # This is used to drive the progress display self.source_size = os.stat(self.image_path)[stat.ST_SIZE] * 2 self.pct_lock = Lock() self.pct = 0 threadMgr.add( AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress)) cmd = "tar" # preserve: ACL's, xattrs, and SELinux context args = [ "--numeric-owner", "--selinux", "--acls", "--xattrs", "--xattrs-include", "*", "--exclude", "dev/*", "--exclude", "proc/*", "--exclude", "tmp/*", "--exclude", "sys/*", "--exclude", "run/*", "--exclude", "boot/*rescue*", "--exclude", "boot/loader", "--exclude", "boot/efi/loader", "--exclude", "etc/machine-id", "-xaf", self.image_path, "-C", conf.target.system_root ] try: rc = util.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: 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)
def crypt_password(password): """Crypt a password. Process a password with appropriate salted one-way algorithm. :param str password: password to be crypted :returns: crypted representation of the original password :rtype: str """ cryptpw = crypt.crypt(password, crypt.METHOD_SHA512) if cryptpw is None: exn = PasswordCryptError(algo=crypt.METHOD_SHA512) if errorHandler.cb(exn) == ERROR_RAISE: raise exn return cryptpw
def setup(self): """ Check the availability and size of the image. """ super().setup() if self.data.liveimg.url.startswith("file://"): error = self._setup_file_image() else: error = self._setup_url_image() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn log.debug("liveimg size is %s", self._min_size)
def turn_on_filesystems(storage, callbacks=None): """Perform installer-specific activation of storage configuration. :param storage: the storage object :type storage: :class:`~.storage.InstallerStorage` :param callbacks: callbacks to be invoked when actions are executed :type callbacks: return value of the :func:`blivet.callbacks.create_new_callbacks_register` """ storage.devicetree.teardown_all() try: storage.do_it(callbacks) except (FSResizeError, FormatResizeError) as e: if error_handler.cb(e) == ERROR_RAISE: raise storage.turn_on_swap()
def run_task(self): """Runs the task (callable) assigned to this Task class instance. This method is mainly aimed at lightweight Task subclassing, without the need to reimplement the full start() method with all the signal triggers and related machinery. """ if self._task: try: # Run the task. self._task(*self._task_args, **self._task_kwargs) except Exception as e: # pylint: disable=broad-except # Handle an error. if errorHandler.cb(e) == ERROR_RAISE: raise else: log.error("Task %s callable not set.", self.name)
def setup(self, storage, instClass): """ Check the availability and size of the image. """ # This is on purpose, we don't want to call LiveImagePayload's setup method. ImagePayload.setup(self, storage, instClass) if self.data.method.url.startswith("file://"): error = self._setup_file_image() else: error = self._setup_url_image() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn log.debug("liveimg size is %s", self._min_size)
def setup(self, storage, instClass): super(LiveImagePayload, self).setup(storage, instClass) # Mount the live device and copy from it instead of the overlay at / osimg = storage.devicetree.getDeviceByPath(self.data.method.partition) if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]): exn = PayloadSetupError("%s is not a valid block device" % (self.data.method.partition,)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn rc = blivet.util.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro") 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)
def setup(self): """ Check the availability and size of the image. """ # This is on purpose, we don't want to call LiveImagePayload's setup method. # FIXME: this should be solved on a inheritance level not like this Payload.setup(self) if self.data.method.url.startswith("file://"): error = self._setup_file_image() else: error = self._setup_url_image() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn log.debug("liveimg size is %s", self._min_size)
def turn_on_filesystems(storage, callbacks=None): """Perform installer-specific activation of storage configuration. :param storage: the storage object :type storage: :class:`~.storage.InstallerStorage` :param callbacks: callbacks to be invoked when actions are executed :type callbacks: return value of the :func:`blivet.callbacks.create_new_callbacks_register` """ storage.devicetree.teardown_all() try: storage.do_it(callbacks) _setup_bootable_devices(storage) storage.dump_state("final") except (FSResizeError, FormatResizeError) as e: if error_handler.cb(e) == ERROR_RAISE: raise storage.turn_on_swap()
def _handleMissing(self, exn): log.info("%s %s" % (self.__class__.__name__, inspect.stack()[0][3])) if self.data.packages.handleMissing == KS_MISSING_IGNORE: return # If we're doing non-interactive ks install, raise CmdlineError, # otherwise the system will just reboot automatically if flags.automatedInstall and not flags.ksprompt: errtxt = _("CmdlineError: Missing package: %s") % str(exn) log.error(errtxt) raise CmdlineError(errtxt) elif errorHandler.cb(exn) == ERROR_RAISE: # The progress bar polls kind of slowly, thus installation could # still continue for a bit before the quit message is processed. # Let's sleep forever to prevent any further actions and wait for # the main thread to quit the process. progressQ.send_quit(1) while True: time.sleep(100000)
def setup(self, storage, instClass): super(LiveImagePayload, self).setup(storage, instClass) # Mount the live device and copy from it instead of the overlay at / osimg = storage.devicetree.getDeviceByPath(self.data.method.partition) if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]): exn = PayloadSetupError("%s is not a valid block device" % (self.data.method.partition, )) if errorHandler.cb(exn) == ERROR_RAISE: raise exn rc = blivet.util.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: raise PayloadInstallError("Failed to mount the install tree") source = iutil.eintr_retry_call(os.statvfs, INSTALL_TREE) self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
def install(self): progress_message(N_('Starting package installation process')) # Get the packages configuration and selection data. configuration = self.get_packages_configuration() selection = self.get_packages_selection() # Add the rpm macros to the global transaction environment task = SetRPMMacrosTask(configuration) task.run() try: # Resolve packages. task = ResolvePackagesTask(self._dnf_manager, selection) task.run() except NonCriticalInstallationError as e: # FIXME: This is a temporary workaround. # Allow users to handle the error. If they don't want # to continue with the installation, raise a different # exception to make sure that we will not run the error # handler again. if error_handler.cb(e) == ERROR_RAISE: raise InstallationError(str(e)) from e # Set up the download location. task = PrepareDownloadLocationTask(self._dnf_manager) task.run() # Download the packages. task = DownloadPackagesTask(self._dnf_manager) task.progress_changed_signal.connect(self._progress_cb) task.run() # Install the packages. task = InstallPackagesTask(self._dnf_manager) task.progress_changed_signal.connect(self._progress_cb) task.run() # Clean up the download location. task = CleanUpDownloadLocationTask(self._dnf_manager) task.run()
def setup(self, storage, instClass): """ Check the availability and size of the image. """ # This is on purpose, we don't want to call LiveImagePayload's setup method. ImagePayload.setup(self, storage, instClass) self._proxies = {} if self.data.method.proxy: try: proxy = ProxyString(self.data.method.proxy) self._proxies = {"http": proxy.url, "https": proxy.url} except ProxyStringError as e: log.info("Failed to parse proxy for liveimg --proxy=\"%s\": %s", self.data.method.proxy, e) error = None try: req = urllib.urlopen(self.data.method.url, proxies=self._proxies) except IOError as e: log.error("Error opening liveimg: %s", e) error = e else: # If it is a http request we need to check the code method = self.data.method.url.split(":", 1)[0] if method.startswith("http") and req.getcode() != 200: error = "http request returned %s" % req.getcode() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # At this point we know we can get the image and what its size is # Make a guess as to minimum size needed: # Enough space for image and image * 3 if req.info().get("content-length"): self._min_size = int(req.info().get("content-length")) * 4 log.debug("liveimg size is %s", self._min_size)
def cryptPassword(password, algo=None): salts = {"md5": "$1$", "sha256": "$5$", "sha512": "$6$"} saltlen = 2 if algo is None: algo = "sha512" if algo == "md5" or algo == "sha256" or algo == "sha512": saltlen = 16 saltstr = salts[algo] for _i in range(saltlen): saltstr = saltstr + random.choice(string.ascii_letters + string.digits + "./") cryptpw = crypt.crypt(password, saltstr) if cryptpw is None: exn = PasswordCryptError(algo=algo) if errorHandler.cb(exn) == ERROR_RAISE: raise exn return cryptpw
def install_boot_loader(storage): """Do the final write of the boot loader. :param storage: an instance of the storage """ log.debug("Installing the boot loader.") stage1_device = storage.bootloader.stage1_device log.info("boot loader stage1 target device is %s", stage1_device.name) stage2_device = storage.bootloader.stage2_device log.info("boot loader stage2 target device is %s", stage2_device.name) # FIXME: do this from elsewhere? storage.bootloader.set_boot_args(storage) try: storage.bootloader.write() except BootLoaderError as e: log.error("bootloader.write failed: %s", e) if errorHandler.cb(e) == ERROR_RAISE: raise
def setup(self, storage): super().setup(storage) # Mount the live device and copy from it instead of the overlay at / osimg = storage.devicetree.get_device_by_path(self.data.method.partition) if not osimg: raise PayloadInstallError("Unable to find osimg for %s" % self.data.method.partition) if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]): exn = PayloadSetupError("%s is not a valid block device" % (self.data.method.partition,)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn rc = payload_utils.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: raise PayloadInstallError("Failed to mount the install tree") # Grab the kernel version list now so it's available after umount self._update_kernel_version_list() source = os.statvfs(INSTALL_TREE) self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
def try_populate_devicetree(devicetree): """ Try to populate the given devicetree while catching errors and dealing with some special ones in a nice way (giving user chance to do something about them). :param devicetree: devicetree to try to populate :type decicetree: :class:`blivet.devicetree.DeviceTree` """ while True: try: devicetree.populate() except StorageError as e: if errorHandler.cb(e) == ERROR_RAISE: raise else: continue else: break return
def cryptPassword(password, algo=None): salts = {'md5': '$1$', 'sha256': '$5$', 'sha512': '$6$'} saltlen = 2 if algo is None: algo = 'sha512' if algo == 'md5' or algo == 'sha256' or algo == 'sha512': saltlen = 16 saltstr = salts[algo] for _i in range(saltlen): saltstr = saltstr + random.choice(string.ascii_letters + string.digits + './') cryptpw = crypt.crypt(password, saltstr) if cryptpw is None: exn = PasswordCryptError(algo=algo) if errorHandler.cb(exn) == ERROR_RAISE: raise exn return cryptpw
def reset_storage(storage, scan_all=False, teardown=False, retry=True): """Reset the storage model. :param storage: an instance of the Blivet's storage object :param scan_all: should we scan all devices in the system? :param teardown: should we teardown devices in the current device tree? :param retry: should we allow to retry the reset? """ # Deactivate all devices. if teardown: try: storage.devicetree.teardown_all() except Exception: # pylint: disable=broad-except log_exception_info(log.error, "Failure tearing down device tree.") # Clear the exclusive disks to scan all devices in the system. if scan_all: disk_select_proxy = STORAGE.get_proxy(DISK_SELECTION) disk_select_proxy.SetExclusiveDisks([]) # Do the reset. while True: try: _reset_storage(storage) except StorageError as e: # Is the retry allowed? if not retry: raise # Does the user want to retry? elif error_handler.cb(e) == ERROR_RAISE: raise # Retry the storage reset. else: continue else: # No need to retry. break
def findFirstIsoImage(path): """ Find the first iso image in path This also supports specifying a specific .iso image Returns the basename of the image """ try: os.stat(path) except OSError: return None arch = _arch if os.path.isfile(path) and path.endswith(".iso"): files = [os.path.basename(path)] path = os.path.dirname(path) else: files = os.listdir(path) for fn in files: what = path + '/' + fn log.debug("Checking %s", what) if not isys.isIsoImage(what): continue log.debug("mounting %s on /mnt/install/cdimage", what) try: blivet.util.mount(what, "/mnt/install/cdimage", fstype="iso9660", options="ro") except OSError: continue if not os.access("/mnt/install/cdimage/.discinfo", os.R_OK): blivet.util.umount("/mnt/install/cdimage") continue log.debug("Reading .discinfo") f = open("/mnt/install/cdimage/.discinfo") f.readline() # skip timestamp f.readline() # skip release description discArch = f.readline().strip() # read architecture f.close() log.debug("discArch = %s", discArch) if discArch != arch: log.warning("findFirstIsoImage: architectures mismatch: %s, %s", discArch, arch) blivet.util.umount("/mnt/install/cdimage") continue # If there's no repodata, there's no point in trying to # install from it. if not os.access("/mnt/install/cdimage/repodata", os.R_OK): log.warning("%s doesn't have repodata, skipping", what) blivet.util.umount("/mnt/install/cdimage") continue # warn user if images appears to be wrong size if os.stat(what)[stat.ST_SIZE] % 2048: log.warning("%s appears to be corrupted", what) exn = InvalidImageSizeError("size is not a multiple of 2048 bytes", what) if errorHandler.cb(exn) == ERROR_RAISE: raise exn log.info("Found disc at %s", fn) blivet.util.umount("/mnt/install/cdimage") return fn return None
def preInstall(self, *args, **kwargs): """ Get image and loopback mount it. This is called after partitioning is setup, we now have space to grab the image. If it is a network source Download it to sysroot and provide feedback during the download (using urlgrabber callback). If it is a file:// source then use the file directly. """ error = None if self.data.method.url.startswith("file://"): self.image_path = self.data.method.url[7:] else: error = self._preInstall_url_image() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Used to make install progress % look correct self._adj_size = os.stat(self.image_path)[stat.ST_SIZE] if self.data.method.checksum: progressQ.send_message(_("Checking image checksum")) sha256 = hashlib.sha256() with open(self.image_path, "rb") as f: while True: data = f.read(1024*1024) if not data: break sha256.update(data) filesum = sha256.hexdigest() log.debug("sha256 of %s is %s", self.data.method.url, filesum) if lowerASCII(self.data.method.checksum) != filesum: log.error("%s does not match checksum.", self.data.method.checksum) exn = PayloadInstallError("Checksum of image does not match") if errorHandler.cb(exn) == ERROR_RAISE: raise exn # If this looks like a tarfile, skip trying to mount it if self.is_tarfile: return # Mount the image and check to see if it is a LiveOS/*.img # style squashfs image. If so, move it to IMAGE_DIR and mount the real # root image on INSTALL_TREE rc = blivet.util.mount(self.image_path, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: log.error("mount error (%s) with %s", rc, self.image_path) exn = PayloadInstallError("mount error %s" % rc) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # 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 img_files = glob.glob(INSTALL_TREE+"/LiveOS/*.img") if img_files: # move the mount to IMAGE_DIR os.makedirs(IMAGE_DIR, 0o755) # work around inability to move shared filesystems rc = iutil.execWithRedirect("mount", ["--make-rprivate", "/"]) if rc == 0: rc = iutil.execWithRedirect("mount", ["--move", INSTALL_TREE, IMAGE_DIR]) if rc != 0: log.error("error %s moving mount", rc) exn = PayloadInstallError("mount error %s" % rc) if errorHandler.cb(exn) == ERROR_RAISE: raise exn img_file = IMAGE_DIR+"/LiveOS/"+os.path.basename(sorted(img_files)[0]) rc = blivet.util.mount(img_file, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: log.error("mount error (%s) with %s", rc, img_file) exn = PayloadInstallError("mount error %s with %s" % (rc, img_file)) 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)
def preInstall(self, *args, **kwargs): """ Download image and loopback mount it. This is called after partitioning is setup, we now have space to grab the image. Download it to ROOT_PATH and provide feedback during the download (using urlgrabber callback). """ # Setup urlgrabber and call back to download image to ROOT_PATH progress = URLGrabberProgress() ugopts = {"ssl_verify_peer": not self.data.method.noverifyssl, "ssl_verify_host": not self.data.method.noverifyssl, "proxies" : self._proxies, "progress_obj" : progress, "copy_local" : True} error = None try: ug = URLGrabber() ug.urlgrab(self.data.method.url, self.image_path, **ugopts) except URLGrabError as e: log.error("Error downloading liveimg: %s", e) error = e else: if not os.path.exists(self.image_path): error = "Failed to download %s, file doesn't exist" % self.data.method.url log.error(error) if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Used to make install progress % look correct self._adj_size = os.stat(self.image_path)[stat.ST_SIZE] if self.data.method.checksum: progressQ.send_message(_("Checking image checksum")) sha256 = hashlib.sha256() with open(self.image_path, "rb") as f: while True: data = f.read(1024*1024) if not data: break sha256.update(data) filesum = sha256.hexdigest() log.debug("sha256 of %s is %s", self.data.method.url, filesum) if lowerASCII(self.data.method.checksum) != filesum: log.error("%s does not match checksum.", self.data.method.checksum) exn = PayloadInstallError("Checksum of image does not match") if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Mount the image and check to see if it is a LiveOS/*.img # style squashfs image. If so, move it to IMAGE_DIR and mount the real # root image on INSTALL_TREE blivet.util.mount(self.image_path, INSTALL_TREE, fstype="auto", options="ro") if os.path.exists(INSTALL_TREE+"/LiveOS"): # Find the first .img in the directory and mount that on INSTALL_TREE img_files = glob.glob(INSTALL_TREE+"/LiveOS/*.img") if img_files: img_file = os.path.basename(sorted(img_files)[0]) # move the mount to IMAGE_DIR os.makedirs(IMAGE_DIR, 0755) # work around inability to move shared filesystems iutil.execWithRedirect("mount", ["--make-rprivate", "/"]) iutil.execWithRedirect("mount", ["--move", INSTALL_TREE, IMAGE_DIR]) blivet.util.mount(IMAGE_DIR+"/LiveOS/"+img_file, INSTALL_TREE, fstype="auto", options="ro")
def findFirstIsoImage(path): """ Find the first iso image in path This also supports specifying a specific .iso image Returns the basename of the image """ try: os.stat(path) except OSError: return None arch = _arch mount_path = "/mnt/install/cdimage" discinfo_path = os.path.join(mount_path, ".discinfo") if os.path.isfile(path) and path.endswith(".iso"): files = [os.path.basename(path)] path = os.path.dirname(path) else: files = os.listdir(path) for fn in files: what = os.path.join(path, fn) log.debug("Checking %s", what) if not isys.isIsoImage(what): continue log.debug("mounting %s on %s", what, mount_path) try: blivet.util.mount(what, mount_path, fstype="iso9660", options="ro") except OSError: continue if not os.access(discinfo_path, os.R_OK): blivet.util.umount(mount_path) continue log.debug("Reading .discinfo") disc_info = DiscInfo() try: disc_info.load(discinfo_path) disc_arch = disc_info.arch except Exception as ex: # pylint: disable=broad-except log.warning(".discinfo file can't be loaded: %s", ex) continue log.debug("discArch = %s", disc_arch) if disc_arch != arch: log.warning("findFirstIsoImage: architectures mismatch: %s, %s", disc_arch, arch) blivet.util.umount(mount_path) continue # If there's no repodata, there's no point in trying to # install from it. if not _check_repodata(mount_path): log.warning("%s doesn't have repodata, skipping", what) blivet.util.umount(mount_path) continue # warn user if images appears to be wrong size if os.stat(what)[stat.ST_SIZE] % 2048: log.warning("%s appears to be corrupted", what) exn = InvalidImageSizeError("size is not a multiple of 2048 bytes", what) if errorHandler.cb(exn) == ERROR_RAISE: raise exn log.info("Found disc at %s", fn) blivet.util.umount(mount_path) return fn return None
def mount_filesystems(self, root_path="", read_only=None, skip_root=False): """Mount the system's filesystems. :param str root_path: the root directory for this filesystem :param read_only: read only option str for this filesystem :type read_only: str or None :param bool skip_root: whether to skip mounting the root filesystem """ devices = list(self.mountpoints.values()) + self.swap_devices devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc, self.selinux, self.usb, self.run]) if isinstance(_platform, EFI): devices.append(self.efivars) devices.sort(key=lambda d: getattr(d.format, "mountpoint", "")) for device in devices: if not device.format.mountable or not device.format.mountpoint: continue if skip_root and device.format.mountpoint == "/": continue options = device.format.options if "noauto" in options.split(","): continue if device.format.type == "bind" and device not in [self.dev, self.run]: # set up the DirectoryDevice's parents now that they are # accessible # # -- bind formats' device and mountpoint are always both # under the chroot. no exceptions. none, damn it. target_dir = "%s/%s" % (root_path, device.path) parent = get_containing_device(target_dir, self.devicetree) if not parent: log.error("cannot determine which device contains " "directory %s", device.path) device.parents = [] self.devicetree._remove_device(device) continue else: device.parents = [parent] try: device.setup() except Exception as e: # pylint: disable=broad-except log_exception_info(fmt_str="unable to set up device %s", fmt_args=[device]) if error_handler.cb(e) == ERROR_RAISE: raise else: continue if read_only: options = "%s,%s" % (options, read_only) try: device.format.setup(options=options, chroot=root_path) except Exception as e: # pylint: disable=broad-except log_exception_info(log.error, "error mounting %s on %s", [device.path, device.format.mountpoint]) if error_handler.cb(e) == ERROR_RAISE: raise self.active = True