python-virtinst

changeset 1258:74bc3757b247

Add --initrd-inject option

For automating Fedora installations using Kickstart, a neat trick is
to put the kickstart file into the initrd. Then there's no need
to have a separate webserver or NFS mount just so anaconda can
retrieve the file.

Example usage:

virt-install --initrd-injections=/path/to/my.ks -x "ks=file:/my.ks" ...

This functionality really needs to be in virt-install because it's
the code which is downloading and then consuming the initrd.
An open question is whether it makes sense to have higher level
options like:

--kickstart=/path/to/my.ks

which would imply both of the above options. This would be
Anaconda-specific however.
author Colin Walters <walters@verbum.org>
date Mon Apr 26 12:02:36 2010 -0400 (2010-04-26)
parents a75a22e5781f
children 1d3ad914004f
files man/en/virt-install.1 man/en/virt-install.pod.in virt-install virtinst/DistroInstaller.py virtinst/Installer.py
line diff
     1.1 --- a/man/en/virt-install.1	Mon Apr 26 12:01:06 2010 -0400
     1.2 +++ b/man/en/virt-install.1	Mon Apr 26 12:02:36 2010 -0400
     1.3 @@ -132,7 +132,7 @@
     1.4  .\" ========================================================================
     1.5  .\"
     1.6  .IX Title "VIRT-INSTALL 1"
     1.7 -.TH VIRT-INSTALL 1 "2010-03-24" "" "Virtual Machine Install Tools"
     1.8 +.TH VIRT-INSTALL 1 "2010-04-26" "" "Virtual Machine Install Tools"
     1.9  .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
    1.10  .\" way too many mistakes in technical documents.
    1.11  .if n .ad l
    1.12 @@ -302,6 +302,13 @@
    1.13  .IX Item "-x EXTRA, --extra-args=EXTRA"
    1.14  Additional kernel command line arguments to pass to the installer when
    1.15  performing a guest install from \f(CW\*(C`\-\-location\*(C'\fR.
    1.16 +.IP "\-\-initrd\-inject=PATH" 2
    1.17 +.IX Item "--initrd-inject=PATH"
    1.18 +Add \s-1PATH\s0 to the root of the initrd fetched with \f(CW\*(C`\-\-location\*(C'\fR. This can be
    1.19 +used to run an automated install without requiring a network hosted kickstart
    1.20 +file:
    1.21 +.Sp
    1.22 +\&\-\-initrd\-injections=/path/to/my.ks \-\-extra\-args \*(L"ks=file:/my.ks\*(R"
    1.23  .IP "\-\-os\-type=OS_TYPE" 2
    1.24  .IX Item "--os-type=OS_TYPE"
    1.25  Optimize the guest configuration for a type of operating system (ex. 'linux',
     2.1 --- a/man/en/virt-install.pod.in	Mon Apr 26 12:01:06 2010 -0400
     2.2 +++ b/man/en/virt-install.pod.in	Mon Apr 26 12:02:36 2010 -0400
     2.3 @@ -212,6 +212,14 @@
     2.4  Additional kernel command line arguments to pass to the installer when
     2.5  performing a guest install from C<--location>.
     2.6  
     2.7 +=item  --initrd-inject=PATH
     2.8 +
     2.9 +Add PATH to the root of the initrd fetched with C<--location>. This can be
    2.10 +used to run an automated install without requiring a network hosted kickstart
    2.11 +file:
    2.12 +
    2.13 +--initrd-injections=/path/to/my.ks --extra-args "ks=file:/my.ks"
    2.14 +
    2.15  =item  --os-type=OS_TYPE
    2.16  
    2.17  Optimize the guest configuration for a type of operating system (ex. 'linux',
     3.1 --- a/virt-install	Mon Apr 26 12:01:06 2010 -0400
     3.2 +++ b/virt-install	Mon Apr 26 12:02:36 2010 -0400
     3.3 @@ -611,6 +611,10 @@
     3.4                      default="",
     3.5                      help=_("Additional arguments to pass to the kernel "
     3.6                             "booted from --location"))
     3.7 +    insg.add_option("", "--initrd-inject", type="string",
     3.8 +                    dest="initrd_injections", action="callback",
     3.9 +                    callback=cli.check_before_append,
    3.10 +                    help=_("Add given file to root of initrd from --location"))
    3.11      insg.add_option("", "--os-type", type="string", dest="distro_type",
    3.12                      action="callback", callback=cli.check_before_store,
    3.13                      help=_("The OS type being installed, e.g. "
    3.14 @@ -808,9 +812,10 @@
    3.15          instclass = virtinst.ImportInstaller
    3.16      else:
    3.17          instclass = virtinst.DistroInstaller
    3.18 +
    3.19      installer = instclass(type=hv_name, os_type=virt_type, conn=conn)
    3.20      installer.arch = capsguest.arch
    3.21 -
    3.22 +    installer.initrd_injections = options.initrd_injections
    3.23  
    3.24      # Get Guest instance from installer parameters.
    3.25      guest = installer.guest_from_installer()
     4.1 --- a/virtinst/DistroInstaller.py	Mon Apr 26 12:01:06 2010 -0400
     4.2 +++ b/virtinst/DistroInstaller.py	Mon Apr 26 12:02:36 2010 -0400
     4.3 @@ -19,6 +19,10 @@
     4.4  
     4.5  import logging
     4.6  import os
     4.7 +import sys
     4.8 +import shutil
     4.9 +import subprocess
    4.10 +import tempfile
    4.11  
    4.12  import _util
    4.13  import Installer
    4.14 @@ -177,6 +181,45 @@
    4.15                                           readOnly=True,
    4.16                                           transient=True)
    4.17  
    4.18 +    def _perform_initrd_injections(self):
    4.19 +        """
    4.20 +        Insert files into the root directory of the initial ram disk
    4.21 +        """
    4.22 +        logging.debug("Unpacking initrd.")
    4.23 +        tempdir = tempfile.mkdtemp(dir=self.scratchdir)
    4.24 +        os.chmod(tempdir, 0775)
    4.25 +
    4.26 +        gzip_proc = subprocess.Popen(['gzip', '-dc', self.install["initrd"]],
    4.27 +                                     stdout=subprocess.PIPE, stderr=sys.stderr)
    4.28 +        cpio_proc = subprocess.Popen(['cpio', '-i', '-d', '--quiet'],
    4.29 +                                     stdin=gzip_proc.stdout,
    4.30 +                                     stderr=sys.stderr, cwd=tempdir)
    4.31 +        cpio_proc.wait()
    4.32 +        gzip_proc.wait()
    4.33 +
    4.34 +        for filename in self._initrd_injections:
    4.35 +            logging.debug("Copying %s to the initrd." % filename)
    4.36 +            shutil.copy(filename, tempdir)
    4.37 +
    4.38 +        logging.debug("Repacking the initrd.")
    4.39 +        find_proc = subprocess.Popen(['find', '.', '-print0'],
    4.40 +                                     stdout=subprocess.PIPE,
    4.41 +                                     stderr=sys.stderr, cwd=tempdir)
    4.42 +        cpio_proc = subprocess.Popen(['cpio', '-o', '--null', '-c', '--quiet'],
    4.43 +                                     stdin=find_proc.stdout,
    4.44 +                                     stdout=subprocess.PIPE,
    4.45 +                                     stderr=sys.stderr, cwd=tempdir)
    4.46 +        new_initrd = self.install["initrd"] + '.new'
    4.47 +        f = open(new_initrd, 'w')
    4.48 +        gzip_proc = subprocess.Popen(['gzip'], stdin=cpio_proc.stdout,
    4.49 +                                     stdout=f, stderr=sys.stderr)
    4.50 +        f.close()
    4.51 +        cpio_proc.wait()
    4.52 +        find_proc.wait()
    4.53 +        gzip_proc.wait()
    4.54 +        os.rename(new_initrd, self.install["initrd"])
    4.55 +        shutil.rmtree(tempdir)
    4.56 +
    4.57      def _prepare_kernel_and_initrd(self, guest, distro, meter):
    4.58          if self.boot is not None:
    4.59              # Got a local kernel/initrd already
    4.60 @@ -211,6 +254,9 @@
    4.61              if initrdfn:
    4.62                  self._tmpfiles.append(initrdfn)
    4.63  
    4.64 +            if self._initrd_injections:
    4.65 +                self._perform_initrd_injections()
    4.66 +
    4.67          # If they're installing off a local file/device, we map it
    4.68          # through to a virtual CD or disk
    4.69          if (self.location is not None and self._location_is_path
     5.1 --- a/virtinst/Installer.py	Mon Apr 26 12:01:06 2010 -0400
     5.2 +++ b/virtinst/Installer.py	Mon Apr 26 12:02:36 2010 -0400
     5.3 @@ -81,6 +81,7 @@
     5.4                   extraargs = None, os_type = None, conn = None):
     5.5          self._type = None
     5.6          self._location = None
     5.7 +        self._initrd_injections = []
     5.8          self._extraargs = None
     5.9          self._boot = None
    5.10          self._cdrom = False
    5.11 @@ -176,6 +177,12 @@
    5.12          self._location = val
    5.13      location = property(get_location, set_location)
    5.14  
    5.15 +    def get_initrd_injections(self):
    5.16 +        return self._initrd_injections
    5.17 +    def set_initrd_injections(self, val):
    5.18 +        self._initrd_injections = val
    5.19 +    initrd_injections = property(get_initrd_injections, set_initrd_injections)
    5.20 +
    5.21      # kernel + initrd pair to use for installing as opposed to using a location
    5.22      def get_boot(self):
    5.23          return self._boot