Exemple #1
0
    def setup(self):
        super().setup()

        # Mount the live device and copy from it instead of the overlay at /
        osimg = payload_utils.resolve_device(self.data.method.partition)
        if not osimg:
            raise PayloadInstallError("Unable to find osimg for %s" %
                                      self.data.method.partition)

        osimg_path = payload_utils.get_device_path(osimg)
        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 _flatpak_install(self):
        # Install flatpak from the local source on SilverBlue
        progressQ.send_message(_("Starting Flatpak installation"))
        # Cleanup temporal repo created in the __init__
        self._flatpak_payload.cleanup()

        # Initialize new repo on the installed system
        self._flatpak_payload.initialize_with_system_path()

        try:
            self._flatpak_payload.install_all()
        except FlatpakInstallError as e:
            exn = PayloadInstallError("Failed to install flatpaks: %s" % e)
            log.error(str(exn))
            if errors.errorHandler.cb(exn) == errors.ERROR_RAISE:
                progressQ.send_quit(1)
                util.ipmi_abort(scripts=self.data.scripts)
                sys.exit(1)

        progressQ.send_message(_("Post-installation flatpak tasks"))

        self._flatpak_payload.add_remote("fedora", "oci+https://registry.fedoraproject.org")
        self._flatpak_payload.replace_installed_refs_remote("fedora")
        self._flatpak_payload.remove_remote(FlatpakPayload.LOCAL_REMOTE_NAME)

        progressQ.send_message(_("Flatpak installation has finished"))
Exemple #3
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
Exemple #4
0
    def run(self):
        """Pull a remote and delete it.

        All pulls in our code follow the pattern pull + delete.

        :raise: PayloadInstallError if the pull fails
        """
        # pull requires this for some reason
        mainctx = create_new_context()
        mainctx.push_thread_default()

        cancellable = None

        # Variable substitute the ref: https://pagure.io/atomic-wg/issue/299
        ref = RpmOstree.varsubst_basearch(self._data.ref)

        self.report_progress(
            _("Starting pull of {branch_name} from {source}").format(
                branch_name=ref, source=self._data.remote))

        progress = OSTree.AsyncProgress.new()
        progress.connect('changed', self._pull_progress_cb)

        pull_opts = {'refs': Variant('as', [ref])}
        # If we're doing a kickstart, we can at least use the content as a reference:
        # See <https://github.com/rhinstaller/anaconda/issues/1117>
        # The first path here is used by <https://pagure.io/fedora-lorax-templates>
        # and the second by <https://github.com/projectatomic/rpm-ostree-toolbox/>
        # FIXME extend tests to cover this part of code
        if OSTree.check_version(2017, 8):
            for path in ['/ostree/repo', '/install/ostree/repo']:
                if os.path.isdir(path + '/objects'):
                    pull_opts['localcache-repos'] = Variant('as', [path])
                    break

        sysroot_file = Gio.File.new_for_path(conf.target.physical_root)
        sysroot = OSTree.Sysroot.new(sysroot_file)
        sysroot.load(cancellable)
        repo = sysroot.get_repo(None)[1]
        # We don't support resuming from interrupted installs
        repo.set_disable_fsync(True)

        try:
            repo.pull_with_options(self._data.remote,
                                   Variant('a{sv}', pull_opts), progress,
                                   cancellable)
        except GError as e:
            raise PayloadInstallError("Failed to pull from repository: %s" %
                                      e) from e

        log.info("ostree pull: %s", progress.get_status() or "")
        self.report_progress(_("Preparing deployment of {}").format(ref))

        # Now that we have the data pulled, delete the remote for now. This will allow a remote
        # configuration defined in the tree (if any) to override what's in the kickstart.
        # Otherwise, we'll re-add it in post.  Ideally, ostree would support a pull without adding
        # a remote, but that would get quite complex.
        repo.remote_delete(self._data.remote, None)

        mainctx.pop_thread_default()
Exemple #5
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", "/tmp/*", "--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
        self._create_rescue_image()
Exemple #6
0
def safe_exec_with_redirect(cmd, argv, **kwargs):
    """Like util.execWithRedirect, but treat errors as fatal.

    :raise: PayloadInstallError if the call fails for any reason
    """
    rc = execWithRedirect(cmd, argv, **kwargs)
    if rc != 0:
        raise PayloadInstallError("{} {} exited with code {}".format(
            cmd, argv, rc))
Exemple #7
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", "tmp/*",
            "--exclude", "sys/*", "--exclude", "run/*", "--exclude",
            "boot/*rescue*", "--exclude", "boot/loader", "--exclude",
            "boot/efi/loader", "--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
        self._create_rescue_image()
Exemple #8
0
    def kernel_version_list(self):
        # If it doesn't look like a tarfile use the super's kernel_version_list
        if not self.is_tarfile:
            return super().kernel_version_list

        if self._kernel_version_list:
            return self._kernel_version_list

        # Cache a list of the kernels (the tar payload may be cleaned up on subsequent calls)
        if not os.path.exists(self.image_path):
            raise PayloadInstallError("kernel_version_list: missing tar payload")

        self._kernel_version_list = get_kernel_version_list_from_tar(self.image_path)

        return self._kernel_version_list
Exemple #9
0
    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)
Exemple #10
0
    def setup(self, storage):
        """ 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, storage)

        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 _install(self, data):
        log.info("executing ostreesetup=%r", data)

        from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
            InitOSTreeFsAndRepoTask
        task = InitOSTreeFsAndRepoTask(conf.target.physical_root)
        task.run()

        # Here, we use the physical root as sysroot, because we haven't
        # yet made a deployment.
        from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
            ChangeOSTreeRemoteTask
        task = ChangeOSTreeRemoteTask(data,
                                      use_root=False,
                                      root=conf.target.physical_root)
        task.run()

        from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
            PullRemoteAndDeleteTask
        task = PullRemoteAndDeleteTask(data)
        task.progress_changed_signal.connect(self._progress_cb)
        task.run()

        from pyanaconda.modules.payloads.payload.rpm_ostree.installation import DeployOSTreeTask
        task = DeployOSTreeTask(data, conf.target.physical_root)
        task.progress_changed_signal.connect(self._progress_cb)
        task.run()

        # Reload now that we've deployed, find the path to the new deployment
        from pyanaconda.modules.payloads.payload.rpm_ostree.installation import SetSystemRootTask
        task = SetSystemRootTask(conf.target.physical_root)
        task.run()

        try:
            from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
                CopyBootloaderDataTask
            task = CopyBootloaderDataTask(sysroot=conf.target.system_root,
                                          physroot=conf.target.physical_root)
            task.run()
        except (OSError, RuntimeError) as e:
            raise PayloadInstallError("Failed to copy bootloader data: %s" %
                                      e) from e
    def kernel_version_list(self):
        # If it doesn't look like a tarfile use the super's kernel_version_list
        if not self.is_tarfile:
            return super().kernel_version_list

        if self._kernel_version_list:
            return self._kernel_version_list

        # Cache a list of the kernels (the tar payload may be cleaned up on subsequent calls)
        if not os.path.exists(self.image_path):
            raise PayloadInstallError("kernel_version_list: missing tar payload")

        import tarfile
        with tarfile.open(self.image_path) as archive:
            names = archive.getnames()

            # Strip out vmlinuz- from the names
            self._kernel_version_list = sorted((n.split("/")[-1][8:] for n in names
                                               if "boot/vmlinuz-" in n),
                                               key=functools.cmp_to_key(payload_utils.version_cmp))
        return self._kernel_version_list
Exemple #13
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))

        # Run the installation task.
        task = InstallFromImageTask(
            sysroot=conf.target.system_root,
            mount_point=INSTALL_TREE + "/"
        )
        task.run()

        # Wait for progress thread to finish
        with self.pct_lock:
            self.pct = 100
        threadMgr.wait(THREAD_LIVE_PROGRESS)
    def run(self):
        self.report_progress(_("Starting Flatpak installation"))

        flatpak_manager = FlatpakManager(self._sysroot)

        # Initialize new repo on the installed system
        flatpak_manager.initialize_with_system_path()

        try:
            flatpak_manager.install_all()
        except FlatpakInstallError as e:
            raise PayloadInstallError(
                "Failed to install flatpaks: {}".format(e)) from e

        self.report_progress(_("Post-installation flatpak tasks"))

        flatpak_manager.add_remote("fedora",
                                   "oci+https://registry.fedoraproject.org")
        flatpak_manager.replace_installed_refs_remote("fedora")
        flatpak_manager.remove_remote(FlatpakManager.LOCAL_REMOTE_NAME)

        self.report_progress(_("Flatpak installation has finished"))
Exemple #15
0
    def _flatpak_install(self):
        # Install flatpak from the local source on SilverBlue
        progressQ.send_message(_("Starting Flatpak installation"))
        # Cleanup temporal repo created in the __init__
        self._flatpak_payload.cleanup()

        # Initialize new repo on the installed system
        self._flatpak_payload.initialize_with_system_path()

        try:
            self._flatpak_payload.install_all()
        except FlatpakInstallError as e:
            raise PayloadInstallError("Failed to install flatpaks: %s" %
                                      e) from e

        progressQ.send_message(_("Post-installation flatpak tasks"))

        self._flatpak_payload.add_remote(
            "fedora", "oci+https://registry.fedoraproject.org")
        self._flatpak_payload.replace_installed_refs_remote("fedora")
        self._flatpak_payload.remove_remote(FlatpakPayload.LOCAL_REMOTE_NAME)

        progressQ.send_message(_("Flatpak installation has finished"))
    def install(self):
        mainctx = create_new_context()
        mainctx.push_thread_default()

        cancellable = None
        gi.require_version("OSTree", "1.0")
        gi.require_version("RpmOstree", "1.0")
        from gi.repository import OSTree, RpmOstree
        ostreesetup = self.data.ostreesetup
        log.info("executing ostreesetup=%r", ostreesetup)

        # Initialize the filesystem - this will create the repo as well
        self._safe_exec_with_redirect("ostree", [
            "admin", "--sysroot=" + conf.target.physical_root, "init-fs",
            conf.target.physical_root
        ])

        # Here, we use the physical root as sysroot, because we haven't
        # yet made a deployment.
        sysroot_file = Gio.File.new_for_path(conf.target.physical_root)
        sysroot = OSTree.Sysroot.new(sysroot_file)
        sysroot.load(cancellable)
        repo = sysroot.get_repo(None)[1]
        # We don't support resuming from interrupted installs
        repo.set_disable_fsync(True)

        self._remoteOptions = {}

        if hasattr(ostreesetup, 'nogpg') and ostreesetup.nogpg:
            self._remoteOptions['gpg-verify'] = Variant('b', False)

        if not conf.payload.verify_ssl:
            self._remoteOptions['tls-permissive'] = Variant('b', True)

        repo.remote_change(None, OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS,
                           ostreesetup.remote, ostreesetup.url,
                           Variant('a{sv}', self._remoteOptions), cancellable)

        # Variable substitute the ref: https://pagure.io/atomic-wg/issue/299
        ref = RpmOstree.varsubst_basearch(ostreesetup.ref)

        progressQ.send_message(
            _("Starting pull of %(branchName)s from %(source)s") % {
                "branchName": ref,
                "source": ostreesetup.remote
            })

        progress = OSTree.AsyncProgress.new()
        progress.connect('changed', self._pull_progress_cb)

        pull_opts = {'refs': Variant('as', [ref])}
        # If we're doing a kickstart, we can at least use the content as a reference:
        # See <https://github.com/rhinstaller/anaconda/issues/1117>
        # The first path here is used by <https://pagure.io/fedora-lorax-templates>
        # and the second by <https://github.com/projectatomic/rpm-ostree-toolbox/>
        if OSTree.check_version(2017, 8):
            for path in ['/ostree/repo', '/install/ostree/repo']:
                if os.path.isdir(path + '/objects'):
                    pull_opts['localcache-repos'] = Variant('as', [path])
                    break

        try:
            repo.pull_with_options(ostreesetup.remote,
                                   Variant('a{sv}', pull_opts), progress,
                                   cancellable)
        except GError as e:
            exn = PayloadInstallError("Failed to pull from repository: %s" % e)
            log.error(str(exn))
            if errors.errorHandler.cb(exn) == errors.ERROR_RAISE:
                progressQ.send_quit(1)
                util.ipmi_abort(scripts=self.data.scripts)
                sys.exit(1)

        log.info("ostree pull: %s", progress.get_status() or "")
        progressQ.send_message(_("Preparing deployment of %s") % (ref, ))

        # Now that we have the data pulled, delete the remote for now.
        # This will allow a remote configuration defined in the tree
        # (if any) to override what's in the kickstart.  Otherwise,
        # we'll re-add it in post.  Ideally, ostree would support a
        # pull without adding a remote, but that would get quite
        # complex.
        repo.remote_delete(self.data.ostreesetup.remote, None)

        self._safe_exec_with_redirect("ostree", [
            "admin", "--sysroot=" + conf.target.physical_root, "os-init",
            ostreesetup.osname
        ])

        admin_deploy_args = [
            "admin", "--sysroot=" + conf.target.physical_root, "deploy",
            "--os=" + ostreesetup.osname
        ]

        admin_deploy_args.append(ostreesetup.remote + ':' + ref)

        log.info("ostree admin deploy starting")
        progressQ.send_message(_("Deployment starting: %s") % (ref, ))
        self._safe_exec_with_redirect("ostree", admin_deploy_args)
        log.info("ostree admin deploy complete")
        progressQ.send_message(_("Deployment complete: %s") % (ref, ))

        # Reload now that we've deployed, find the path to the new deployment
        sysroot.load(None)
        deployments = sysroot.get_deployments()
        assert len(deployments) > 0
        deployment = deployments[0]
        deployment_path = sysroot.get_deployment_directory(deployment)
        util.set_system_root(deployment_path.get_path())

        try:
            self._copy_bootloader_data()
        except (OSError, RuntimeError) as e:
            exn = PayloadInstallError("Failed to copy bootloader data: %s" % e)
            log.error(str(exn))
            if errors.errorHandler.cb(exn) == errors.ERROR_RAISE:
                progressQ.send_quit(1)
                util.ipmi_abort(scripts=self.data.scripts)
                sys.exit(1)

        mainctx.pop_thread_default()
Exemple #17
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:
         raise PayloadInstallError("%s %s exited with code %d" %
                                   (cmd, argv, rc))
Exemple #18
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)
Exemple #19
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.liveimg.url.startswith("file://"):
            self.image_path = self.data.liveimg.url[7:]
        else:
            error = self._pre_install_url_image()

        if error:
            raise PayloadInstallError(str(error))

        # Verify the checksum.
        task = VerifyImageChecksum(image_path=self.image_path,
                                   checksum=self.data.liveimg.checksum)
        task.progress_changed_signal.connect(self._progress_cb)
        task.run()

        # If this looks like a tarfile, skip trying to mount it
        if self.is_tarfile:
            return

        # 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 = util.execWithRedirect("mount", ["--make-rprivate", "/"])
        if rc != 0:
            log.error("mount error (%s) making mount of '/' rprivate", rc)
            raise PayloadInstallError("mount error %s" % 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 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)
            raise PayloadInstallError("mount error %s" % rc)

        # 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)
            rc = util.execWithRedirect("mount",
                                       ["--move", INSTALL_TREE, IMAGE_DIR])
            if rc != 0:
                log.error("error %s moving mount", rc)
                raise PayloadInstallError("mount error %s" % rc)

            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)
                raise PayloadInstallError("mount error %s with %s" %
                                          (rc, img_file))

            self._update_kernel_version_list()
Exemple #20
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])