Add options; generate virtimage file (in progress)
This commit is contained in:
committed by
Brian O'Connor
parent
1ea9d7d4de
commit
d4279559fa
+62
-30
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user