[master] Add support for tarfiles to liveimg kickstart command

Vratislav Podzimek vpodzime at redhat.com
Tue Mar 25 08:03:32 UTC 2014


On Mon, 2014-03-24 at 09:06 -0700, Brian C. Lane wrote:
> With these changes you can now pass the url of a tarfile to liveimg and
> it will install it to the target system. The same rules apply, the
> correct utilities need to be included in the tar for the configuration
> to work correctly.
> 
> The following extensions are recognized as tarfiles:
> 
> .tar .tbz .tgz .txz .tar.bz2 .tar.gz .tar.xz
> ---
>  pyanaconda/constants.py             |  3 ++
>  pyanaconda/packaging/livepayload.py | 99 ++++++++++++++++++++++++++++---------
>  2 files changed, 79 insertions(+), 23 deletions(-)
> 
> diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
> index 8de29a9..8f001f7 100644
> --- a/pyanaconda/constants.py
> +++ b/pyanaconda/constants.py
> @@ -151,3 +151,6 @@ FIRSTBOOT_ENVIRON = "firstboot"
>  
>  # Tainted hardware
>  UNSUPPORTED_HW = 1 << 28
> +
> +# Recognizing a tarfile
> +TAR_SUFFIX = (".tar", ".tbz", ".tgz", ".txz", ".tar.bz2", "tar.gz", "tar.xz")
> diff --git a/pyanaconda/packaging/livepayload.py b/pyanaconda/packaging/livepayload.py
> index 48c154f..795a4ef 100644
> --- a/pyanaconda/packaging/livepayload.py
> +++ b/pyanaconda/packaging/livepayload.py
> @@ -43,7 +43,7 @@ import glob
>  from . import ImagePayload, PayloadSetupError, PayloadInstallError
>  
>  from pyanaconda.constants import INSTALL_TREE, ROOT_PATH, THREAD_LIVE_PROGRESS
> -from pyanaconda.constants import IMAGE_DIR
> +from pyanaconda.constants import IMAGE_DIR, TAR_SUFFIX
>  
>  from pyanaconda import iutil
>  
> @@ -75,6 +75,9 @@ class LiveImagePayload(ImagePayload):
>                  raise exn
>          blivet.util.mount(osimg.path, INSTALL_TREE, fstype="auto", options="ro")
>  
> +        source = os.statvfs(INSTALL_TREE)
> +        self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
> +
>      def preInstall(self, packages=None, groups=None):
>          """ Perform pre-installation tasks. """
>          super(LiveImagePayload, self).preInstall(packages=packages, groups=groups)
> @@ -84,8 +87,6 @@ class LiveImagePayload(ImagePayload):
>          """Monitor the amount of disk space used on the target and source and
>             update the hub's progress bar.
>          """
> -        source = os.statvfs(INSTALL_TREE)
> -        source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
>          mountpoints = self.storage.mountpoints.copy()
>          last_pct = -1
>          while self.pct < 100:
> @@ -96,7 +97,7 @@ class LiveImagePayload(ImagePayload):
>              if dest_size >= self._adj_size:
>                  dest_size -= self._adj_size
>  
> -            pct = int(100 * dest_size / source_size)
> +            pct = int(100 * dest_size / self.source_size)
>              if pct != last_pct:
>                  with self.pct_lock:
>                      self.pct = pct
> @@ -312,25 +313,77 @@ class LiveImageKSPayload(LiveImagePayload):
>                  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")
> +        # If this looks like a tarfile, skip trying to mount it
> +        if not any(self.data.method.url.endswith(suffix) for suffix in TAR_SUFFIX):
What about definining a 'using_tar' property and using it here and in
the install method?

> +            # 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")
> +
> +                    source = os.statvfs(INSTALL_TREE)
> +                    self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
> +
> +    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 any(self.data.method.url.endswith(suffix) for suffix in TAR_SUFFIX):
> +            super(LiveImageKSPayload, self).install()
> +            return
> +
> +        # Use the archive's size for want of something better
> +        self.source_size = os.stat(self.image_path)[stat.ST_SIZE] * 2
Why is the ST_SIZE doubled? If it's intentional, it deserves a comment.

> +
> +        self.pct_lock = Lock()
> +        self.pct = 0
> +        threadMgr.add(AnacondaThread(name=THREAD_LIVE_PROGRESS,
> +                                     target=self.progress))
> +
> +        cmd = "tar"
> +        # preserve: permissions, owners, groups, ACL's, xattrs, times,
> +        #           symlinks, hardlinks
> +        # go recursively, include devices and special files, don't cross
> +        # file system boundaries
This comment needs a minor update when used here with tar instead of
rsync in the live install payload, I think.

> +        args = ["--selinux", "--acls", "--xattrs",
> +                "--exclude", "/dev/", "--exclude", "/proc/",
> +                "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*",
> +                "--exclude", "/etc/machine-id", "-xaf", self.image_path, "-C", 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:
> +            exn = PayloadInstallError(err or msg)
> +            if errorHandler.cb(exn) == ERROR_RAISE:
> +                raise exn
> +
> +        # Wait for progress thread to finish
> +        with self.pct_lock:
> +            self.pct = 100
> +        threadMgr.wait(THREAD_LIVE_PROGRESS)
>  
>      def postInstall(self):
>          """ Unmount image, remove image file from target
If you want to make these installations a lot faster, you can use
pbzcat/xzcat -T/pigz with their output piped into the tar itself.
However, that could be something extra for a follow-up patch.

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list