Add no-virt mode to livemedia-creator

This runs anaconda directly, using the --image install feature. The host
system should be the same release as the target system in order to avoid
unexpected problems.
This commit is contained in:
Brian C. Lane 2011-12-08 17:12:06 -08:00
parent bfe5ce2813
commit 7149adee25
2 changed files with 127 additions and 36 deletions

View File

@ -36,7 +36,7 @@ to monitor the logs for fatal errors, but may not catch everything.
HOW IT WORKS HOW IT WORKS
------------ ------------
The --make-* switches define the final output. Currently only --make-iso The --make-* switches define the final output. Currently only --make-iso
is working. and --make-disk are working.
You then need to either pass --iso and --ks in order to create a disk image 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 using virt-install, or --disk-image to use a disk image from a previous run
@ -127,6 +127,33 @@ You can also add an update repo, but don't name it updates. Add --proxy to
it as well. 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.
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
host is running. Because Anaconda has expectations about the system it is
running under you may encounter strange bugs if you try to build newer or
older releases.
2. Make sure selinux is set to permissive or disabled. It won't install
correctly with selinux set to enforcing yet.
3. It may totally trash your host. So far I haven't had this happen, but the
possibility exists that a bug in Anaconda could result in it operating on
real devices. I recommend running it in a virt or on a system that you can
afford to lose all data from.
The logs from anaconda will be placed in an ./anaconda/ directory in either
the current directory or in the directory used for --logfile
Example cmdline:
sudo livemedia-creator --make-iso --no-virt --ks=./fedora-livemedia.ks
DEBUGGING PROBLEMS DEBUGGING PROBLEMS
------------------ ------------------
Cleaning up an aborted (ctrl-c) virt-install run (as root): Cleaning up an aborted (ctrl-c) virt-install run (as root):
@ -144,6 +171,9 @@ You can add --image-only to skip the .iso creation and examine the resulting
disk image. Or you can pass --keep-image to keep it around after lorax is disk image. Or you can pass --keep-image to keep it around after lorax is
run. run.
Cleaning up aborted --no-virt installs can sometimes be accomplished by running
the anaconda-cleanup script.
THE FUTURE THE FUTURE
---------- ----------

View File

@ -2,7 +2,7 @@
# #
# Live Media Creator # Live Media Creator
# #
# Copyright (C) 2009 Red Hat, Inc. # Copyright (C) 2011 Red Hat, Inc.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -46,12 +46,13 @@ from pykickstart.version import makeVersion
from pylorax.base import DataHolder from pylorax.base import DataHolder
from pylorax.treebuilder import TreeBuilder, RuntimeBuilder from pylorax.treebuilder import TreeBuilder, RuntimeBuilder
from pylorax.sysutils import joinpaths, remove, linktree from pylorax.sysutils import joinpaths, remove, linktree
from pylorax.imgutils import PartitionMount from pylorax.imgutils import PartitionMount, mksparse
from pylorax.executils import execWithRedirect, execWithCapture from pylorax.executils import execWithRedirect, execWithCapture
# Default parameters for rebuilding initramfs, overrice with --dracut-args # Default parameters for rebuilding initramfs, overrice with --dracut-args
DRACUT_DEFAULT = ["--xz", "--omit", "plymouth"] DRACUT_DEFAULT = ["--xz", "--add", "livenet", "--add", "dmsquash-live",
"--omit", "plymouth"]
class LogRequestHandler(SocketServer.BaseRequestHandler): class LogRequestHandler(SocketServer.BaseRequestHandler):
@ -106,11 +107,14 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
""" """
Check a line to see if it contains an error indicating install failure Check a line to see if it contains an error indicating install failure
""" """
if line.find("Traceback (") > -1 \ simple_tests = [ "Traceback (",
or line.find("Out of memory:") > -1 \ "Out of memory:",
or line.find("Call Trace:") > -1 \ "Call Trace:",
or line.find("insufficient disk space:") > -1: "insufficient disk space:" ]
self.server.log_error = True for t in simple_tests:
if line.find( t ) > -1:
self.server.log_error = True
return
class LogServer(SocketServer.TCPServer): class LogServer(SocketServer.TCPServer):
@ -343,6 +347,22 @@ class VirtualInstall( object ):
subprocess.call(["virsh","undefine",self.virt_name]) subprocess.call(["virsh","undefine",self.virt_name])
def anaconda_install( disk_img, disk_size, kickstart, repo, args ):
"""
"""
# Create the sparse image
mksparse( disk_img, disk_size * 1024**3 )
cmd = [ "anaconda", "--image", disk_img, "--kickstart", kickstart,
"--script", "--repo", repo_url ]
cmd += args
log.debug( cmd )
return execWithRedirect( cmd[0], cmd[1:] )
def get_kernels( boot_dir ): def get_kernels( boot_dir ):
""" """
Examine the vmlinuz-* versions and return a list of them Examine the vmlinuz-* versions and return a list of them
@ -434,7 +454,7 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser( description="Create Live Install Media", parser = argparse.ArgumentParser( description="Create Live Install Media",
fromfile_prefix_chars="@" ) fromfile_prefix_chars="@" )
# These two are mutually exclusive, one is required # These are mutually exclusive, one is required
action = parser.add_mutually_exclusive_group( required=True ) action = parser.add_mutually_exclusive_group( required=True )
action.add_argument( "--make-iso", action="store_true", action.add_argument( "--make-iso", action="store_true",
help="Build a live iso" ) help="Build a live iso" )
@ -445,10 +465,9 @@ if __name__ == '__main__':
action.add_argument( "--make-ami", action="store_true", action.add_argument( "--make-ami", action="store_true",
help="Build an ami image" ) help="Build an ami image" )
source = parser.add_mutually_exclusive_group( required=True ) parser.add_argument( "--iso", type=os.path.abspath,
source.add_argument( "--iso", type=os.path.abspath,
help="Anaconda installation .iso path to use for virt-install" ) help="Anaconda installation .iso path to use for virt-install" )
source.add_argument( "--disk-image", type=os.path.abspath, parser.add_argument( "--disk-image", type=os.path.abspath,
help="Path to disk image to use for creating final image" ) help="Path to disk image to use for creating final image" )
parser.add_argument( "--ks", action="append", type=os.path.abspath, parser.add_argument( "--ks", action="append", type=os.path.abspath,
@ -459,6 +478,11 @@ if __name__ == '__main__':
help="Keep raw disk image after .iso creation" ) help="Keep raw disk image after .iso creation" )
parser.add_argument( "--no-virt", action="store_true", parser.add_argument( "--no-virt", action="store_true",
help="Use Anaconda's image install instead of virt-install" ) help="Use Anaconda's image install instead of virt-install" )
parser.add_argument( "--proxy",
help="proxy URL to use for the install" )
parser.add_argument( "--anaconda-arg", action="append", dest="anaconda_args",
help="Additional argument to pass to anaconda (no-virt "
"mode). Pass once for each argument" )
parser.add_argument( "--logfile", default="./livemedia.log", parser.add_argument( "--logfile", default="./livemedia.log",
type=os.path.abspath, type=os.path.abspath,
@ -551,10 +575,6 @@ if __name__ == '__main__':
log.error( "The disk image {0} is missing.".format( opts.disk_image ) ) log.error( "The disk image {0} is missing.".format( opts.disk_image ) )
sys.exit( 1 ) sys.exit( 1 )
if opts.no_virt:
log.error( "--no-virt is not yet implemented." )
sys.exit( 1 )
if opts.make_appliance: if opts.make_appliance:
log.error( "--make-appliance is not yet implemented." ) log.error( "--make-appliance is not yet implemented." )
sys.exit( 1 ) sys.exit( 1 )
@ -563,14 +583,12 @@ if __name__ == '__main__':
log.error( "--make-ami is not yet implemented." ) log.error( "--make-ami is not yet implemented." )
sys.exit( 1 ) sys.exit( 1 )
# Use virt-install to make the disk image if not opts.no_virt and not opts.iso and not opts.disk_image:
if opts.iso: log.error( "virt-install needs an install iso." )
disk_img = tempfile.mktemp( prefix="disk", suffix=".img", dir=opts.tmp ) sys.exit( 1 )
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) )
# Make the disk image
if not opts.disk_image:
# Parse the kickstart to get the partition sizes # Parse the kickstart to get the partition sizes
ks_version = makeVersion() ks_version = makeVersion()
ks = KickstartParser( ks_version, errorsAreFatal=False, missingIncludeIsFatal=False ) ks = KickstartParser( ks_version, errorsAreFatal=False, missingIncludeIsFatal=False )
@ -578,19 +596,62 @@ if __name__ == '__main__':
disk_size = 1 + (sum( [p.size for p in ks.handler.partition.partitions] ) / 1024) disk_size = 1 + (sum( [p.size for p in ks.handler.partition.partitions] ) / 1024)
log.info( "disk_size = {0}GB".format(disk_size) ) log.info( "disk_size = {0}GB".format(disk_size) )
iso_mount = IsoMountpoint( opts.iso ) if ks.handler.method.method != "url":
log_monitor = LogMonitor( install_log ) log.error( "Only url install method is currently supported. Please "
"fix your kickstart file." )
sys.exit( 1 )
repo_url = ks.handler.method.url
virt = VirtualInstall( iso_mount, opts.ks, disk_img, disk_size, disk_img = tempfile.mktemp( prefix="disk", suffix=".img", dir=opts.tmp )
opts.kernel_args, opts.ram, opts.vnc, install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
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(): log.info( "disk_img = {0}".format(disk_img) )
log.info( "install_log = {0}".format(install_log) )
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 ]
# 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",
"yum.log"]:
if os.path.exists( "/tmp/"+l ):
shutil.copy2( "/tmp/"+l, log_anaconda )
os.unlink( "/tmp/"+l )
else:
iso_mount = IsoMountpoint( opts.iso )
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,
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" ) log.error( "Install failed" )
if not opts.keep_image: if not opts.keep_image:
log.info( "Removing bad disk image" ) log.info( "Removing bad disk image" )
@ -616,7 +677,7 @@ if __name__ == '__main__':
log.info("SUMMARY") log.info("SUMMARY")
log.info("-------") log.info("-------")
log.info("Logs are in {0}".format(os.path.abspath(os.path.dirname(opts.logfile)))) log.info("Logs are in {0}".format(os.path.abspath(os.path.dirname(opts.logfile))))
if opts.keep_image: if opts.keep_image or opts.make_disk:
log.info("Disk image is at {0}".format(disk_img)) log.info("Disk image is at {0}".format(disk_img))
else: else:
log.info("Disk image erased") log.info("Disk image erased")