コード例 #1
0
ファイル: livepayload.py プロジェクト: evildesign/anaconda
    def setup(self, storage, instClass):
        super(LiveImagePayload, self).setup(storage, instClass)

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

        if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]):
            exn = PayloadSetupError("%s is not a valid block device" %
                                    (self.data.method.partition, ))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn
        rc = blivet.util.mount(osimg.path,
                               INSTALL_TREE,
                               fstype="auto",
                               options="ro")
        if rc != 0:
            raise PayloadInstallError("Failed to mount the install tree")

        # Grab the kernel version list now so it's available after umount
        self._updateKernelVersionList()

        source = os.statvfs(INSTALL_TREE)
        self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
コード例 #2
0
ファイル: livepayload.py プロジェクト: evildesign/anaconda
    def install(self):
        """ Install the payload. """

        if self.source_size <= 0:
            raise PayloadInstallError("Nothing to install")

        self.pct_lock = Lock()
        self.pct = 0
        threadMgr.add(
            AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress))

        cmd = "rsync"
        # preserve: permissions, owners, groups, ACL's, xattrs, times,
        #           symlinks, hardlinks
        # go recursively, include devices and special files, don't cross
        # file system boundaries
        args = [
            "-pogAXtlHrDx", "--exclude", "/dev/", "--exclude", "/proc/",
            "--exclude", "/sys/", "--exclude", "/run/", "--exclude",
            "/boot/*rescue*", "--exclude", "/etc/machine-id",
            INSTALL_TREE + "/",
            iutil.getSysroot()
        ]
        try:
            rc = iutil.execWithRedirect(cmd, args)
        except (OSError, RuntimeError) as e:
            msg = None
            err = str(e)
            log.error(err)
        else:
            err = None
            msg = "%s exited with code %d" % (cmd, rc)
            log.info(msg)

        if err or rc == 12:
            exn = PayloadInstallError(err or msg)
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Wait for progress thread to finish
        with self.pct_lock:
            self.pct = 100
        threadMgr.wait(THREAD_LIVE_PROGRESS)

        # Live needs to create the rescue image before bootloader is written
        if not os.path.exists(iutil.getSysroot() + "/usr/sbin/new-kernel-pkg"):
            log.error(
                "new-kernel-pkg does not exist - grubby wasn't installed?  skipping"
            )
            return

        for kernel in self.kernelVersionList:
            log.info("Generating rescue image for %s", kernel)
            iutil.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
コード例 #3
0
ファイル: rpmostreepayload.py プロジェクト: bwann/anaconda
 def _safeExecWithRedirect(self, cmd, argv, **kwargs):
     """Like iutil.execWithRedirect, but treat errors as fatal"""
     rc = iutil.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
コード例 #4
0
ファイル: livepayload.py プロジェクト: jjmichaud/anaconda
    def install(self):
        """ Install the payload. """
        self.pct_lock = Lock()
        self.pct = 0
        threadMgr.add(AnacondaThread(name=THREAD_LIVE_PROGRESS,
                                     target=self.progress))

        cmd = "rsync"
        # preserve: permissions, owners, groups, ACL's, xattrs, times,
        #           symlinks, hardlinks
        # go recursively, include devices and special files, don't cross
        # file system boundaries
        args = ["-pogAXtlHrDx", "--exclude", "/dev/", "--exclude", "/proc/",
                "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*",
                "--exclude", "/etc/machine-id", INSTALL_TREE+"/", ROOT_PATH]
        try:
            rc = iutil.execWithRedirect(cmd, args)
        except (OSError, RuntimeError) as e:
            msg = None
            err = str(e)
            log.error(err)
        else:
            err = None
            msg = "%s exited with code %d" % (cmd, rc)
            log.info(msg)

        if err or rc == 12:
            exn = PayloadInstallError(err or msg)
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Wait for progress thread to finish
        with self.pct_lock:
            self.pct = 100
        threadMgr.wait(THREAD_LIVE_PROGRESS)
コード例 #5
0
ファイル: livepayload.py プロジェクト: evildesign/anaconda
    def install(self):
        """ Install the payload if it is a tar.
            Otherwise fall back to rsync of INSTALL_TREE
        """
        # If it doesn't look like a tarfile use the super's install()
        if not self.is_tarfile:
            super(LiveImageKSPayload, self).install()
            return

        # Use 2x the archive's size to estimate the size of the install
        # This is used to drive the progress display
        self.source_size = os.stat(self.image_path)[stat.ST_SIZE] * 2

        self.pct_lock = Lock()
        self.pct = 0
        threadMgr.add(
            AnacondaThread(name=THREAD_LIVE_PROGRESS, target=self.progress))

        cmd = "tar"
        # preserve: ACL's, xattrs, and SELinux context
        args = [
            "--selinux", "--acls", "--xattrs", "--xattrs-include", "*",
            "--exclude", "/dev/", "--exclude", "/proc/", "--exclude", "/sys/",
            "--exclude", "/run/", "--exclude", "/boot/*rescue*", "--exclude",
            "/etc/machine-id", "-xaf", self.image_path, "-C",
            iutil.getSysroot()
        ]
        try:
            rc = iutil.execWithRedirect(cmd, args)
        except (OSError, RuntimeError) as e:
            msg = None
            err = str(e)
            log.error(err)
        else:
            err = None
            msg = "%s exited with code %d" % (cmd, rc)
            log.info(msg)

        if err:
            exn = PayloadInstallError(err or msg)
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Wait for progress thread to finish
        with self.pct_lock:
            self.pct = 100
        threadMgr.wait(THREAD_LIVE_PROGRESS)

        # Live needs to create the rescue image before bootloader is written
        for kernel in self.kernelVersionList:
            log.info("Generating rescue image for %s", kernel)
            iutil.execInSysroot("new-kernel-pkg", ["--rpmposttrans", kernel])
コード例 #6
0
ファイル: livepayload.py プロジェクト: evildesign/anaconda
    def setup(self, storage, instClass):
        """ Check the availability and size of the image.
        """
        # This is on purpose, we don't want to call LiveImagePayload's setup method.
        ImagePayload.setup(self, storage, instClass)

        if self.data.method.url.startswith("file://"):
            error = self._setup_file_image()
        else:
            error = self._setup_url_image()

        if error:
            exn = PayloadInstallError(str(error))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        log.debug("liveimg size is %s", self._min_size)
コード例 #7
0
    def setup(self, storage, instClass):
        super(LiveImagePayload, self).setup(storage, instClass)

        # Mount the live device and copy from it instead of the overlay at /
        osimg = storage.devicetree.getDeviceByPath(self.data.method.partition)
        if not stat.S_ISBLK(os.stat(osimg.path)[stat.ST_MODE]):
            exn = PayloadSetupError("%s is not a valid block device" %
                                    (self.data.method.partition, ))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn
        rc = blivet.util.mount(osimg.path,
                               INSTALL_TREE,
                               fstype="auto",
                               options="ro")
        if rc != 0:
            raise PayloadInstallError("Failed to mount the install tree")

        source = iutil.eintr_retry_call(os.statvfs, INSTALL_TREE)
        self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
コード例 #8
0
ファイル: livepayload.py プロジェクト: jjmichaud/anaconda
    def setup(self, storage, instClass):
        """ Check the availability and size of the image.
        """
        # This is on purpose, we don't want to call LiveImagePayload's setup method.
        ImagePayload.setup(self, storage, instClass)

        self._proxies = {}
        if self.data.method.proxy:
            try:
                proxy = ProxyString(self.data.method.proxy)
                self._proxies = {"http": proxy.url,
                                 "https": proxy.url}
            except ProxyStringError as e:
                log.info("Failed to parse proxy for liveimg --proxy=\"%s\": %s",
                         self.data.method.proxy, e)

        error = None
        try:
            req = urllib.urlopen(self.data.method.url, proxies=self._proxies)
        except IOError as e:
            log.error("Error opening liveimg: %s", e)
            error = e
        else:
            # If it is a http request we need to check the code
            method = self.data.method.url.split(":", 1)[0]
            if method.startswith("http") and req.getcode() != 200:
                error = "http request returned %s" % req.getcode()

        if error:
            exn = PayloadInstallError(str(error))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # At this point we know we can get the image and what its size is
        # Make a guess as to minimum size needed:
        # Enough space for image and image * 3
        if req.info().get("content-length"):
            self._min_size = int(req.info().get("content-length")) * 4

        log.debug("liveimg size is %s", self._min_size)
コード例 #9
0
    def install(self):
        mainctx = GLib.MainContext.new()
        mainctx.push_thread_default()

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

        # Initialize the filesystem - this will create the repo as well
        self._safeExecWithRedirect("ostree", [
            "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "init-fs",
            iutil.getTargetPhysicalRoot()
        ])

        self._sysroot_path = Gio.File.new_for_path(
            iutil.getTargetPhysicalRoot())

        sysroot = OSTree.Sysroot.new(self._sysroot_path)
        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'] = GLib.Variant('b', False)

        if flags.noverifyssl:
            self._remoteOptions['tls-permissive'] = GLib.Variant('b', True)

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

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

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

        try:
            repo.pull(ostreesetup.remote, [ostreesetup.ref], 0, progress,
                      cancellable)
        except GLib.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)
                iutil.ipmi_report(constants.IPMI_ABORTED)
                sys.exit(1)

        progressQ.send_message(
            _("Preparing deployment of %s") % (ostreesetup.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._safeExecWithRedirect("ostree", [
            "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "os-init",
            ostreesetup.osname
        ])

        admin_deploy_args = [
            "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "deploy",
            "--os=" + ostreesetup.osname
        ]

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

        log.info("ostree admin deploy starting")
        progressQ.send_message(
            _("Deployment starting: %s") % (ostreesetup.ref, ))
        self._safeExecWithRedirect("ostree", admin_deploy_args)
        log.info("ostree admin deploy complete")
        progressQ.send_message(
            _("Deployment complete: %s") % (ostreesetup.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)
        iutil.setSysroot(deployment_path.get_path())

        try:
            self._copyBootloaderData()
        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)
                iutil.ipmi_report(constants.IPMI_ABORTED)
                sys.exit(1)

        mainctx.pop_thread_default()
コード例 #10
0
ファイル: livepayload.py プロジェクト: evildesign/anaconda
    def preInstall(self, *args, **kwargs):
        """ Get image and loopback mount it.

            This is called after partitioning is setup, we now have space to
            grab the image. If it is a network source Download it to sysroot
            and provide feedback during the download (using urlgrabber
            callback).

            If it is a file:// source then use the file directly.
        """
        error = None
        if self.data.method.url.startswith("file://"):
            self.image_path = self.data.method.url[7:]
        else:
            error = self._preInstall_url_image()

        if error:
            exn = PayloadInstallError(str(error))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Used to make install progress % look correct
        self._adj_size = os.stat(self.image_path)[stat.ST_SIZE]

        if self.data.method.checksum:
            progressQ.send_message(_("Checking image checksum"))
            sha256 = hashlib.sha256()
            with open(self.image_path, "rb") as f:
                while True:
                    data = f.read(1024 * 1024)
                    if not data:
                        break
                    sha256.update(data)
            filesum = sha256.hexdigest()
            log.debug("sha256 of %s is %s", self.data.method.url, filesum)

            if lowerASCII(self.data.method.checksum) != filesum:
                log.error("%s does not match checksum.",
                          self.data.method.checksum)
                exn = PayloadInstallError("Checksum of image does not match")
                if errorHandler.cb(exn) == ERROR_RAISE:
                    raise exn

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

        # Mount the image and check to see if it is a LiveOS/*.img
        # style squashfs image. If so, move it to IMAGE_DIR and mount the real
        # root image on INSTALL_TREE
        rc = blivet.util.mount(self.image_path,
                               INSTALL_TREE,
                               fstype="auto",
                               options="ro")
        if rc != 0:
            log.error("mount error (%s) with %s", rc, self.image_path)
            exn = PayloadInstallError("mount error %s" % rc)
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Nothing more to mount
        if not os.path.exists(INSTALL_TREE + "/LiveOS"):
            self._updateKernelVersionList()
            return

        # Mount the first .img in the directory on INSTALL_TREE
        img_files = glob.glob(INSTALL_TREE + "/LiveOS/*.img")
        if img_files:
            # move the mount to IMAGE_DIR
            os.makedirs(IMAGE_DIR, 0o755)
            # work around inability to move shared filesystems
            rc = iutil.execWithRedirect("mount", ["--make-rprivate", "/"])
            if rc == 0:
                rc = iutil.execWithRedirect(
                    "mount", ["--move", INSTALL_TREE, IMAGE_DIR])
            if rc != 0:
                log.error("error %s moving mount", rc)
                exn = PayloadInstallError("mount error %s" % rc)
                if errorHandler.cb(exn) == ERROR_RAISE:
                    raise exn

            img_file = IMAGE_DIR + "/LiveOS/" + os.path.basename(
                sorted(img_files)[0])
            rc = blivet.util.mount(img_file,
                                   INSTALL_TREE,
                                   fstype="auto",
                                   options="ro")
            if rc != 0:
                log.error("mount error (%s) with %s", rc, img_file)
                exn = PayloadInstallError("mount error %s with %s" %
                                          (rc, img_file))
                if errorHandler.cb(exn) == ERROR_RAISE:
                    raise exn

            self._updateKernelVersionList()

            source = os.statvfs(INSTALL_TREE)
            self.source_size = source.f_frsize * (source.f_blocks -
                                                  source.f_bfree)
コード例 #11
0
ファイル: livepayload.py プロジェクト: jjmichaud/anaconda
    def preInstall(self, *args, **kwargs):
        """ Download image and loopback mount it.

            This is called after partitioning is setup, we now have space
            to grab the image. Download it to ROOT_PATH and provide feedback
            during the download (using urlgrabber callback).
        """
        # Setup urlgrabber and call back to download image to ROOT_PATH
        progress = URLGrabberProgress()
        ugopts = {"ssl_verify_peer": not self.data.method.noverifyssl,
                  "ssl_verify_host": not self.data.method.noverifyssl,
                  "proxies" : self._proxies,
                  "progress_obj" : progress,
                  "copy_local" : True}

        error = None
        try:
            ug = URLGrabber()
            ug.urlgrab(self.data.method.url, self.image_path, **ugopts)
        except URLGrabError as e:
            log.error("Error downloading liveimg: %s", e)
            error = e
        else:
            if not os.path.exists(self.image_path):
                error = "Failed to download %s, file doesn't exist" % self.data.method.url
                log.error(error)

        if error:
            exn = PayloadInstallError(str(error))
            if errorHandler.cb(exn) == ERROR_RAISE:
                raise exn

        # Used to make install progress % look correct
        self._adj_size = os.stat(self.image_path)[stat.ST_SIZE]

        if self.data.method.checksum:
            progressQ.send_message(_("Checking image checksum"))
            sha256 = hashlib.sha256()
            with open(self.image_path, "rb") as f:
                while True:
                    data = f.read(1024*1024)
                    if not data:
                        break
                    sha256.update(data)
            filesum = sha256.hexdigest()
            log.debug("sha256 of %s is %s", self.data.method.url, filesum)

            if lowerASCII(self.data.method.checksum) != filesum:
                log.error("%s does not match checksum.", self.data.method.checksum)
                exn = PayloadInstallError("Checksum of image does not match")
                if errorHandler.cb(exn) == ERROR_RAISE:
                    raise exn

        # Mount the image and check to see if it is a LiveOS/*.img
        # style squashfs image. If so, move it to IMAGE_DIR and mount the real
        # root image on INSTALL_TREE
        blivet.util.mount(self.image_path, INSTALL_TREE, fstype="auto", options="ro")
        if os.path.exists(INSTALL_TREE+"/LiveOS"):
            # Find the first .img in the directory and mount that on INSTALL_TREE
            img_files = glob.glob(INSTALL_TREE+"/LiveOS/*.img")
            if img_files:
                img_file = os.path.basename(sorted(img_files)[0])

                # move the mount to IMAGE_DIR
                os.makedirs(IMAGE_DIR, 0755)
                # work around inability to move shared filesystems
                iutil.execWithRedirect("mount",
                                       ["--make-rprivate", "/"])
                iutil.execWithRedirect("mount",
                                       ["--move", INSTALL_TREE, IMAGE_DIR])
                blivet.util.mount(IMAGE_DIR+"/LiveOS/"+img_file, INSTALL_TREE,
                                  fstype="auto", options="ro")