def updateNVRAMBootList(self): if not conf.target.is_hardware: return log.debug("updateNVRAMBootList: self.stage1_device.path = %s", self.stage1_device.path) buf = util.execWithCapture("nvram", ["--print-config=boot-device"]) if len(buf) == 0: log.error("Failed to determine nvram boot device") return boot_list = buf.strip().replace("\"", "").split() log.debug("updateNVRAMBootList: boot_list = %s", boot_list) buf = util.execWithCapture("ofpathname", [self.stage1_device.path]) if len(buf) > 0: boot_disk = buf.strip() else: log.error("Failed to translate boot path into device name") return # Place the disk containing the PReP partition first. # Remove all other occurances of it. boot_list = [boot_disk] + [x for x in boot_list if x != boot_disk] update_value = "boot-device=%s" % " ".join(boot_list) rc = util.execWithRedirect("nvram", ["--update-config", update_value]) if rc: log.error("Failed to update new boot device order")
def exec_with_capture_test(self): """Test execWithCapture.""" # check some output is returned self.assertGreater(len(util.execWithCapture('ls', ['--help'])), 0) # check no output is returned self.assertEqual(len(util.execWithCapture('true', [])), 0)
def test_exec_with_capture(self): """Test execWithCapture.""" # check some output is returned assert len(util.execWithCapture('ls', ['--help'])) > 0 # check no output is returned assert len(util.execWithCapture('true', [])) == 0
def shutdownServer(): """Try to shutdown any running XVNC server Why is this function on the module level and not in the VncServer class ? As the server needs to be killed from the exit handler, it would have to somehow get to the VncServer instance. Like this, it can just kill it by calling a function of the vnc module. """ try: util.execWithCapture("killall", [XVNC_BINARY_NAME]) log.info("The XVNC server has been shut down.") except OSError as e: log.error("Shutdown of the XVNC server failed with exception:\n%s", e)
def setup(self): security_proxy = SECURITY.get_proxy() realm = RealmData.from_structure(security_proxy.Realm) if not realm.name: return try: argv = ["discover", "--verbose" ] + realm.discover_options + [realm.name] output = util.execWithCapture("realm", argv, filter_stderr=True) except OSError: # TODO: A lousy way of propagating what will usually be # 'no such realm' # The error message is logged by util return # Now parse the output for the required software. First line is the # realm name, and following lines are information as "name: value" self.packages = ["realmd"] self.discovered = "" lines = output.split("\n") if not lines: return self.discovered = lines.pop(0).strip() realm_log.info("Realm discovered: %s", self.discovered) for line in lines: parts = line.split(":", 1) if len(parts) == 2 and parts[0].strip() == "required-package": self.packages.append(parts[1].strip()) realm_log.info("Realm %s needs packages %s", self.discovered, ", ".join(self.packages))
def setup(self): security_proxy = SECURITY.get_proxy() realm = RealmData.from_structure(security_proxy.Realm) if not realm.name: return try: argv = ["discover", "--verbose"] + realm.discover_options + [realm.name] output = util.execWithCapture("realm", argv, filter_stderr=True) except OSError: # TODO: A lousy way of propagating what will usually be # 'no such realm' # The error message is logged by util return # Now parse the output for the required software. First line is the # realm name, and following lines are information as "name: value" self.packages = ["realmd"] self.discovered = "" lines = output.split("\n") if not lines: return self.discovered = lines.pop(0).strip() realm_log.info("Realm discovered: %s", self.discovered) for line in lines: parts = line.split(":", 1) if len(parts) == 2 and parts[0].strip() == "required-package": self.packages.append(parts[1].strip()) realm_log.info("Realm %s needs packages %s", self.discovered, ", ".join(self.packages))
def detect_live_os_image(self): """Detect live os image in the system.""" log.debug("Trying to detect live os base image automatically") for block_device in [ "/dev/mapper/live-base", "/dev/mapper/live-osimg-min" ]: try: if stat.S_ISBLK(os.stat(block_device)[stat.ST_MODE]): log.debug("Detected live base image %s", block_device) return block_device except FileNotFoundError: pass # Is it a squashfs+overlayfs base image? if os.path.exists("/run/rootfsbase"): try: block_device = execWithCapture( "findmnt", ["-n", "-o", "SOURCE", "/run/rootfsbase"]).strip() if block_device: log.debug("Detected live base image %s", block_device) return block_device except (OSError, FileNotFoundError): pass log.debug("No live base image detected") return ""
def run(self): if not self._realm_data.name: log.debug("No realm name set, skipping realm discovery.") return self._realm_data output = "" try: argv = ["discover", "--verbose"] + self._realm_data.discover_options \ + [self._realm_data.name] output = util.execWithCapture(REALM_TOOL_NAME, argv, filter_stderr=True) except OSError: # TODO: A lousy way of propagating what will usually be # 'no such realm' # The error message is logged by util return self._realm_data realm_discovered, required_packages = self._parse_realm_data(output) # set the result in the realm data holder and return it self._realm_data.discovered = realm_discovered self._realm_data.required_packages = required_packages return self._realm_data
def run(self): """Run the task""" if not self._gpg_keys: log.debug("No GPG keys to import.") return if not os.path.exists(self._sysroot + "/usr/bin/rpm"): log.error( "Can not import GPG keys to RPM database because " "the 'rpm' executable is missing on the target " "system. The following keys were not imported:\n%s", "\n".join(self._gpg_keys) ) return # Get substitutions for variables. # TODO: replace the interpolation with DNF once possible basearch = util.execWithCapture("uname", ["-i"]).strip().replace("'", "") releasever = util.get_os_release_value("VERSION_ID", sysroot=self._sysroot) or "" # Import GPG keys to RPM database. for key in self._gpg_keys: key = key.replace("$releasever", releasever).replace("$basearch", basearch) log.info("Importing GPG key to RPM database: %s", key) rc = util.execWithRedirect("rpm", ["--import", key], root=self._sysroot) if rc: log.error("Failed to import the GPG key.")
def _get_current_free_space_map(): """Get the available file system disk space of the current system. :return: a dictionary of mount points and their available space """ mapping = {} # Generate the dictionary of mount points and sizes. output = execWithCapture('df', ['--output=target,avail']) lines = output.rstrip().splitlines() for line in lines: key, val = line.rsplit(maxsplit=1) if not key.startswith('/'): continue mapping[key] = Size(int(val) * 1024) # Add /var/tmp/ if this is a directory or image installation. if not conf.target.is_hardware: var_tmp = os.statvfs("/var/tmp") mapping["/var/tmp"] = Size(var_tmp.f_frsize * var_tmp.f_bfree) return mapping
def test_exec_with_capture_no_stderr(self): """Test execWithCapture with no stderr""" with tempfile.NamedTemporaryFile(mode="w+t") as testscript: testscript.write("""#!/bin/sh echo "output" echo "error" >&2 """) testscript.flush() # check that only the output is captured assert util.execWithCapture("/bin/sh", [testscript.name], filter_stderr=True) == \ "output\n" # check that both output and error are captured assert util.execWithCapture("/bin/sh", [testscript.name]) == "output\nerror\n"
def test_resolve_date_format(self): """All locales' date formats should be properly resolved.""" locales = (line.strip() for line in execWithCapture("locale", ["-a"]).splitlines()) for locale in locales: locale_mod.setlocale(locale_mod.LC_ALL, locale) order = localization.resolve_date_format(1, 2, 3, fail_safe=False)[0] for i in (1, 2, 3): self.assertIn(i, order)
def exec_with_capture_no_stderr_test(self): """Test execWithCapture with no stderr""" with tempfile.NamedTemporaryFile(mode="w+t") as testscript: testscript.write("""#!/bin/sh echo "output" echo "error" >&2 """) testscript.flush() # check that only the output is captured self.assertEqual( util.execWithCapture("/bin/sh", [testscript.name], filter_stderr=True), "output\n") # check that both output and error are captured self.assertEqual(util.execWithCapture("/bin/sh", [testscript.name]), "output\nerror\n")
def updateNVRAMBootList(self): if not conf.target.is_hardware: return log.debug("updateNVRAMBootList: self.stage1_device.path = %s", self.stage1_device.path) buf = util.execWithCapture("nvram", ["--print-config=boot-device"], filter_stderr=True) if len(buf) == 0: log.error("Failed to determine nvram boot device") return boot_list = buf.strip().replace("\"", "").split() log.debug("updateNVRAMBootList: boot_list = %s", boot_list) buf = util.execWithCapture("ofpathname", [self.stage1_device.path], filter_stderr=True) if len(buf) > 0: boot_disk = buf.strip() else: log.error("Failed to translate boot path into device name") return # Place the disk containing the PReP partition first. # Remove all other occurances of it. boot_list = [boot_disk] + [x for x in boot_list if x != boot_disk] # The boot-device NVRAM variable has a maximum number of devices allowed, # don't add more than the limit in the ibm,max-boot-devices OF property. max_dev_path = "/sys/firmware/devicetree/base/ibm,max-boot-devices" if os.access(max_dev_path, os.F_OK): with open(max_dev_path, "rb") as f: limit = int.from_bytes(f.read(4), byteorder='big') boot_list = boot_list[:limit] update_value = "boot-device=%s" % " ".join(boot_list) rc = util.execWithRedirect("nvram", ["--update-config", update_value]) if rc: log.error("Failed to update new boot device order")
def ifaceForHostIP(host): route = util.execWithCapture("ip", ["route", "get", "to", host]) if not route: log.error("Could not get interface for route to %s", host) return "" routeInfo = route.split() if routeInfo[0] != host or len(routeInfo) < 5 or \ "dev" not in routeInfo or routeInfo.index("dev") > 3: log.error('Unexpected "ip route get to %s" reply: %s', host, routeInfo) return "" return routeInfo[routeInfo.index("dev") + 1]
def _check_mount_point(self, mount_point): """Check a block device at the specified mount point.""" log.debug("Checking the %s mount point.", mount_point) if not os.path.exists(mount_point): return None try: block_device = execWithCapture("findmnt", ["-n", "-o", "SOURCE", mount_point]).strip() return block_device or None except (OSError, FileNotFoundError): pass return None
def iface_for_host_ip(host_ip): """Get interface used to access given host IP.""" route = util.execWithCapture("ip", ["route", "get", "to", host_ip]) if not route: log.error("Could not get interface for route to %s", host_ip) return "" route_info = route.split() if route_info[0] != host_ip or len(route_info) < 5 or \ "dev" not in route_info or route_info.index("dev") > 3: log.error('Unexpected "ip route get to %s" reply: %s', host_ip, route_info) return "" return route_info[route_info.index("dev") + 1]
def get_df_map(): """Return (mountpoint -> size available) mapping.""" output = util.execWithCapture('df', ['--output=target,avail']) output = output.rstrip() lines = output.splitlines() structured = {} for line in lines: key, val = line.rsplit(maxsplit=1) if not key.startswith('/'): continue structured[key] = Size(int(val) * 1024) # Add /var/tmp/ if this is a directory or image installation if not conf.target.is_hardware: var_tmp = os.statvfs("/var/tmp") structured["/var/tmp"] = Size(var_tmp.f_frsize * var_tmp.f_bfree) return structured
def write_config(self): config_path = "%s%s" % (conf.target.system_root, self.efi_config_file) with open(config_path, "w") as fd: grub_dir = self.config_dir fs_uuid = self.stage2_device.format.uuid grub_dir = util.execWithCapture("grub2-mkrelpath", [grub_dir], root=conf.target.system_root) if not grub_dir: raise BootLoaderError("Could not get GRUB directory path") fd.write("search --no-floppy --fs-uuid --set=dev %s\n" % fs_uuid) fd.write("set prefix=($dev)%s\n" % grub_dir) fd.write("export $prefix\n") fd.write("configfile $prefix/grub.cfg\n") super().write_config()
def _encrypt_password(self): """Make sure self.encrypted_password is set up properly.""" if self.encrypted_password: return if not self.password: raise RuntimeError("cannot encrypt empty password") (pread, pwrite) = os.pipe() passwords = "%s\n%s\n" % (self.password, self.password) os.write(pwrite, passwords.encode("utf-8")) os.close(pwrite) buf = util.execWithCapture("grub2-mkpasswd-pbkdf2", [], stdin=pread, root=util.getSysroot()) os.close(pread) self.encrypted_password = buf.split()[-1].strip() if not self.encrypted_password.startswith("grub.pbkdf2."): raise BootLoaderError("failed to encrypt boot loader password")
def is_service_installed(service, root="/"): """Is a systemd service installed? Runs 'systemctl list-unit-files' to determine if the service exists. :param str service: name of the service to check :param str root: path to the sysroot, defaults to installation environment """ if not service.endswith(".service"): service += ".service" args = ["list-unit-files", service, "--no-legend"] if root != "/": args += ["--root", root] unit_file = execWithCapture("systemctl", args) return bool(unit_file)
def _is_language_support_installed(self, lang): """Is the support for the specified language installed? The language is considered to be supported if we are not able to determine the supported locales due to missing tools. :param lang: a value for the LANG locale variable :return: False if the locale is known to be not supported, otherwise True """ try: output = execWithCapture("locale", ["-a"], root=self._sysroot) except OSError as e: log.warning("Couldn't get supported locales: %s", e) return True match = find_best_locale_match(lang, output.splitlines()) log.debug("The '%s' locale matched '%s'.", lang, match) return bool(match)
def _df_map(): """Return (mountpoint -> size available) mapping.""" output = util.execWithCapture('df', ['--output=target,avail']) output = output.rstrip() lines = output.splitlines() structured = {} for line in lines: items = line.split() key = items[0] val = items[1] if not key.startswith('/'): continue structured[key] = Size(int(val) * 1024) # Add /var/tmp/ if this is a directory or image installation if flags.dirInstall or flags.imageInstall: var_tmp = os.statvfs("/var/tmp") structured["/var/tmp"] = Size(var_tmp.f_frsize * var_tmp.f_bfree) return structured
def _encrypt_password(self): """Make sure self.encrypted_password is set up properly.""" if self.encrypted_password: return if not self.password: raise RuntimeError("cannot encrypt empty password") (pread, pwrite) = os.pipe() passwords = "%s\n%s\n" % (self.password, self.password) os.write(pwrite, passwords.encode("utf-8")) os.close(pwrite) buf = util.execWithCapture("grub2-mkpasswd-pbkdf2", [], stdin=pread, root=conf.target.system_root) os.close(pread) self.encrypted_password = buf.split()[-1].strip() if not self.encrypted_password.startswith("grub.pbkdf2."): raise BootLoaderError("failed to encrypt boot loader password")
def get_default_route_iface(family="inet"): """Get the device having default route. :return: the name of the network device having default route """ routes = util.execWithCapture("ip", ["-f", family, "route", "show"]) if not routes: log.debug("Could not get default %s route device", family) return None for line in routes.split("\n"): if line.startswith("default"): parts = line.split() if len(parts) >= 5 and parts[3] == "dev": return parts[4] else: log.debug("Could not parse default %s route device", family) return None return None
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 "): raise BootLoaderError(line) if not self.stage1_name: raise BootLoaderError("could not find IPL device") # do the reipl util.reIPL(self.stage1_name)
def test_exec_with_capture_empty(self): """Test execWithCapture with no output""" # check that the output is an empty string assert util.execWithCapture("/bin/sh", ["-c", "exit 0"]) == ""
def exec_with_capture_empty_test(self): """Test execWithCapture with no output""" # check that the output is an empty string self.assertEqual(util.execWithCapture("/bin/sh", ["-c", "exit 0"]), "")
def lsblk_callback(): """Callback to get info about block devices.""" options = "NAME,SIZE,OWNER,GROUP,MODE,FSTYPE,LABEL,UUID,PARTUUID,FSAVAIL,FSUSE%,MOUNTPOINT" return util.execWithCapture("lsblk", ["--bytes", "-o", options])
def lsblk_callback(): """Callback to get info about block devices.""" return util.execWithCapture("lsblk", ["--perms", "--fs", "--bytes"])
def nmcli_dev_list_callback(): """Callback to get info about network devices.""" return util.execWithCapture("nmcli", ["device", "show"])