示例#1
0
    def setUserSshKey(self, username, key, **kwargs):
        root = kwargs.get("root", util.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 util.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))
            util.execWithRedirect("restorecon", ["-r", sshdir])
示例#2
0
    def _setup_hmc_device(self, storage, method, isodev, device):
        # Check if /dev/hmcdrv is already mounted.
        if device == "/dev/hmcdrv":
            log.debug("HMC is already mounted at %s.", DRACUT_REPODIR)
            url = "file://" + DRACUT_REPODIR
        else:
            log.debug("Trying to mount the content of HMC media drive.")

            # Test the SE/HMC file access.
            if util.execWithRedirect("/usr/sbin/lshmc", []):
                raise PayloadSetupError("The content of HMC media drive couldn't be accessed.")

            # Test if a path is a mount point.
            if os.path.ismount(INSTALL_TREE):
                log.debug("Don't mount the content of HMC media drive yet.")
            else:
                # Make sure that the directories exists.
                util.mkdirChain(INSTALL_TREE)

                # Mount the device.
                if util.execWithRedirect("/usr/bin/hmcdrvfs", [INSTALL_TREE]):
                    raise PayloadSetupError("The content of HMC media drive couldn't be mounted.")

            log.debug("We are ready to use the HMC at %s.", INSTALL_TREE)
            url = "file://" + INSTALL_TREE

        return url
示例#3
0
def time_initialize(timezone_proxy, storage):
    """
    Try to guess if RTC uses UTC time or not, set timezone.isUtc properly and
    set system time from RTC using the UTC guess.
    Guess is done by searching for bootable ntfs devices.

    :param timezone_proxy: DBus proxy of the timezone module
    :param storage: pyanaconda.storage.InstallerStorage instance
    """

    if arch.is_s390():
        # nothing to do on s390(x) were hwclock doesn't exist
        return

    if not timezone_proxy.IsUTC and not flags.automatedInstall:
        # if set in the kickstart, no magic needed here
        threadMgr.wait(THREAD_STORAGE)
        ntfs_devs = filter(lambda dev: dev.format.name == "ntfs",
                           storage.devices)

        timezone_proxy.SetIsUTC(not storage.bootloader.has_windows(ntfs_devs))

    cmd = "hwclock"
    args = ["--hctosys"]
    if timezone_proxy.IsUTC:
        args.append("--utc")
    else:
        args.append("--localtime")

    util.execWithRedirect(cmd, args)
示例#4
0
    def exec_with_redirect_test(self):
        """Test execWithRedirect."""
        # correct calling should return rc==0
        self.assertEqual(util.execWithRedirect('ls', []), 0)

        # incorrect calling should return rc!=0
        self.assertNotEqual(util.execWithRedirect('ls', ['--asdasd']), 0)
示例#5
0
    def execute(self, storage, ksdata, users, payload):
        # the KdumpSpoke should run only if requested
        if not flags.cmdline.getbool("kdump_addon", default=False) or not self.enabled:
            return

        action = "enable"

        util.execWithRedirect("systemctl", [action, "kdump.service"], root=util.getSysroot())
示例#6
0
def set_x_resolution(runres):
    """Set X server screen resolution.

    :param str runres: a resolution specification string
    """
    try:
        log.info("Setting the screen resolution to: %s.", runres)
        util.execWithRedirect("xrandr", ["-d", ":1", "-s", runres])
    except RuntimeError:
        log.error("The X resolution was not set")
        util.execWithRedirect("xrandr", ["-d", ":1", "-q"])
示例#7
0
def do_extra_x11_actions(runres, gui_mode):
    """Perform X11 actions not related to startup.

    :param str runres: a resolution specification string
    :param gui_mode: an Anaconda display mode
    """
    if runres and gui_mode and not flags.usevnc:
        set_x_resolution(runres)

    # Load the system-wide Xresources
    util.execWithRedirect("xrdb", ["-nocpp", "-merge", "/etc/X11/Xresources"])

    start_spice_vd_agent()
示例#8
0
def _try_to_load_keymap(keymap):
    """
    Method that tries to load keymap and returns boolean indicating if it was
    successfull or not. It can be used to test if given string is VConsole
    keymap or not, but in case it is given valid keymap, IT REALLY LOADS IT!.

    :type keymap: string
    :raise KeyboardConfigError: if loadkeys command is not available
    :return: True if given string was a valid keymap and thus was loaded,
             False otherwise

    """

    # BUG: systemd-localed should be able to tell us if we are trying to
    #      activate invalid keymap. Then we will be able to get rid of this
    #      fuction

    ret = 0

    try:
        ret = util.execWithRedirect("loadkeys", [keymap])
    except OSError as oserr:
        msg = "'loadkeys' command not available (%s)" % oserr.strerror
        raise KeyboardConfigError(msg)

    return ret == 0
示例#9
0
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)
示例#10
0
    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")
示例#11
0
    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 util.getSysroot().
        """
        root = kwargs.get("root", util.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 = util.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))
示例#12
0
 def _safe_exec_with_redirect(self, cmd, argv, **kwargs):
     """Like util.execWithRedirect, but treat errors as fatal"""
     rc = util.execWithRedirect(cmd, argv, **kwargs)
     if rc != 0:
         exn = PayloadInstallError("%s %s exited with code %d" % (cmd, argv, rc))
         if errors.errorHandler.cb(exn) == errors.ERROR_RAISE:
             raise exn
示例#13
0
 def _safeExecWithRedirect(self, cmd, argv, **kwargs):
     """Like util.execWithRedirect, but treat errors as fatal"""
     rc = util.execWithRedirect(cmd, argv, **kwargs)
     if rc != 0:
         exn = PayloadInstallError("%s %s exited with code %d" %
                                   (cmd, argv, rc))
         if errors.errorHandler.cb(exn) == errors.ERROR_RAISE:
             raise exn
示例#14
0
    def run(self):
        """Run the task."""
        if not arch.is_s390():
            log.debug("ZIPL can be run only on s390x.")
            return

        if conf.target.is_directory:
            log.debug(
                "The bootloader installation is disabled for dir installations."
            )
            return

        if self._mode == BootloaderMode.DISABLED:
            log.debug("The bootloader installation is disabled.")
            return

        execWithRedirect("zipl", [], root=conf.target.system_root)
示例#15
0
    def _do_mount(self):
        """Set up the installation source."""
        log.debug("Trying to mount the content of HMC media drive.")

        # Test the SE/HMC file access.
        if execWithRedirect("/usr/sbin/lshmc", []):
            raise SourceSetupError(
                "The content of HMC media drive couldn't be accessed.")

        # Make sure that the directories exists.
        mkdirChain(self._target_mount)

        # Mount the device.
        if execWithRedirect("/usr/bin/hmcdrvfs", [self._target_mount]):
            raise SourceSetupError(
                "The content of HMC media drive couldn't be mounted.")

        log.debug("We are ready to use the HMC at %s.", self._target_mount)
示例#16
0
 def input(self, args, key):
     """Override input so that we can launch the VNC password spoke"""
     if self._container.process_user_input(key):
         self.apply()
         return InputState.PROCESSED_AND_CLOSE
     else:
         # TRANSLATORS: 'q' to quit
         if key.lower() == C_('TUI|Spoke Navigation', 'q'):
             d = YesNoDialog(_(u"Do you really want to quit?"))
             ScreenHandler.push_screen_modal(d)
             if d.answer:
                 ipmi_abort(scripts=self.data.scripts)
                 if conf.system.can_reboot:
                     execWithRedirect("systemctl", ["--no-wall", "reboot"])
                 else:
                     sys.exit(1)
         else:
             return super().input(args, key)
示例#17
0
def safe_exec_with_redirect(cmd, argv, **kwargs):
    """Like util.execWithRedirect, but treat errors as fatal.

    :raise: PayloadInstallationError if the call fails for any reason
    """
    rc = execWithRedirect(cmd, argv, **kwargs)
    if rc != 0:
        raise PayloadInstallationError("{} {} exited with code {}".format(
            cmd, argv, rc))
示例#18
0
 def input(self, args, key):
     """Override input so that we can launch the VNC password spoke"""
     if self._container.process_user_input(key):
         self.apply()
         return InputState.PROCESSED_AND_CLOSE
     else:
         # TRANSLATORS: 'q' to quit
         if key.lower() == C_('TUI|Spoke Navigation', 'q'):
             d = YesNoDialog(_(u"Do you really want to quit?"))
             ScreenHandler.push_screen_modal(d)
             if d.answer:
                 ipmi_abort(scripts=self.data.scripts)
                 if conf.system.can_reboot:
                     execWithRedirect("systemctl", ["--no-wall", "reboot"])
                 else:
                     sys.exit(1)
         else:
             return super().input(args, key)
示例#19
0
    def run(self):
        args = []

        # If --use-system-defaults was passed then the user wants
        # whatever was provided by the rpms or ostree to be the
        # default, do nothing.
        if self._firewall_mode == FirewallMode.USE_SYSTEM_DEFAULTS:
            log.info("ks file instructs to use system defaults for firewall, "
                     "skipping configuration.")
            return

        # enabled is None if neither --enable or --disable is passed
        # default to enabled if nothing has been set.
        if self._firewall_mode == FirewallMode.DISABLED:
            args += ["--disabled"]
        else:
            args += ["--enabled"]

        ssh_service_not_enabled = "ssh" not in self._enabled_services
        ssh_service_not_disabled = "ssh" not in self._disabled_services
        ssh_port_not_enabled = "22:tcp" not in self._enabled_ports

        # always enable SSH unless the service is explicitely disabled
        if ssh_service_not_enabled and ssh_service_not_disabled and ssh_port_not_enabled:
            args += ["--service=ssh"]

        for dev in self._trusts:
            args += ["--trust=%s" % (dev,)]

        for port in self._enabled_ports:
            args += ["--port=%s" % (port,)]

        for remove_service in self._disabled_services:
            args += ["--remove-service=%s" % (remove_service,)]

        for service in self._enabled_services:
            args += ["--service=%s" % (service,)]

        if not os.path.exists(self._sysroot + self.FIREWALL_OFFLINE_CMD):
            if self._firewall_mode == FirewallMode.ENABLED:
                msg = _("%s is missing. Cannot setup firewall.") % (self.FIREWALL_OFFLINE_CMD,)
                raise FirewallConfigurationError(msg)
        else:
            execWithRedirect(self.FIREWALL_OFFLINE_CMD, args, root=self._sysroot)
示例#20
0
def create_bls_entries(sysroot, storage, kernel_versions):
    """Create BLS entries.

    :param sysroot: a path to the root of the installed system
    :param storage: an instance of the storage
    :param kernel_versions: a list of kernel versions
    """
    # Not using BLS configuration, skip it
    if os.path.exists(sysroot + "/usr/sbin/new-kernel-pkg"):
        return

    # Remove any existing BLS entries, they will not match the new system's
    # machine-id or /boot mountpoint.
    for file in glob(sysroot + "/boot/loader/entries/*.conf"):
        log.info("Removing old BLS entry: %s", file)
        os.unlink(file)

    # Create new BLS entries for this system
    for kernel in kernel_versions:
        log.info("Regenerating BLS info for %s", kernel)
        execWithRedirect(
            "kernel-install",
            ["add", kernel, "/lib/modules/{0}/vmlinuz".format(kernel)],
            root=sysroot
        )

    # Update the bootloader configuration to make sure that the BLS
    # entries will have the correct kernel cmdline and not the value
    # taken from /proc/cmdline, that is used to boot the live image.
    if isinstance(storage.bootloader, EFIBase):
        grub_cfg_path = "/etc/grub2-efi.cfg"
    else:
        grub_cfg_path = "/etc/grub2.cfg"

    rc = execWithRedirect(
        "grub2-mkconfig",
        ["-o", grub_cfg_path],
        root=sysroot
    )

    if rc:
        raise BootloaderInstallationError(
            "failed to write boot loader configuration"
        )
示例#21
0
def save_hw_clock(timezone):
    """
    Save system time to HW clock.

    :param timezone: ksdata.timezone object

    """

    if arch.is_s390():
        return

    cmd = "hwclock"
    args = ["--systohc"]
    if timezone.isUtc:
        args.append("--utc")
    else:
        args.append("--local")

    util.execWithRedirect(cmd, args)
示例#22
0
    def run(self):
        """Run update of bls configuration."""
        # Not using BLS configuration, skip it
        if os.path.exists(self._sysroot + "/usr/sbin/new-kernel-pkg"):
            return

        # Remove any existing BLS entries, they will not match the new system's
        # machine-id or /boot mountpoint.
        for file in glob.glob(self._sysroot + "/boot/loader/entries/*.conf"):
            log.info("Removing old BLS entry: %s", file)
            os.unlink(file)

        # Create new BLS entries for this system
        for kernel in self._kernel_version_list:
            log.info("Regenerating BLS info for %s", kernel)
            execWithRedirect(
                "kernel-install",
                ["add", kernel, "/lib/modules/{0}/vmlinuz".format(kernel)],
                root=self._sysroot)
示例#23
0
    def run(self):
        """Configure FIPS on the installed system.

        If the installation is running in fips mode then make sure
        fips is also correctly enabled in the installed system.
        """
        if not self._fips_enabled:
            log.debug("FIPS is not enabled. Skipping.")
            return

        if not conf.target.is_hardware:
            log.debug("Don't set up FIPS on %s.", conf.target.type.value)
            return

        # We use the --no-bootcfg option as we don't want fips-mode-setup
        # to modify the bootloader configuration. Anaconda already does
        # everything needed & it would require grubby to be available on
        # the system.
        util.execWithRedirect("fips-mode-setup", ["--enable", "--no-bootcfg"],
                              root=self._sysroot)
示例#24
0
def start_spice_vd_agent():
    """Start the spice vdagent.

    For certain features to work spice requires that the guest os
    is running the spice vdagent.
    """
    status = util.execWithRedirect("spice-vdagent", [])
    if status:
        log.info("spice-vdagent exited with status %d", status)
    else:
        log.info("Started spice-vdagent.")
示例#25
0
    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])
示例#26
0
def start_spice_vd_agent():
    """Start the spice vdagent.

    For certain features to work spice requires that the guest os
    is running the spice vdagent.
    """
    status = util.execWithRedirect("spice-vdagent", [])
    if status:
        log.info("spice-vdagent exited with status %d", status)
    else:
        log.info("Started spice-vdagent.")
示例#27
0
    def updateNVRAMBootList(self):
        if not conf.target.is_hardware:
            return

        log.debug("updateNVRAMBootList: self.stage1_device.path = %s",
                  self.stage1_device.path)

        rc = util.execWithRedirect(
            "bootlist", ["-m", "normal", "-o", self.stage1_device.path])
        if rc:
            log.error("Failed to update new boot device order")
示例#28
0
    def add_driver_repos(self):
        """Add driver repositories and packages.

        FIXME: Don't run this code on every payload restart.
        """
        # Drivers are loaded by anaconda-dracut, their repos are copied
        # into /run/install/DD-X where X is a number starting at 1. The list of
        # packages that were selected is in /run/install/dd_packages

        # Add repositories
        dir_num = 0
        while True:
            dir_num += 1
            repo = "/run/install/DD-%d/" % dir_num
            if not os.path.isdir(repo):
                break

            # Run createrepo if there are rpms and no repodata
            if not os.path.isdir(repo + "/repodata"):
                rpms = glob(repo + "/*rpm")
                if not rpms:
                    continue
                log.info("Running createrepo on %s", repo)
                util.execWithRedirect("createrepo_c", [repo])

            # Generate the repo name.
            repo_name = "DD-%d" % dir_num

            # The repo has been already created (#1268357).
            for ks_repo in self.data.repo.dataList():
                if repo_name == ks_repo.name:
                    continue

            # Or create a new one.
            ks_repo = self.data.RepoData(
                name=repo_name,
                baseurl="file://" + repo,
                enabled=True
            )

            self._add_repo_to_dnf_and_ks(ks_repo)
示例#29
0
def _call_syspurpose_tool(sysroot, args):
    """Helper function for invoking the syspurpose tool with error checking.

    :param str sysroot: system root path
    :param args: list of arguments for syspurpose
    :type args: list of str
    :return: syspurpose tool return code (non zero means failure)
    """
    rc = util.execWithRedirect("syspurpose", args, root=sysroot)
    if rc:
        log.error("subscription: syspurpose invocation failed for args %s with rc %s", args, rc)
    return rc
示例#30
0
    def run(self):
        """Run installation of the payload from a tarball.

        Preserve ACL's, xattrs, and SELinux context.
        """
        cmd = "tar"
        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._tarfile, "-C",
            self._sysroot
        ]

        try:
            execWithRedirect(cmd, args)
        except (OSError, RuntimeError) as e:
            msg = "Failed to install tar: {}".format(e)
            raise PayloadInstallationError(msg) from None
示例#31
0
def save_hw_clock(timezone_proxy=None):
    """
    Save system time to HW clock.

    :param timezone_proxy: DBus proxy of the timezone module

    """
    if arch.is_s390():
        return

    if not timezone_proxy:
        timezone_proxy = TIMEZONE.get_proxy()

    cmd = "hwclock"
    args = ["--systohc"]
    if timezone_proxy.IsUTC:
        args.append("--utc")
    else:
        args.append("--local")

    util.execWithRedirect(cmd, args)
示例#32
0
    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)
示例#33
0
def safe_exec_with_redirect(cmd, argv, successful_return_codes=(0, ),
                            **kwargs):
    """Like util.execWithRedirect, but treat errors as fatal.

    :raise: PayloadInstallationError if the call fails for any reason
    """
    rc = execWithRedirect(cmd, argv, **kwargs)

    if rc not in successful_return_codes:
        raise PayloadInstallationError(
            "The command '{}' exited with the code {}.".format(
                " ".join([cmd] + argv), rc))
示例#34
0
def create_rescue_image(root, kernel_version_list):
    """Create the rescue initrd images for each kernel."""
    # Always make sure the new system has a new machine-id, it won't boot without it
    # (and nor will some of the subsequent commands like grub2-mkconfig and kernel-install)
    log.info("Generating machine ID")
    if os.path.exists(root + "/etc/machine-id"):
        os.unlink(root + "/etc/machine-id")
    execWithRedirect("systemd-machine-id-setup", [], root=root)

    if os.path.exists(root + "/usr/sbin/new-kernel-pkg"):
        use_nkp = True
    else:
        log.warning("new-kernel-pkg does not exist - grubby wasn't installed?")
        use_nkp = False

    for kernel in kernel_version_list:
        log.info("Generating rescue image for %s", kernel)
        if use_nkp:
            execWithRedirect("new-kernel-pkg", ["--rpmposttrans", kernel],
                             root=root)
        else:
            files = glob.glob(root + "/etc/kernel/postinst.d/*")
            srlen = len(root)
            files = sorted([f[srlen:] for f in files if os.access(f, os.X_OK)])
            for file in files:
                execWithRedirect(file,
                                 [kernel, "/boot/vmlinuz-%s" % kernel],
                                 root=root)
示例#35
0
def create_rescue_images(sysroot, kernel_versions):
    """Create the rescue initrd images for each installed kernel."""
    # Always make sure the new system has a new machine-id, it
    # won't boot without it and some of the subsequent commands
    # like grub2-mkconfig and kernel-install will not work as well.
    log.info("Generating a new machine id.")

    if os.path.exists(sysroot + "/etc/machine-id"):
        os.unlink(sysroot + "/etc/machine-id")

    execWithRedirect("systemd-machine-id-setup", [], root=sysroot)

    if os.path.exists(sysroot + "/usr/sbin/new-kernel-pkg"):
        use_nkp = True
    else:
        log.debug("new-kernel-pkg does not exist, calling scripts directly.")
        use_nkp = False

    for kernel in kernel_versions:
        log.info("Generating rescue image for %s.", kernel)

        if use_nkp:
            execWithRedirect("new-kernel-pkg", ["--rpmposttrans", kernel],
                             root=sysroot)
        else:
            files = glob(sysroot + "/etc/kernel/postinst.d/*")
            srlen = len(sysroot)
            files = sorted([f[srlen:] for f in files if os.access(f, os.X_OK)])

            for file in files:
                execWithRedirect(file,
                                 [kernel, "/boot/vmlinuz-%s" % kernel],
                                 root=sysroot)
示例#36
0
    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])
示例#37
0
    def setUserPassword(self, username, password, isCrypted, lock, algo=None, root="/"):
        # Only set the password if it is a string, including the empty string.
        # Otherwise leave it alone (defaults to locked for new users) and reset sp_lstchg
        if password or password == "":
            if password == "":
                log.info("user account %s setup with no password", username)
            elif not isCrypted:
                password = cryptPassword(password, algo)

            if lock:
                password = "******" + password
                log.info("user account %s locked", username)

            proc = util.startProgram(["chpasswd", "-R", root, "-e"], stdin=subprocess.PIPE)
            proc.communicate(("%s:%s\n" % (username, password)).encode("utf-8"))
            if proc.returncode != 0:
                raise OSError("Unable to set password for new user: status=%s" % proc.returncode)

        # Reset sp_lstchg to an empty string. On systems with no rtc, this
        # field can be set to 0, which has a special meaning that the password
        # must be reset on the next login.
        util.execWithRedirect("chage", ["-R", root, "-d", "", username])
示例#38
0
    def _make_root_rprivate():
        """Make the mount of '/' rprivate.

        Work around inability to move shared filesystems. Also,
        do not share the image mounts with /run bind-mounted to
        physical target root during storage.mount_filesystems.
        """
        rc = execWithRedirect("mount", ["--make-rprivate", "/"])

        if rc != 0:
            raise PayloadInstallationError(
                "Failed to make the '/' mount rprivate: {}".format(rc)
            )
示例#39
0
def set_user_ssh_key(username, key, root=None):
    """Set an SSH key for a given username.

    :param str username: a username
    :param str key: the SSH key to set
    :param str root: target system sysroot path
    """
    if root is None:
        root = util.getSysroot()

    pwent = _getpwnam(username, root)
    if not pwent:
        raise ValueError("set_user_ssh_key: user %s does not exist" % username)

    homedir = root + pwent[5]
    if not os.path.exists(homedir):
        log.error("set_user_ssh_key: home directory for %s does not exist",
                  username)
        raise ValueError(
            "set_user_ssh_key: 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 util.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))
        util.execWithRedirect("restorecon", ["-r", sshdir])
示例#40
0
    def _mount_image(self, image_path, mount_point):
        # Work around inability to move shared filesystems.
        # Also, do not share the image mounts with /run bind-mounted to physical
        # target root during storage.mount_filesystems.
        rc = execWithRedirect("mount", ["--make-rprivate", "/"])
        if rc != 0:
            log.error("mount error (%s) making mount of '/' rprivate", rc)
            raise SourceSetupError("Mount error {}".format(rc))

        # 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 mount_point
        rc = mount(image_path, mount_point, fstype="auto", options="ro")
        if rc != 0:
            log.error("mount error (%s) with %s", rc, image_path)
            raise SourceSetupError("Mount error {}".format(rc))

        nested_image_files = glob.glob(mount_point + "/LiveOS/*.img")
        if nested_image_files:
            # Mount the first .img in the directory on mount_point
            nested_image = sorted(nested_image_files)[0]

            # move the mount to IMAGE_DIR
            os.makedirs(IMAGE_DIR, 0o755)
            rc = execWithRedirect("mount", ["--move", mount_point, IMAGE_DIR])
            if rc != 0:
                log.error("error %s moving mount", rc)
                raise SourceSetupError("Mount error {}".format(rc))

            nested_image_path = IMAGE_DIR + "/LiveOS/" + os.path.basename(
                nested_image)
            rc = mount(nested_image_path,
                       mount_point,
                       fstype="auto",
                       options="ro")
            if rc != 0:
                log.error("mount error (%s) with %s", rc, nested_image_path)
                raise SourceSetupError("Mount error {} with {}".format(
                    rc, nested_image_path))
示例#41
0
    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.kernel_version_list:
            log.info("Generating rescue image for %s", kernel)
            util.execInSysroot("new-kernel-pkg",
                               ["--rpmposttrans", kernel])
示例#42
0
    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)
示例#43
0
def get_locale_map_from_ostree(repo, ref):
    """Get a map of languages and locales from the given OSTree.

    For example: {"en": ["en_US"]}

    :param repo: the OSTree repository url
    :param ref: the name of branch inside the repository
    :return: a map of languages and locales
    """
    # Fallback to just en_US in case of errors.
    locale_map = {"en": ["en_US"]}

    # Let's only handle local embedded repos for now. Anyway, it'd probably
    # not be very common to only override ostreesetup through kickstart and
    # still want the interactive installer. Though to be nice, let's handle
    # that case.
    if not repo.startswith("file://"):
        log.info("ostree repo is not local; defaulting to en_US")
        return

    # Convert to regular UNIX path.
    repo = repo[len("file://"):]

    util.mkdirChain(os.path.join(repo, "tmp/usr/lib"))
    rc = util.execWithRedirect("/usr/bin/ostree", [
        "checkout", "--repo", repo, ref, "--subpath",
        "/usr/lib/locale/locale-archive",
        "%s/tmp/usr/lib/locale" % repo
    ])
    if rc != 0:
        log.error("failed to check out locale-archive; check program.log")
        return

    for line in util.execReadlines(
            "/usr/bin/localedef",
        ["--prefix", os.path.join(repo, "tmp"), "--list-archive"]):
        line = strip_codeset_and_modifier(line)
        if '_' in line:
            (lang, _territory) = line.split('_', 1)
        else:
            lang = line
        if lang not in locale_map:
            locale_map[lang] = [line]
        else:
            locale_map[lang].append(line)

    # Nuke the checkout for good measure.
    shutil.rmtree(os.path.join(repo, "tmp/usr"))
    return locale_map
示例#44
0
    def add_driver_repos(self):
        """Add driver repositories and packages."""
        # Drivers are loaded by anaconda-dracut, their repos are copied
        # into /run/install/DD-X where X is a number starting at 1. The list of
        # packages that were selected is in /run/install/dd_packages

        # Add repositories
        dir_num = 0
        while True:
            dir_num += 1
            repo = "/run/install/DD-%d/" % dir_num
            if not os.path.isdir(repo):
                break

            # Run createrepo if there are rpms and no repodata
            if not os.path.isdir(repo + "/repodata"):
                rpms = glob(repo + "/*rpm")
                if not rpms:
                    continue
                log.info("Running createrepo on %s", repo)
                util.execWithRedirect("createrepo_c", [repo])

            repo_name = "DD-%d" % dir_num
            if repo_name not in self.addons:
                ks_repo = self.data.RepoData(name=repo_name,
                                             baseurl="file://" + repo,
                                             enabled=True)
                self.add_repo(ks_repo)

        # Add packages
        if not os.path.exists("/run/install/dd_packages"):
            return
        with open("/run/install/dd_packages", "r") as f:
            for line in f:
                package = line.strip()
                self.requirements.add_packages([package], reason="driver disk")
示例#45
0
def set_console_font(font):
    """Try to set console font to the given value.

    :param str font: console font name
    :returns: True on success, False on failure
    :rtype: bool
    """
    log.debug("setting console font to %s", font)
    rc = execWithRedirect("setfont", [font])
    if rc == 0:
        log.debug("console font set successfully to %s", font)
        return True
    else:
        log.error("setting console font to %s failed", font)
        return False
示例#46
0
def generate_driver_disk_repositories(path="/run/install"):
    """Generate driver disk repositories.

    Drivers are loaded by anaconda-dracut. Their repos are copied
    into /run/install/DD-X where X is a number starting at 1.

    :param path: a path to the file with a package list
    :return: a list of repo configuration data
    """
    repositories = []

    # Iterate over all driver disk repositories.
    for i in count(start=1):
        repo_name = "DD-{}".format(i)
        repo_path = join_paths(path, repo_name)

        # Is there a directory of this name?
        if not os.path.isdir(repo_path):
            break

        # Are there RPMs in this directory?
        if not glob(repo_path + "/*rpm"):
            continue

        # Create a repository if there are no repodata.
        if not os.path.isdir(join_paths(repo_path, "repodata")):
            log.info("Running createrepo on %s", repo_path)
            execWithRedirect("createrepo_c", [repo_path])

        # Generate a repo configuration.
        repo = RepoConfigurationData()
        repo.name = repo_name
        repo.url = "file://" + repo_path
        repositories.append(repo)

    return repositories
示例#47
0
def recreate_initrds(sysroot, kernel_versions):
    """Recreate the initrds by calling new-kernel-pkg or dracut.

    This needs to be done after all configuration files have been
    written, since dracut depends on some of them.

    :param sysroot: a path to the root of the installed system
    :param kernel_versions: a list of kernel versions
    """
    if os.path.exists(sysroot + "/usr/sbin/new-kernel-pkg"):
        use_dracut = False
    else:
        log.debug("new-kernel-pkg does not exist, using dracut instead")
        use_dracut = True

    for kernel in kernel_versions:
        log.info("Recreating initrd for %s", kernel)

        if conf.target.is_image:
            # Dracut runs in the host-only mode by default, so we need to
            # turn it off by passing the -N option, because the mode is not
            # sensible for disk image installations. Using /dev/disk/by-uuid/
            # is necessary due to disk image naming.
            execWithRedirect(
                "dracut", [
                    "-N", "--persistent-policy", "by-uuid",
                    "-f", "/boot/initramfs-%s.img" % kernel, kernel
                ],
                root=sysroot
            )
        else:
            if use_dracut:
                execWithRedirect(
                    "depmod", ["-a", kernel], root=sysroot
                )
                execWithRedirect(
                    "dracut",
                    ["-f", "/boot/initramfs-%s.img" % kernel, kernel],
                    root=sysroot
                )
            else:
                execWithRedirect(
                    "new-kernel-pkg",
                    ["--mkinitrd", "--dracut", "--depmod", "--update", kernel],
                    root=sysroot
                )
示例#48
0
    def add_driver_repos(self):
        """Add driver repositories and packages."""
        # Drivers are loaded by anaconda-dracut, their repos are copied
        # into /run/install/DD-X where X is a number starting at 1. The list of
        # packages that were selected is in /run/install/dd_packages

        # Add repositories
        dir_num = 0
        while True:
            dir_num += 1
            repo = "/run/install/DD-%d/" % dir_num
            if not os.path.isdir(repo):
                break

            # Run createrepo if there are rpms and no repodata
            if not os.path.isdir(repo + "/repodata"):
                rpms = glob(repo + "/*rpm")
                if not rpms:
                    continue
                log.info("Running createrepo on %s", repo)
                util.execWithRedirect("createrepo_c", [repo])

            repo_name = "DD-%d" % dir_num
            if repo_name not in self.addons:
                ks_repo = self.data.RepoData(name=repo_name,
                                             baseurl="file://" + repo,
                                             enabled=True)
                self.add_repo(ks_repo)

        # Add packages
        if not os.path.exists("/run/install/dd_packages"):
            return
        with open("/run/install/dd_packages", "r") as f:
            for line in f:
                package = line.strip()
                self.requirements.add_packages([package], reason="driver disk")
示例#49
0
def get_locale_map_from_ostree(repo, ref):
    """Get a map of languages and locales from the given OSTree.

    For example: {"en": ["en_US"]}

    :param repo: the OSTree repository url
    :param ref: the name of branch inside the repository
    :return: a map of languages and locales
    """
    # Fallback to just en_US in case of errors.
    locale_map = {"en": ["en_US"]}

    # Let's only handle local embedded repos for now. Anyway, it'd probably
    # not be very common to only override ostreesetup through kickstart and
    # still want the interactive installer. Though to be nice, let's handle
    # that case.
    if not repo.startswith("file://"):
        log.info("ostree repo is not local; defaulting to en_US")
        return

    # Convert to regular UNIX path.
    repo = repo[len("file://"):]

    util.mkdirChain(os.path.join(repo, "tmp/usr/lib"))
    rc = util.execWithRedirect("/usr/bin/ostree",
                               ["checkout", "--repo", repo, ref,
                                "--subpath", "/usr/lib/locale/locale-archive",
                                "%s/tmp/usr/lib/locale" % repo])
    if rc != 0:
        log.error("failed to check out locale-archive; check program.log")
        return

    for line in util.execReadlines("/usr/bin/localedef",
                                   ["--prefix", os.path.join(repo, "tmp"),
                                    "--list-archive"]):
        line = strip_codeset_and_modifier(line)
        if '_' in line:
            (lang, _territory) = line.split('_', 1)
        else:
            lang = line
        if lang not in locale_map:
            locale_map[lang] = [line]
        else:
            locale_map[lang].append(line)

    # Nuke the checkout for good measure.
    shutil.rmtree(os.path.join(repo, "tmp/usr"))
    return locale_map
示例#50
0
def set_console_font(font):
    """
    Try to set console font to the given value.

    :param str font: console font name
    :returns: True on success, False on failure
    :rtype: Bool

    """
    log.debug("setting console font to %s", font)
    rc = execWithRedirect("setfont", [font])
    if rc == 0:
        log.debug("console font set successfully to %s", font)
        return True
    else:
        log.error("setting console font to %s failed", font)
        return False
示例#51
0
    def install(self, args=None):
        if args is None:
            args = []

        # XXX will installing to multiple drives work as expected with GRUBv2?
        for (stage1dev, stage2dev) in self.install_targets:
            grub_args = args + ["--no-floppy", stage1dev.path]
            if stage1dev == stage2dev:
                # This is hopefully a temporary hack. GRUB2 currently refuses
                # to install to a partition's boot block without --force.
                grub_args.insert(0, '--force')
            else:
                if self.keep_mbr:
                    grub_args.insert(0, '--grub-setup=/bin/true')
                    log.info("bootloader.py: mbr update by grub2 disabled")
                else:
                    log.info("bootloader.py: mbr will be updated for grub2")

            rc = util.execWithRedirect("grub2-install", grub_args,
                                       root=util.getSysroot(),
                                       env_prune=['MALLOC_PERTURB_'])
            if rc:
                raise BootLoaderError("boot loader install failed")
示例#52
0
    def execute(self):
        if not self.discovered:
            return

        security_proxy = SECURITY.get_proxy()
        realm = RealmData.from_structure(security_proxy.Realm)

        for arg in realm.join_options:
            if arg.startswith("--no-password") or arg.startswith("--one-time-password"):
                pw_args = []
                break
        else:
            # no explicit password arg using implicit --no-password
            pw_args = ["--no-password"]

        argv = ["join", "--install", util.getSysroot(), "--verbose"] + pw_args + realm.join_options
        rc = -1
        try:
            rc = util.execWithRedirect("realm", argv)
        except OSError:
            pass

        if rc == 0:
            realm_log.info("Joined realm %s", realm.name)
示例#53
0
    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", "/boot/loader/", "--exclude", "/boot/efi/loader/",
                "--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 == 11:
            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 os.path.exists(util.getSysroot() + "/usr/sbin/new-kernel-pkg"):
            use_nkp = True
        else:
            log.warning("new-kernel-pkg does not exist - grubby wasn't installed?")
            use_nkp = False

        for kernel in self.kernel_version_list:
            log.info("Generating rescue image for %s", kernel)
            if use_nkp:
                util.execInSysroot("new-kernel-pkg",
                                   ["--rpmposttrans", kernel])
            else:
                files = glob.glob(util.getSysroot() + "/etc/kernel/postinst.d/*")
                srlen = len(util.getSysroot())
                files = sorted([f[srlen:] for f in files
                                if os.access(f, os.X_OK)])
                for file in files:
                    util.execInSysroot(file,
                                       [kernel, "/boot/vmlinuz-%s" % kernel])
示例#54
0
    def pre_install(self):
        """ 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._pre_install_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 util.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 = payload_utils.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._update_kernel_version_list()
            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 = util.execWithRedirect("mount",
                                       ["--make-rprivate", "/"])
            if rc == 0:
                rc = util.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 = payload_utils.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._update_kernel_version_list()

            source = os.statvfs(INSTALL_TREE)
            self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
示例#55
0
 def finish(self, delay=0):
     """Finish rescue mode with optional delay."""
     time.sleep(delay)
     if self.reboot:
         util.execWithRedirect("systemctl", ["--no-wall", "reboot"])
示例#56
0
    def createUser(self, user_name, *args, **kwargs):
        """Create a new user on the system with the given name.  Optional kwargs:

           :keyword str algo: The password algorithm to use in case isCrypted=True.
                              If none is given, the cryptPassword default is used.
           :keyword str gecos: The GECOS information (full name, office, phone, etc.).
                               Defaults to "".
           :keyword groups: A list of group names the user should be added to.
                            Each group name can contain an optional GID in parenthesis,
                            such as "groupName(5000)". Defaults to [].
           :type groups: list of str
           :keyword str homedir: The home directory for the new user.  Defaults to
                                 /home/<name>.
           :keyword bool isCrypted: Is the password kwargs already encrypted?  Defaults
                                    to False.
           :keyword bool lock: Is the new account locked by default?  Defaults to
                               False.
           :keyword str password: The password.  See isCrypted for how this is interpreted.
                                  If the password is "" then the account is created
                                  with a blank password. If None or False the account will
                                  be left in its initial state (locked)
           :keyword str root: The directory of the system to create the new user
                              in.  homedir will be interpreted relative to this.
                              Defaults to util.getSysroot().
           :keyword str shell: The shell for the new user.  If none is given, the
                               login.defs default is used.
           :keyword int uid: The UID for the new user.  If none is given, the next
                             available one is used.
           :keyword int gid: The GID for the new user.  If none is given, the next
                             available one is used.
        """

        root = kwargs.get("root", util.getSysroot())

        if self.checkUserExists(user_name, root):
            raise ValueError("User %s already exists" % user_name)

        args = ["-R", root]

        # Split the groups argument into a list of (username, gid or None) tuples
        # the gid, if any, is a string since that makes things simpler
        group_gids = [GROUPLIST_FANCY_PARSE.match(group).groups()
                      for group in kwargs.get("groups", [])]

        # If a specific gid is requested:
        #   - check if a group already exists with that GID. i.e., the user's
        #     GID should refer to a system group, such as users. If so, just set
        #     the GID.
        #   - check if a new group is requested with that GID. If so, set the GID
        #     and let the block below create the actual group.
        #   - if neither of those are true, create a new user group with the requested
        #     GID
        # otherwise use -U to create a new user group with the next available GID.
        if kwargs.get("gid", None):
            if not self._getgrgid(kwargs['gid'], root) and \
                    not any(gid[1] == str(kwargs['gid']) for gid in group_gids):
                self.createGroup(user_name, gid=kwargs['gid'], root=root)

            args.extend(['-g', str(kwargs['gid'])])
        else:
            args.append('-U')

        # If any requested groups do not exist, create them.
        group_list = []
        for group_name, gid in group_gids:
            existing_group = self._getgrnam(group_name, root)

            # Check for a bad GID request
            if gid and existing_group and gid != existing_group[2]:
                raise ValueError("Group %s already exists with GID %s" % (group_name, gid))

            # Otherwise, create the group if it does not already exist
            if not existing_group:
                self.createGroup(group_name, gid=gid, root=root)
            group_list.append(group_name)

        if group_list:
            args.extend(['-G', ",".join(group_list)])

        if kwargs.get("homedir"):
            homedir = kwargs["homedir"]
        else:
            homedir = "/home/" + user_name

        # useradd expects the parent directory tree to exist.
        parent_dir = util.parent_dir(root + homedir)

        # If root + homedir came out to "/", such as if we're creating the sshpw user,
        # parent_dir will be empty. Don't create that.
        if parent_dir:
            util.mkdirChain(parent_dir)

        args.extend(["-d", homedir])

        # Check whether the directory exists or if useradd should create it
        mk_homedir = not os.path.exists(root + homedir)
        if mk_homedir:
            args.append("-m")
        else:
            args.append("-M")

        if kwargs.get("shell"):
            args.extend(["-s", kwargs["shell"]])

        if kwargs.get("uid"):
            args.extend(["-u", str(kwargs["uid"])])

        if kwargs.get("gecos"):
            args.extend(["-c", kwargs["gecos"]])

        args.append(user_name)
        with self._ensureLoginDefs(root):
            status = util.execWithRedirect("useradd", args)

        if status == 4:
            raise ValueError("UID %s already exists" % kwargs.get("uid"))
        elif status == 6:
            raise ValueError("Invalid groups %s" % kwargs.get("groups", []))
        elif status == 9:
            raise ValueError("User %s already exists" % user_name)
        elif status != 0:
            raise OSError("Unable to create user %s: status=%s" % (user_name, status))

        if not mk_homedir:
            try:
                stats = os.stat(root + homedir)
                orig_uid = stats.st_uid
                orig_gid = stats.st_gid

                # Gett the UID and GID of the created user
                pwent = self._getpwnam(user_name, root)

                log.info("Home directory for the user %s already existed, "
                         "fixing the owner and SELinux context.", user_name)
                # home directory already existed, change owner of it properly
                util.chown_dir_tree(root + homedir,
                                    int(pwent[2]), int(pwent[3]),
                                    orig_uid, orig_gid)
                util.execWithRedirect("restorecon", ["-r", root + homedir])
            except OSError as e:
                log.critical("Unable to change owner of existing home directory: %s", e.strerror)
                raise

        pw = kwargs.get("password", False)
        crypted = kwargs.get("isCrypted", False)
        algo = kwargs.get("algo", None)
        lock = kwargs.get("lock", False)

        self.setUserPassword(user_name, pw, crypted, lock, algo, root)
示例#57
0
    def _setup_nfs_device(self, storage, method, isodev, device):
        # There are several possible scenarios here:
        # 1. dracut could have mounted both the nfs repo and an iso and used
        #    the stage2 from inside the iso to boot from.
        #    isodev and device will be set in this case.
        # 2. dracut could have mounted the nfs repo and used a stage2 from
        #    the NFS mount w/o mounting the iso.
        #    isodev will be None and device will be the nfs: path
        # 3. dracut did not mount the nfs (eg. stage2 came from elsewhere)
        #    isodev and/or device are None
        # 4. The repo may not contain an iso, in that case use it as is
        url = None
        path = None

        if isodev and device:
            path = util.parseNfsUrl('nfs:%s' % isodev)[2]
            # See if the dir holding the iso is what we want
            # and also if we have an iso mounted to /run/install/repo
            if path and path in isodev and DRACUT_ISODIR in device:
                # Everything should be setup
                url = "file://" + DRACUT_REPODIR
        else:
            # see if the nfs dir is mounted
            need_mount = True
            if device:
                _options, host, path = util.parseNfsUrl('nfs:%s' % device)
                if method.server and method.server == host and \
                   method.dir and method.dir == path:
                    need_mount = False
                    path = DRACUT_REPODIR
            elif isodev:
                # isodev with no device can happen when options on an existing
                # nfs mount have changed. It is already mounted, but on INSTALL_TREE
                # which is the same as DRACUT_ISODIR, making it hard for _setup_NFS
                # to detect that it is already mounted.
                _options, host, path = util.parseNfsUrl('nfs:%s' % isodev)
                if path and path in isodev:
                    need_mount = False
                    path = DRACUT_ISODIR

            if need_mount:
                # Mount the NFS share on INSTALL_TREE. If it ends up
                # being nfsiso we will move the mountpoint to ISO_DIR.
                if method.dir.endswith(".iso"):
                    nfs_dir = os.path.dirname(method.dir)
                else:
                    nfs_dir = method.dir

                self._setup_NFS(INSTALL_TREE, method.server, nfs_dir, method.opts)
                path = INSTALL_TREE

            # check for ISO images in the newly mounted dir
            if method.dir.endswith(".iso"):
                # if the given URL includes a specific ISO image file, use it
                image_file = os.path.basename(method.dir)
                path = os.path.normpath("%s/%s" % (path, image_file))

            image = findFirstIsoImage(path)

            # An image was found, mount it on INSTALL_TREE
            if image:
                if path.startswith(INSTALL_TREE):
                    # move the INSTALL_TREE mount to ISO_DIR so we can
                    # mount the contents of the iso there.
                    # work around inability to move shared filesystems
                    util.execWithRedirect("mount",
                                          ["--make-rprivate", "/"])
                    util.execWithRedirect("mount",
                                          ["--move", INSTALL_TREE, ISO_DIR])
                    # The iso is now under ISO_DIR
                    path = ISO_DIR
                elif path.endswith(".iso"):
                    path = os.path.dirname(path)

                # mount the ISO on a loop
                image = os.path.normpath("%s/%s" % (path, image))
                mountImage(image, INSTALL_TREE)

                url = "file://" + INSTALL_TREE
            elif os.path.isdir(path):
                # Fall back to the mount path instead of a mounted iso
                url = "file://" + path
            else:
                # Do not try to use iso as source if it is not valid source
                raise PayloadSetupError("Not a valid ISO image!")

        return url
示例#58
0
    try:
        pidfile.create()
    except pid.PidFileError as e:
        log.error("Unable to create %s, exiting", pidfile.filename)

        # If we had a $DISPLAY at start and zenity is available, we may be
        # running in a live environment and we can display an error dialog.
        # Otherwise just print an error.
        if flags.preexisting_x11 and os.access("/usr/bin/zenity", os.X_OK):
            # The module-level _() calls are ok here because the language may
            # be set from the live environment in this case, and anaconda's
            # language setup hasn't happened yet.
            # pylint: disable=found-_-in-module-class
            util.execWithRedirect("zenity",
                                  ["--error", "--title", _("Unable to create PID file"), "--text",
                                   _("Anaconda is unable to create %s because the file"
                                     " already exists. Anaconda is already running, or "
                                     "a previous instance of anaconda has crashed.")
                                   % pidfile.filename])
        else:
            print("%s already exists, exiting" % pidfile.filename)

        util.ipmi_report(constants.IPMI_FAILED)
        sys.exit(1)

    # add our own additional signal handlers
    signal.signal(signal.SIGHUP, start_debugger)

    # assign the other anaconda variables from options
    anaconda.set_from_opts(opts)

    # check memory, just the text mode for now: