[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