[livemedia-creator] Add filesystem image install support
Brian C. Lane
bcl at redhat.com
Thu Feb 7 18:51:47 UTC 2013
From: "Brian C. Lane" <bcl at redhat.com>
This adds support for installing to a filesystem image instead of a
partitioned disk image. It requires Anaconda's --dirinstall support.
Also re-organized the code to break it up into smaller methods.
This speeds up iso creation in no-virt mode by removing the need to copy
the filesystem from the partitioned disk image to the filesystem image
that is used to make the squashfs image.
---
README.livemedia-creator | 44 ++--
src/sbin/livemedia-creator | 559 ++++++++++++++++++++++++++-------------------
2 files changed, 355 insertions(+), 248 deletions(-)
diff --git a/README.livemedia-creator b/README.livemedia-creator
index dee51b2..424bd24 100644
--- a/README.livemedia-creator
+++ b/README.livemedia-creator
@@ -2,7 +2,9 @@
INTRO
-----
livemedia-creator uses Anaconda, kickstart and Lorax to create bootable media
-such as live iso's that use the same install path as a normal system install.
+that use the same install path as a normal system install. It can be used to
+make live isos, bootable (partitioned) disk images and filesystem images for
+use with virtualization.
The general idea is to use virt-install to install into a disk image and then
use the disk image to create the bootable media.
@@ -18,12 +20,12 @@ minimum you need:
QUICKSTART
----------
sudo livemedia-creator --make-iso \
---iso=/extra/iso/Fedora-16-x86_64-netinst.iso --ks=./fedora-livemedia.ks
+--iso=/extra/iso/Fedora-18-x86_64-netinst.iso --ks=./docs/fedora-livemedia.ks
If you are using the lorax git repo you can run it like so:
sudo PATH=./src/sbin/:$PATH PYTHONPATH=./src/ ./src/sbin/livemedia-creator \
---make-iso --iso=/extra/iso/Fedora-16-x86_64-netinst.iso \
+--make-iso --iso=/extra/iso/Fedora-18-x86_64-netinst.iso \
--ks=./docs/fedora-livemedia.ks --lorax-templates=./share/
If you want to watch the install you can pass '--vnc vnc' and use a vnc
@@ -35,16 +37,17 @@ to monitor the logs for fatal errors, but may not catch everything.
HOW IT WORKS
------------
-The --make-* switches define the final output.
-
-You then need to either pass --iso and --ks in order to create a disk image
-using virt-install, or --disk-image to use a disk image from a previous run
-to create the .iso
-
-virt-install boots using the passed Anaconda installer iso and installs the
-system based on the kickstart. The %post section of the kickstart is used to
-customize the installed system in the same way that current spin-kickstarts
-do.
+There are 2 stages, the install stage which produces a disk or filesystem
+image as its output, and the boot media creation which uses the image as
+its input. Normally you would have it run both stages, but it is possible
+to have it stop after the install stage, using --image-only, or to have it
+skip the install stage and use a previously created disk image by passing
+--disk-image or --fs-image
+
+When creating an iso virt-install boots using the passed Anaconda installer iso
+and installs the system based on the kickstart. The %post section of the
+kickstart is used to customize the installed system in the same way that
+current spin-kickstarts do.
livemedia-creator monitors the install process for problems by watching the
install logs. They are written to the current directory or to the base
@@ -129,7 +132,7 @@ it as well.
ANACONDA IMAGE INSTALL
----------------------
You can create images without using virt-install by passing --no-virt on the
-cmdline. This will use Anaconda's image install feature to handle the install.
+cmdline. This will use Anaconda's directory install feature to handle the install.
There are a couple of things to keep in mind when doing this:
1. It will be most reliable when building images for the same release that the
@@ -168,10 +171,11 @@ This will produce an ami-root.img file in the working directory.
At this time I have not tested the image with EC2. Feedback would we welcome.
-APPLIANCE CREATION ------------------ livemedia-creator can now replace
-appliance-tools by using the --make-appliance switch. This will create the
-partitioned disk image and an XML file that can be used with virt-image to
-setup a virtual system.
+APPLIANCE CREATION
+------------------
+livemedia-creator can now replace appliance-tools by using the --make-appliance
+switch. This will create the partitioned disk image and an XML file that can be
+used with virt-image to setup a virtual system.
The XML is generated using the Mako template from
/usr/share/lorax/appliance/virt-image.xml You can use a different template by
@@ -218,7 +222,9 @@ disk image. Or you can pass --keep-image to keep it around after lorax is
run.
Cleaning up aborted --no-virt installs can sometimes be accomplished by running
-the anaconda-cleanup script.
+the anaconda-cleanup script. As of f18 anaconda is multi-threaded and it can
+sometimes become stuck and refuse to exit. When this happens you can usually
+clean up by first killing the anaconda process then running anaconda-cleanup.
HACKING
diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator
index f80ad00..202e963 100755
--- a/src/sbin/livemedia-creator
+++ b/src/sbin/livemedia-creator
@@ -2,7 +2,7 @@
#
# Live Media Creator
#
-# Copyright (C) 2011-2012 Red Hat, Inc.
+# Copyright (C) 2011-2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@ import threading
import SocketServer
from time import sleep
import shutil
-import traceback
import argparse
import hashlib
@@ -49,9 +48,10 @@ from mako.exceptions import text_error_template
# Use the Lorax treebuilder branch for iso creation
from pylorax.base import DataHolder
from pylorax.treebuilder import TreeBuilder, RuntimeBuilder, udev_escape
-from pylorax.sysutils import joinpaths, remove, linktree
+from pylorax.sysutils import joinpaths, remove
from pylorax.imgutils import PartitionMount, mksparse, mkext4img, loop_detach
-from pylorax.imgutils import get_loop_name, dm_detach
+from pylorax.imgutils import get_loop_name, dm_detach, mount, umount, Mount
+from pylorax.imgutils import mksquashfs
from pylorax.executils import execWithRedirect, execWithCapture
# no-virt mode doesn't need libvirt, so make it optional
@@ -64,6 +64,12 @@ except ImportError:
DRACUT_DEFAULT = ["--xz", "--add", "livenet dmsquash-live convertfs pollcdrom",
"--omit", "plymouth"]
+ROOT_PATH = "/mnt/sysimage/"
+RUNTIME = "images/install.img"
+
+class InstallError(Exception):
+ pass
+
class LogRequestHandler(SocketServer.BaseRequestHandler):
"""
@@ -184,11 +190,7 @@ class IsoMountpoint(object):
self.initrd_path = initrd_path
if not self.initrd_path:
- self.mount_dir = tempfile.mkdtemp()
- if not self.mount_dir:
- raise Exception("Error creating temporary directory")
-
- execWithRedirect("mount", ["-o", "loop", self.iso_path, self.mount_dir])
+ self.mount_dir = mount(self.iso_path, opts="loop")
else:
self.mount_dir = self.initrd_path
@@ -213,8 +215,7 @@ class IsoMountpoint(object):
def umount( self ):
if not self.initrd_path:
- execWithRedirect("umount", [self.mount_dir])
- os.rmdir( self.mount_dir )
+ umount(self.mount_dir)
def get_iso_label( self ):
"""
@@ -328,8 +329,8 @@ class VirtualInstall( object ):
Could use libvirt for this instead.
"""
log.info( "Shutting down {0}".format(self.virt_name) )
- subprocess.call(["virsh","destroy",self.virt_name])
- subprocess.call(["virsh","undefine",self.virt_name])
+ subprocess.call(["virsh", "destroy", self.virt_name])
+ subprocess.call(["virsh", "undefine", self.virt_name])
def is_image_mounted(disk_img):
"""
@@ -343,42 +344,37 @@ def is_image_mounted(disk_img):
return False
-def anaconda_install( disk_img, disk_size, kickstart, repo, args ):
+class KernelInfo(object):
"""
- disk_img Full path of the disk image
- disk_size Disk size in GB
- kickstart Full path to kickstart file
- repo URL of repository
- args Extra args to pass to anaconda --image install
+ Info about the kernels in boot_dir
"""
- import selinux
-
- # Set selinux to Permissive if it is Enforcing
- selinux_enforcing = False
- if selinux.is_selinux_enabled() and selinux.security_getenforce():
- selinux_enforcing = True
- selinux.security_setenforce(0)
-
- # Create the sparse image
- mksparse( disk_img, disk_size * 1024**3 )
-
- cmd = [ "anaconda", "--image", disk_img, "--kickstart", kickstart,
- "--cmdline", "--repo", repo_url ]
- cmd += args
-
- rc = execWithRedirect( cmd[0], cmd[1:] )
+ def __init__(self, boot_dir):
+ self.boot_dir = boot_dir
+ self.list = self.get_kernels()
+ self.arch = self.get_kernel_arch()
+ log.debug("kernel_list for {0.boot_dir} = {0.list}".format(self))
+ log.debug("kernel_arch is {0.arch}".format(self))
+
+ def get_kernels(self):
+ """
+ Get a list of the kernels in the boot_dir
- if selinux_enforcing:
- selinux.security_setenforce(1)
- return rc
+ Examine the vmlinuz-* versions and return a list of them
+ """
+ files = os.listdir(self.boot_dir)
+ return [f[8:] for f in files if f.startswith("vmlinuz-")]
+ def get_kernel_arch(self):
+ """
+ Get the arch of the first kernel in boot_dir
-def get_kernels( boot_dir ):
- """
- Examine the vmlinuz-* versions and return a list of them
- """
- files = os.listdir(boot_dir)
- return [f[8:] for f in files if f.startswith("vmlinuz-")]
+ Defaults to i386
+ """
+ if self.list:
+ kernel_arch = self.list[0].split(".")[-1]
+ else:
+ kernel_arch = "i386"
+ return kernel_arch
def make_appliance(disk_img, name, template, outfile, networks=None, ram=1024,
@@ -450,8 +446,32 @@ def make_ami( disk_img, ami_img="ami-root.img", ami_label="AMI" ):
return work_dir
-def make_livecd( disk_img, squashfs_args="", templatedir=None,
- title="Linux", project="Linux", releasever=16, isolabel=None ):
+def make_runtime(opts, mount_dir, work_dir):
+ """
+ Make the squashfs image from a directory
+
+ Result is in work_dir+RUNTIME
+ """
+ kernels = KernelInfo(joinpaths(mount_dir, "boot" ))
+
+ # Fake yum object
+ fake_yum = DataHolder(conf=DataHolder(installroot=mount_dir))
+ # Fake arch with only basearch set
+ arch = DataHolder(basearch=kernels.arch, libdir=None, buildarch=None)
+ # TODO: Need to get release info from someplace...
+ product = DataHolder(name=opts.project, version=opts.releasever, release="",
+ variant="", bugurl="", isfinal=False)
+
+ # This is a mounted image partition, cannot hardlink to it, so just use it
+ # symlink mount_dir/images to work_dir/images so we don't run out of space
+ os.makedirs(joinpaths(work_dir, "images"))
+
+ rb = RuntimeBuilder(product, arch, fake_yum)
+ log.info("Creating runtime")
+ rb.create_runtime(joinpaths(work_dir, RUNTIME), size=None)
+
+
+def make_livecd(opts, mount_dir, work_dir):
"""
Take the content from the disk image and make a livecd out of it
@@ -466,76 +486,195 @@ def make_livecd( disk_img, squashfs_args="", templatedir=None,
mounts that and then mounts LiveOS/rootfs.img as /
"""
- with PartitionMount( disk_img ) as img_mount:
- if not img_mount or not img_mount.mount_dir:
- return None
+ kernels = KernelInfo(joinpaths(mount_dir, "boot" ))
+
+ arch = DataHolder(basearch=kernels.arch, libdir=None, buildarch=None)
+ # TODO: Need to get release info from someplace...
+ product = DataHolder(name=opts.project, version=opts.releasever, release="",
+ variant="", bugurl="", isfinal=False)
+
+ # Link /images to work_dir/images to make the templates happy
+ if os.path.islink(joinpaths(mount_dir, "images")):
+ os.unlink(joinpaths(mount_dir, "images"))
+ execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"),
+ joinpaths(mount_dir, "images")])
+
+ # The templates expect the config files to be in /tmp/config_files
+ # I think these should be release specific, not from lorax, but for now
+ configdir = joinpaths(opts.lorax_templates,"live/config_files/")
+ configdir_path = "tmp/config_files"
+ fullpath = joinpaths(mount_dir, configdir_path)
+ if os.path.exists(fullpath):
+ remove(fullpath)
+ shutil.copytree(configdir, fullpath)
+
+ isolabel = opts.volid or "{0.name} {0.version} {1.basearch}".format(product, arch)
+ if len(isolabel) > 32:
+ isolabel = isolabel[:32]
+ log.warn("Truncating isolabel to 32 chars: %s" % (isolabel,))
+
+ tb = TreeBuilder(product=product, arch=arch,
+ inroot=mount_dir, outroot=work_dir,
+ runtime=RUNTIME, isolabel=isolabel,
+ templatedir=joinpaths(opts.lorax_templates,"live/"))
+ log.info( "Rebuilding initrds" )
+ if not opts.dracut_args:
+ dracut_args = DRACUT_DEFAULT
+ else:
+ dracut_args = []
+ for arg in opts.dracut_args:
+ dracut_args += arg.split(" ", 1)
+ log.info("dracut args = {0}".format(dracut_args))
+ tb.rebuild_initrds(add_args=dracut_args)
+ log.info("Building boot.iso")
+ tb.build()
- kernel_list = get_kernels( joinpaths( img_mount.mount_dir, "boot" ) )
- log.debug( "kernel_list = {0}".format(kernel_list) )
- if kernel_list:
- kernel_arch = kernel_list[0].split(".")[-1]
- else:
- kernel_arch = "i386"
- log.debug( "kernel_arch = {0}".format(kernel_arch) )
+ return work_dir
- work_dir = tempfile.mkdtemp()
- log.info( "working dir is {0}".format(work_dir) )
-
- runtime = "images/install.img"
- # This is a mounted image partition, cannot hardlink to it, so just use it
- installroot = img_mount.mount_dir
- # symlink installroot/images to work_dir/images so we don't run out of space
- os.makedirs( joinpaths( work_dir, "images" ) )
-
- # TreeBuilder expects the config files to be in /tmp/config_files
- # I think these should be release specific, not from lorax, but for now
- configdir = joinpaths(templatedir,"live/config_files/")
- configdir_path = "tmp/config_files"
- fullpath = joinpaths(installroot, configdir_path)
- if os.path.exists(fullpath):
- remove(fullpath)
- shutil.copytree(configdir, fullpath)
-
- # Fake yum object
- fake_yum = DataHolder( conf=DataHolder( installroot=installroot ) )
- # Fake arch with only basearch set
- arch = DataHolder( basearch=kernel_arch, libdir=None, buildarch=None )
- # TODO: Need to get release info from someplace...
- product = DataHolder( name=project, version=releasever, release="",
- variant="", bugurl="", isfinal=False )
-
- rb = RuntimeBuilder( product, arch, fake_yum )
- log.info( "Creating runtime" )
- rb.create_runtime( joinpaths( work_dir, runtime ), size=None )
-
- # Link /images to work_dir/images to make the templates happy
- if os.path.islink( joinpaths( installroot, "images" ) ):
- os.unlink( joinpaths( installroot, "images" ) )
- execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"),
- joinpaths(installroot, "images")])
-
- isolabel = isolabel or "{0.name} {0.version} {1.basearch}".format(product, arch)
- if len(isolabel) > 32:
- isolabel = isolabel[:32]
- log.error("Truncating isolabel to 32 chars: %s" % (isolabel,))
-
- tb = TreeBuilder( product=product, arch=arch,
- inroot=installroot, outroot=work_dir,
- runtime=runtime, isolabel=isolabel,
- templatedir=joinpaths(templatedir,"live/"))
- log.info( "Rebuilding initrds" )
- if not opts.dracut_args:
- dracut_args = DRACUT_DEFAULT
+
+def novirt_install(opts, disk_img, disk_size, repo_url):
+ """
+ Use Anaconda to install to a disk image
+ """
+ import selinux
+
+ # Set selinux to Permissive if it is Enforcing
+ selinux_enforcing = False
+ if selinux.is_selinux_enabled() and selinux.security_getenforce():
+ selinux_enforcing = True
+ selinux.security_setenforce(0)
+
+ cmd = ["anaconda", "--kickstart", opts.ks[0], "--cmdline", "--repo", repo_url]
+ if opts.anaconda_args:
+ for arg in opts.anaconda_args:
+ cmd += arg.split(" ", 1)
+ if opts.proxy:
+ cmd += ["--proxy", opts.proxy]
+ if opts.armplatform:
+ cmd += ["--armplatform", opts.armplatform]
+
+ if opts.make_iso or opts.make_fsimage:
+ # Make a blank fs image
+ cmd += ["--dirinstall"]
+
+ mkext4img(None, disk_img, label="Anaconda", size=disk_size * 1024**3)
+ if not os.path.isdir(ROOT_PATH):
+ os.mkdir(ROOT_PATH)
+ mount(disk_img, opts="loop", mnt=ROOT_PATH)
+ else:
+ cmd += ["--image", disk_img]
+
+ # Create the sparse image
+ mksparse( disk_img, disk_size * 1024**3 )
+
+ rc = execWithRedirect(cmd[0], cmd[1:])
+
+ # Move the anaconda logs over to a log directory
+ log_dir = os.path.abspath(os.path.dirname(opts.logfile))
+ log_anaconda = joinpaths(log_dir, "anaconda")
+ if not os.path.isdir(log_anaconda):
+ os.mkdir(log_anaconda)
+ for l in ["anaconda.log", "ifcfg.log", "program.log", "storage.log",
+ "packaging.log", "yum.log"]:
+ if os.path.exists("/tmp/"+l):
+ shutil.copy2("/tmp/"+l, log_anaconda)
+ os.unlink("/tmp/"+l)
+
+ if opts.make_iso or opts.make_fsimage:
+ umount(ROOT_PATH)
+ else:
+ # If anaconda failed the disk image may still be in use by dm
+ execWithRedirect("anaconda-cleanup", [])
+ dm_name = os.path.splitext(os.path.basename(disk_img))[0]
+ dm_path = "/dev/mapper/"+dm_name
+ if os.path.exists(dm_path):
+ dm_detach(dm_path)
+ loop_detach(get_loop_name(disk_img))
+
+ if selinux_enforcing:
+ selinux.security_setenforce(1)
+
+ if rc:
+ raise InstallError("novirt_install failed")
+
+
+def virt_install(opts, install_log, disk_img, disk_size):
+ """
+ Use virt-install to install to a disk image
+ """
+ iso_mount = IsoMountpoint(opts.iso, opts.location)
+ log_monitor = LogMonitor(install_log)
+
+ kernel_args = ""
+ if opts.kernel_args:
+ kernel_args += opts.kernel_args
+ if opts.proxy:
+ kernel_args += " proxy="+opts.proxy
+
+ virt = VirtualInstall(iso_mount, opts.ks, disk_img, disk_size,
+ kernel_args, opts.ram, opts.vnc, opts.arch,
+ log_check = log_monitor.server.log_check,
+ virtio_host = log_monitor.host,
+ virtio_port = log_monitor.port)
+ virt.destroy()
+ log_monitor.shutdown()
+ iso_mount.umount()
+
+ if log_monitor.server.log_check():
+ raise InstallError("virt_install failed")
+
+
+def make_squashfs(disk_img, work_dir, compression="xz"):
+ """
+ Take disk_img and put it into LiveOS/rootfs.img and squashfs this
+ tree into work_dir+RUNTIME
+ """
+ liveos_dir = joinpaths(work_dir, "runtime/LiveOS")
+ os.makedirs(liveos_dir)
+ os.makedirs(os.path.dirname(joinpaths(work_dir, RUNTIME)))
+ execWithRedirect("/bin/ln", [disk_img,
+ joinpaths(liveos_dir, "rootfs.img")])
+ mksquashfs(joinpaths(work_dir, "runtime"),
+ joinpaths(work_dir, RUNTIME), compression)
+ remove(joinpaths(work_dir, "runtime"))
+
+
+def make_image(opts, ks):
+ """
+ Install to an image
+
+ Use virt or anaconda to install to an image.
+
+ Returns the name of the image created.
+ """
+ disk_size = 1 + (sum([p.size for p in ks.handler.partition.partitions]) / 1024)
+ log.info("disk_size = {0}GB".format(disk_size))
+
+ repo_url = ks.handler.method.url
+
+ if opts.image_name:
+ disk_img = joinpaths(opts.tmp, opts.image_name)
+ else:
+ disk_img = tempfile.mktemp(prefix="disk", suffix=".img", dir=opts.tmp)
+ install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
+
+ log.info("disk_img = {0}".format(disk_img))
+ log.info("install_log = {0}".format(install_log))
+
+ try:
+ if opts.no_virt:
+ novirt_install(opts, disk_img, disk_size, repo_url)
else:
- dracut_args = []
- for arg in opts.dracut_args:
- dracut_args += arg.split(" ", 1)
- log.info( "dracut args = {0}".format( dracut_args ) )
- tb.rebuild_initrds( add_args=dracut_args )
- log.info( "Building boot.iso" )
- tb.build()
+ virt_install(opts, install_log, disk_img, disk_size)
+ except InstallError as e:
+ log.error("Install failed: {0}".format(e))
+ if not opts.keep_image:
+ log.info("Removing bad disk image")
+ os.unlink(disk_img)
+ raise
- return work_dir
+ log.info("Disk Image install successful")
+ return disk_img
def setup_logging(opts):
@@ -574,7 +713,9 @@ if __name__ == '__main__':
action.add_argument( "--make-iso", action="store_true",
help="Build a live iso" )
action.add_argument( "--make-disk", action="store_true",
- help="Build a disk image" )
+ help="Build a partitioned disk image" )
+ action.add_argument( "--make-fsimage", action="store_true",
+ help="Build a filesystem image" )
action.add_argument( "--make-appliance", action="store_true",
help="Build an appliance image and XML description" )
action.add_argument( "--make-ami", action="store_true",
@@ -584,13 +725,15 @@ if __name__ == '__main__':
help="Anaconda installation .iso path to use for virt-install" )
parser.add_argument( "--disk-image", type=os.path.abspath,
help="Path to disk image to use for creating final image" )
+ parser.add_argument( "--fs-image", type=os.path.abspath,
+ help="Path to filesystem image to use for creating final image" )
parser.add_argument( "--ks", action="append", type=os.path.abspath,
help="Kickstart file defining the install." )
parser.add_argument( "--image-name", default=None,
- help="Name of disk image to create. Default is a random name." )
+ help="Name of fs/disk image to create. Default is a random name." )
parser.add_argument( "--image-only", action="store_true",
- help="Exit after creating disk image." )
+ help="Exit after creating fs/disk image." )
parser.add_argument( "--keep-image", action="store_true",
help="Keep raw disk image after .iso creation" )
parser.add_argument( "--no-virt", action="store_true",
@@ -692,23 +835,30 @@ if __name__ == '__main__':
log.error( "The disk image {0} is missing.".format( opts.disk_image ) )
sys.exit( 1 )
- if not opts.no_virt and not opts.iso and not opts.disk_image:
+ if opts.fs_image and not os.path.exists( opts.fs_image ):
+ log.error( "The filesystem image {0} is missing.".format( opts.fs_image ) )
+ sys.exit( 1 )
+
+ is_install = not (opts.disk_image or opts.fs_image)
+ if is_install and not opts.no_virt and not opts.iso:
log.error( "virt-install needs an install iso." )
sys.exit( 1 )
if opts.volid and len(opts.volid) > 32:
- logger.fatal("the volume id cannot be longer than 32 characters")
+ log.fatal("the volume id cannot be longer than 32 characters")
sys.exit(1)
- if not opts.no_virt and not libvirt:
+ if is_install and not opts.no_virt and not libvirt:
log.error("virt-install requires libvirt-python to be installed.")
sys.exit(1)
- if not opts.no_virt and not os.path.exists("/usr/bin/virt-install"):
+ if is_install and not opts.no_virt \
+ and not os.path.exists("/usr/bin/virt-install"):
log.error("virt-install requires python-virtinst to be installed.")
sys.exit(1)
- if opts.no_virt and not os.path.exists("/usr/sbin/anaconda"):
+ if not is_install and opts.no_virt \
+ and not os.path.exists("/usr/sbin/anaconda"):
log.error("no-virt requires anaconda to be installed.")
sys.exit(1)
@@ -721,7 +871,7 @@ if __name__ == '__main__':
"exist".format(opts.app_template))
sys.exit(1)
- if opts.image_name and os.path.exists(joinpaths(opts.tmp,opts.image_name)):
+ if opts.image_name and os.path.exists(joinpaths(opts.tmp, opts.image_name)):
log.error("The disk image to be created should not exist.")
sys.exit(1)
@@ -737,123 +887,74 @@ if __name__ == '__main__':
ks = KickstartParser( ks_version, errorsAreFatal=False, missingIncludeIsFatal=False )
ks.readKickstart( opts.ks[0] )
- # Make the disk image
- if not opts.disk_image:
+ # Make the disk or filesystem image
+ if not opts.disk_image and not opts.fs_image:
if not opts.ks:
log.error("Image creation requires a kickstart file")
sys.exit(1)
- disk_size = 1 + (sum( [p.size for p in ks.handler.partition.partitions] ) / 1024)
- log.info( "disk_size = {0}GB".format(disk_size) )
-
+ errors = []
if ks.handler.method.method != "url":
- log.error( "Only url install method is currently supported. Please "
- "fix your kickstart file." )
- sys.exit( 1 )
- repo_url = ks.handler.method.url
- if ks.handler.displaymode.displayMode is not None:
- log.error("The kickstart must not set a display mode (text, cmdline, "
- "graphical), this will interfere with livemedia-creator.")
- sys.exit(1)
+ errors.append("Only url install method is currently supported. Please "
+ "fix your kickstart file." )
- if opts.image_name:
- disk_img = joinpaths(opts.tmp, opts.image_name)
- else:
- disk_img = tempfile.mktemp( prefix="disk", suffix=".img", dir=opts.tmp )
- install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
+ if ks.handler.displaymode.displayMode is not None:
+ errors.append("The kickstart must not set a display mode (text, cmdline, "
+ "graphical), this will interfere with livemedia-creator.")
- log.info( "disk_img = {0}".format(disk_img) )
- log.info( "install_log = {0}".format(install_log) )
+ if errors:
+ for e in errors:
+ log.error(e)
+ sys.exit(1)
- if opts.no_virt:
- anaconda_args = []
- if opts.anaconda_args:
- for arg in opts.anaconda_args:
- anaconda_args += arg.split(" ", 1)
- if opts.proxy:
- anaconda_args += [ "--proxy", opts.proxy ]
- if opts.armplatform:
- anaconda_args += [ "--armplatform", opts.armplatform ]
-
- # Use anaconda's image install
- install_error = anaconda_install( disk_img, disk_size, opts.ks[0],
- repo_url, anaconda_args )
-
- # Move the anaconda logs over to a log directory
- log_dir = os.path.abspath(os.path.dirname(opts.logfile))
- log_anaconda = joinpaths( log_dir, "anaconda" )
- if not os.path.isdir( log_anaconda ):
- os.mkdir( log_anaconda )
- for l in ["anaconda.log", "ifcfg.log", "program.log", "storage.log",
- "packaging.log", "yum.log"]:
- if os.path.exists( "/tmp/"+l ):
- shutil.copy2( "/tmp/"+l, log_anaconda )
- os.unlink( "/tmp/"+l )
-
- # If anaconda failed the disk image may still be in use by dm
- execWithRedirect("anaconda-cleanup", [])
- dm_name = os.path.splitext(os.path.basename(disk_img))[0]
- dm_path = "/dev/mapper/"+dm_name
- if os.path.exists(dm_path):
- dm_detach(dm_path)
- loop_detach(get_loop_name(disk_img))
+ # Make the image. Output of this is either a partitioned disk image or a fsimage
+ try:
+ disk_img = make_image(opts, ks)
+ except InstallError as e:
+ log.error("ERROR: Image creation failed: %s" % (e))
+ sys.exit(1)
- else:
- iso_mount = IsoMountpoint( opts.iso, opts.location )
- log_monitor = LogMonitor( install_log )
-
- kernel_args = ""
- if opts.kernel_args:
- kernel_args += opts.kernel_args
- if opts.proxy:
- kernel_args += " proxy="+opts.proxy
-
- virt = VirtualInstall( iso_mount, opts.ks, disk_img, disk_size,
- kernel_args, opts.ram, opts.vnc, opts.arch,
- log_check = log_monitor.server.log_check,
- virtio_host = log_monitor.host,
- virtio_port = log_monitor.port )
- virt.destroy()
- log_monitor.shutdown()
- iso_mount.umount()
-
- install_error = log_monitor.server.log_check()
-
- if install_error:
- log.error( "Install failed" )
- if not opts.keep_image:
- log.info( "Removing bad disk image" )
- os.unlink( disk_img )
- sys.exit( 1 )
- else:
- log.info( "Disk Image install successful" )
-
-
- result_dir = None
- if opts.make_iso and not opts.image_only:
- result_dir = make_livecd( opts.disk_image or disk_img, opts.squashfs_args,
- opts.lorax_templates,
- opts.title, opts.project, opts.releasever,
- opts.volid )
- # cleanup the mess
- if disk_img and not opts.keep_image and not opts.disk_image:
- os.unlink( disk_img )
- log.info("Disk image erased")
- disk_img = None
- elif opts.make_ami and not opts.image_only:
- result_dir = make_ami(opts.disk_image or disk_img)
- elif opts.make_appliance and not opts.image_only:
- if not opts.ks:
- networks = []
- else:
- networks = ks.handler.network.network
- make_appliance(opts.disk_image or disk_img, opts.app_name,
- opts.app_template, opts.app_file, networks, opts.ram,
- opts.vcpus, opts.arch, opts.title, opts.project, opts.releasever)
-
- if opts.result_dir and result_dir:
- shutil.copytree( result_dir, opts.result_dir )
- shutil.rmtree( result_dir )
+ if not opts.image_only:
+ result_dir = None
+ if opts.make_iso:
+ work_dir = tempfile.mkdtemp()
+ log.info("working dir is {0}".format(work_dir))
+
+ if (opts.fs_image or opts.no_virt) and not opts.disk_image:
+ # Create iso from a filesystem image
+ disk_img = opts.fs_image or disk_img
+
+ make_squashfs(disk_img, work_dir)
+ with Mount(disk_img, opts="loop") as mount_dir:
+ result_dir = make_livecd(opts, mount_dir, work_dir)
+ else:
+ # Create iso from a partitioned disk image
+ disk_img = opts.disk_image or disk_img
+ with PartitionMount(disk_img) as img_mount:
+ if img_mount and img_mount.mount_dir:
+ make_runtime(opts, img_mount.mount_dir, work_dir)
+ result_dir = make_livecd(opts, img_mount.mount_dir, work_dir)
+
+ # cleanup the mess
+ # cleanup work_dir?
+ if disk_img and not (opts.keep_image or opts.disk_image or opts.fs_image):
+ os.unlink(disk_img)
+ log.info("Disk image erased")
+ disk_img = None
+ elif opts.make_ami:
+ result_dir = make_ami(opts.disk_image or disk_img)
+ elif opts.make_appliance:
+ if not opts.ks:
+ networks = []
+ else:
+ networks = ks.handler.network.network
+ make_appliance(opts.disk_image or disk_img, opts.app_name,
+ opts.app_template, opts.app_file, networks, opts.ram,
+ opts.vcpus, opts.arch, opts.title, opts.project, opts.releasever)
+
+ if opts.result_dir and result_dir:
+ shutil.copytree( result_dir, opts.result_dir )
+ shutil.rmtree( result_dir )
log.info("SUMMARY")
log.info("-------")
--
1.8.1
More information about the anaconda-patches
mailing list