Add options; generate virtimage file (in progress)

This commit is contained in:
Bob Lantz
2013-09-11 12:00:17 -07:00
committed by Brian O'Connor
parent 1ea9d7d4de
commit d4279559fa
+62 -30
View File
@@ -30,7 +30,8 @@ import os
from os import stat, path from os import stat, path
from stat import ST_MODE from stat import ST_MODE
from os.path import abspath from os.path import abspath
from sys import exit, argv from sys import exit, stdout
import re
from glob import glob from glob import glob
from subprocess import check_output, call, Popen from subprocess import check_output, call, Popen
from tempfile import mkdtemp from tempfile import mkdtemp
@@ -42,6 +43,10 @@ pexpect = None # For code check - imported dynamically
# boot can be slooooow!!!! need to debug/optimize somehow # boot can be slooooow!!!! need to debug/optimize somehow
TIMEOUT=600 TIMEOUT=600
# Some configuration
LogToConsole = False # VM output to console rather than log file
SaveQCOW2 = False # Save QCOW2 image rather than deleting it
VMImageDir = os.environ[ 'HOME' ] + '/vm-images' VMImageDir = os.environ[ 'HOME' ] + '/vm-images'
isoURLs = { isoURLs = {
@@ -307,22 +312,22 @@ def makeKickstartFloppy():
return floppy, kickstart, preseed return floppy, kickstart, preseed
def kvmFor( filepath ): def archFor( filepath ):
"Guess kvm version for file path" "Guess architecture for file path"
name = path.basename( filepath ) name = path.basename( filepath )
if '64' in name: if '64' in name:
kvm = 'qemu-system-x86_64' arch = 'x86_64'
elif 'i386' in name or '32' in name: elif 'i386' in name or '32' in name:
kvm = 'qemu-system-i386' arch = 'i386'
else: else:
log( "Error: can't discern CPU for file name", name ) log( "Error: can't discern CPU for file name", name )
exit( 1 ) exit( 1 )
return kvm return arch
def installUbuntu( iso, image, logfilename='install.log' ): def installUbuntu( iso, image, logfilename='install.log' ):
"Install Ubuntu from iso onto image" "Install Ubuntu from iso onto image"
kvm = kvmFor( iso ) kvm = 'qemu-system-' + archFor( iso )
floppy, kickstart, preseed = makeKickstartFloppy() floppy, kickstart, preseed = makeKickstartFloppy()
# Mount iso so we can use its kernel # Mount iso so we can use its kernel
mnt = mkdtemp() mnt = mkdtemp()
@@ -349,10 +354,14 @@ def installUbuntu( iso, image, logfilename='install.log' ):
log( '* INSTALLING UBUNTU FROM', iso, 'ONTO', image ) log( '* INSTALLING UBUNTU FROM', iso, 'ONTO', image )
log( ' '.join( cmd ) ) log( ' '.join( cmd ) )
log( '* logging to', abspath( logfilename ) ) log( '* logging to', abspath( logfilename ) )
params = {}
if not LogToConsole:
logfile = open( logfilename, 'w' ) logfile = open( logfilename, 'w' )
vm = Popen( cmd, stdout=logfile, stderr=logfile ) params = { 'stdout': logfile, 'stderr': logfile }
vm = Popen( cmd, **params )
log( '* Waiting for installation to complete') log( '* Waiting for installation to complete')
vm.wait() vm.wait()
if not LogToConsole:
logfile.close() logfile.close()
elapsed = time() - ubuntuStart elapsed = time() - ubuntuStart
# Unmount iso and clean up # Unmount iso and clean up
@@ -374,8 +383,8 @@ def boot( cow, kernel, initrd, logfile ):
# pexpect might not be installed until after depend() is called # pexpect might not be installed until after depend() is called
global pexpect global pexpect
import pexpect import pexpect
kvm = kvmFor( kernel ) arch = archFor( kernel )
cmd = [ 'sudo', kvm, cmd = [ 'sudo', 'qemu-system-' + arch,
'-machine accel=kvm', '-machine accel=kvm',
'-nographic', '-nographic',
'-netdev user,id=mnbuild', '-netdev user,id=mnbuild',
@@ -478,7 +487,7 @@ VirtImageXML = """
<domain> <domain>
<boot type="hvm"> <boot type="hvm">
<guest> <guest>
<arch>%s/arch> <arch>%s<arch>
</guest> </guest>
<os> <os>
<loader dev="hd"/> <loader dev="hd"/>
@@ -498,20 +507,30 @@ VirtImageXML = """
</image> </image>
""" """
def genVirtImage( name, mem, diskname, disksize ): def genVirtImage( name, mem, diskname, disksize ):
"Generate and return virt-image file name.xml" "Generate and return virt-image file name.xml"
# Our strategy is going to be: create a # Our strategy is going to be: create a
# virt-image file and then use virt-convert to convert # virt-image file and then use virt-convert to convert
# it to an .ovf file # it to an .ovf file
xmlfile = name + '.xml' xmlfile = name + '.xml'
xmltext = VirtImageXML % ( name, mem, diskname, disksize ) arch = archFor( name )
xmltext = VirtImageXML % ( name, arch, mem, diskname, disksize )
with open( xmlfile, 'w+' ) as f: with open( xmlfile, 'w+' ) as f:
f.write( xmltext ) f.write( xmltext )
return xmlfile return xmlfile
def qcow2size( qcow2 ):
"Return virtual disk size (in bytes) of qcow2 image"
output = check_output( [ 'file', qcow2 ] )
assert 'QCOW' in output
bytes = int( re.findall( '(\d+) bytes', output )[ 0 ] )
return bytes
def build( flavor='raring32server' ): def build( flavor='raring32server' ):
"Build a Mininet VM" "Build a Mininet VM; return vmdk and vdisk size"
global LogFile global LogFile
start = time() start = time()
date = strftime( '%y%m%d-%H-%M-%S', localtime()) date = strftime( '%y%m%d-%H-%M-%S', localtime())
@@ -528,14 +547,21 @@ def build( flavor='raring32server' ):
volume = flavor + '.qcow2' volume = flavor + '.qcow2'
run( 'qemu-img create -f qcow2 -b %s %s' % ( image, volume ) ) run( 'qemu-img create -f qcow2 -b %s %s' % ( image, volume ) )
log( '* VM image for', flavor, 'created as', volume ) log( '* VM image for', flavor, 'created as', volume )
if LogToConsole:
logfile = stdout
else:
logfile = open( flavor + '.log', 'w+' ) logfile = open( flavor + '.log', 'w+' )
log( '* Logging results to', abspath( logfile.name ) ) log( '* Logging results to', abspath( logfile.name ) )
vm = boot( volume, kernel, initrd, logfile ) vm = boot( volume, kernel, initrd, logfile )
interact( vm ) interact( vm )
size = qcow2size( volume )
vmdk = convert( volume, basename=flavor ) vmdk = convert( volume, basename=flavor )
if not SaveQCOW2:
log( '* Removing qcow2 volume', volume ) log( '* Removing qcow2 volume', volume )
os.remove( volume ) os.remove( volume )
log( '* Converted VM image stored as', abspath( vmdk ) ) log( '* Converted VM image stored as', abspath( vmdk ) )
vimage = genVirtImage( flavor, mem=512, diskname=vmdk, disksize=size )
log( '* Generated virtimage file as', vimage )
end = time() end = time()
elapsed = end - start elapsed = end - start
log( '* Results logged to', abspath( logfile.name ) ) log( '* Results logged to', abspath( logfile.name ) )
@@ -543,44 +569,50 @@ def build( flavor='raring32server' ):
log( '* %s VM build DONE!!!!! :D' % flavor ) log( '* %s VM build DONE!!!!! :D' % flavor )
os.chdir( '..' ) os.chdir( '..' )
def buildFlavorString():
def listFlavors(): "Return string listing valid build flavors"
"List valid build flavors" return 'valid build flavors: %s' % ' '.join( sorted( isoURLs ) )
print '\nvalid build flavors:', ' '.join( isoURLs ), '\n'
def parseArgs(): def parseArgs():
"Parse command line arguments and run" "Parse command line arguments and run"
parser = argparse.ArgumentParser( description='Mininet VM build script' ) global LogToConsole
parser.add_argument( '--depend', action='store_true', parser = argparse.ArgumentParser( description='Mininet VM build script',
epilog=buildFlavorString() )
parser.add_argument( '-v', '--verbose', action='store_true',
help='send VM output to console rather than log file' )
parser.add_argument( '-d', '--depend', action='store_true',
help='install dependencies for this script' ) help='install dependencies for this script' )
parser.add_argument( '--list', action='store_true', parser.add_argument( '-l', '--list', action='store_true',
help='list valid build flavors' ) help='list valid build flavors' )
parser.add_argument( '--clean', action='store_true', parser.add_argument( '-c', '--clean', action='store_true',
help='clean up leftover build junk (e.g. qemu-nbd)' ) help='clean up leftover build junk (e.g. qemu-nbd)' )
parser.add_argument( '-q', '--qcow2', action='store_true',
help='save qcow2 image rather than deleting it' )
parser.add_argument( 'flavor', nargs='*', parser.add_argument( 'flavor', nargs='*',
help='VM flavor to build (e.g. raring32server)' ) help='VM flavor(s) to build (e.g. raring32server)' )
args = parser.parse_args( argv ) args = parser.parse_args()
if args.depend: if args.depend:
depend() depend()
if args.list: if args.list:
listFlavors() print buildFlavorString()
if args.clean: if args.clean:
cleanup() cleanup()
flavors = args.flavor[ 1: ] if args.verbose:
for flavor in flavors: LogToConsole = True
for flavor in args.flavor:
if flavor not in isoURLs: if flavor not in isoURLs:
parser.print_help() print "Unknown build flavor:", flavor
listFlavors() print buildFlavorString()
break break
# try: # try:
build( flavor ) build( flavor )
# except Exception as e: # except Exception as e:
# log( '* BUILD FAILED with exception: ', e ) # log( '* BUILD FAILED with exception: ', e )
# exit( 1 ) # exit( 1 )
if not ( args.depend or args.list or args.clean or flavors ): if not ( args.depend or args.list or args.clean or args.flavor ):
parser.print_help() parser.print_help()
listFlavors()
if __name__ == '__main__': if __name__ == '__main__':
parseArgs() parseArgs()