diff --git a/util/vm/build.py b/util/vm/build.py
index 1cac35a..bcd8726 100755
--- a/util/vm/build.py
+++ b/util/vm/build.py
@@ -28,15 +28,16 @@ Basic idea:
import os
from os import stat, path
-from stat import ST_MODE
+from stat import ST_MODE, ST_SIZE
from os.path import abspath
-from sys import exit, stdout
+from sys import exit, stdout, argv
import re
from glob import glob
from subprocess import check_output, call, Popen
from tempfile import mkdtemp
from time import time, strftime, localtime
import argparse
+from distutils.spawn import find_executable
pexpect = None # For code check - imported dynamically
@@ -46,6 +47,7 @@ TIMEOUT=600
# Some configuration
LogToConsole = False # VM output to console rather than log file
SaveQCOW2 = False # Save QCOW2 image rather than deleting it
+NoKVM = False # Don't use kvm and use emulation instead
VMImageDir = os.environ[ 'HOME' ] + '/vm-images'
@@ -104,6 +106,10 @@ def run( cmd, **kwargs ):
"Convenient interface to check_output"
log( '-', cmd )
cmd = cmd.split()
+ arg0 = cmd[ 0 ]
+ if not find_executable( arg0 ):
+ raise Exception( 'Cannot find executable "%s";' % arg0 +
+ 'you might try %s --depend' % argv[ 0 ] )
return check_output( cmd, **kwargs )
@@ -112,6 +118,9 @@ def srun( cmd, **kwargs ):
return run( 'sudo ' + cmd, **kwargs )
+# BL: we should probably have a "checkDepend()" which
+# checks to make sure all dependencies are satisfied!
+
def depend():
"Install package dependencies"
log( '* Installing package dependencies' )
@@ -334,8 +343,12 @@ def installUbuntu( iso, image, logfilename='install.log' ):
srun( 'mount %s %s' % ( iso, mnt ) )
kernel = path.join( mnt, 'install/vmlinuz' )
initrd = path.join( mnt, 'install/initrd.gz' )
+ if NoKVM:
+ accel = 'tcg'
+ else:
+ accel = 'kvm'
cmd = [ 'sudo', kvm,
- '-machine', 'accel=kvm',
+ '-machine', 'accel=%s' % accel,
'-nographic',
'-netdev', 'user,id=mnbuild',
'-device', 'virtio-net,netdev=mnbuild',
@@ -384,8 +397,12 @@ def boot( cow, kernel, initrd, logfile ):
global pexpect
import pexpect
arch = archFor( kernel )
+ if NoKVM:
+ accel = 'tcg'
+ else:
+ accel = 'kvm'
cmd = [ 'sudo', 'qemu-system-' + arch,
- '-machine accel=kvm',
+ '-machine accel=%s' % accel,
'-nographic',
'-netdev user,id=mnbuild',
'-device virtio-net,netdev=mnbuild',
@@ -478,47 +495,109 @@ def convert( cow, basename ):
return vmdk
-# Template for virt-image(5) file
+# Template for OVF - a very verbose format!
+# In the best of all possible worlds, we might use an XML
+# library to generate this, but a template is easier and
+# possibly more concise!
-VirtImageXML = """
-
-
- %s
-
-
-
- %s
-
-
-
-
-
-
-
- 1
- %s
-
-
-
-
-
-
-
-
+OVFTemplate = """
+
+
+
+
+
+
+Virtual disk information
+
+
+
+The list of logical networks
+
+The nat network
+
+
+
+A Mininet Virtual Machine (%s)
+mininet-vm
+
+Virtual hardware requirements
+-
+hertz * 10^6
+Number of Virtual CPUs
+1 virtual CPU(s)
+1
+3
+1
+
+-
+byte * 2^20
+Memory Size
+%dMB of memory
+2
+4
+%d
+
+-
+0
+scsiController0
+SCSI Controller
+scsiController0
+4
+lsilogic
+6
+
+-
+0
+disk1
+ovf:/disk/vmdisk1
+11
+4
+17
+
+-
+2
+true
+nat
+E1000 ethernet adapter on nat
+ethernet0
+12
+E1000
+10
+
+-
+0
+usb
+USB Controller
+usb
+9
+23
+
+
+
+
"""
-def genVirtImage( name, mem, diskname, disksize ):
- "Generate and return virt-image file name.xml"
- # Our strategy is going to be: create a
- # virt-image file and then use virt-convert to convert
- # it to an .ovf file
- xmlfile = name + '.xml'
- arch = archFor( name )
- xmltext = VirtImageXML % ( name, arch, mem, diskname, disksize )
- with open( xmlfile, 'w+' ) as f:
+def generateOVF( name, diskname, disksize, mem=1024 ):
+ """Generate (and return) OVF file "name.ovf"
+ name: root name of OVF file to generate
+ diskname: name of disk file
+ disksize: size of virtual disk in bytes
+ mem: VM memory size in MB"""
+ ovf = name + '.ovf'
+ filesize = stat( diskname )[ ST_SIZE ]
+ # OVFTemplate uses the memory size twice in a row
+ xmltext = OVFTemplate % ( diskname, filesize, disksize, name, mem, mem )
+ with open( ovf, 'w+' ) as f:
f.write( xmltext )
- return xmlfile
+ return ovf
def qcow2size( qcow2 ):
@@ -560,8 +639,8 @@ def build( flavor='raring32server' ):
log( '* Removing qcow2 volume', volume )
os.remove( volume )
log( '* Converted VM image stored as', abspath( vmdk ) )
- vimage = genVirtImage( flavor, mem=512, diskname=vmdk, disksize=size )
- log( '* Generated virtimage file as', vimage )
+ ovf = generateOVF( diskname=vmdk, disksize=size, name=flavor, mem=1024 )
+ log( '* Generated OVF descriptor file', ovf )
end = time()
elapsed = end - start
log( '* Results logged to', abspath( logfile.name ) )
@@ -576,7 +655,7 @@ def buildFlavorString():
def parseArgs():
"Parse command line arguments and run"
- global LogToConsole
+ global LogToConsole, NoKVM
parser = argparse.ArgumentParser( description='Mininet VM build script',
epilog=buildFlavorString() )
parser.add_argument( '-v', '--verbose', action='store_true',
@@ -589,6 +668,8 @@ def parseArgs():
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( '-n', '--nokvm', action='store_true',
+ help="Don't use kvm - use tcg emulation instead" )
parser.add_argument( 'flavor', nargs='*',
help='VM flavor(s) to build (e.g. raring32server)' )
args = parser.parse_args()
@@ -600,6 +681,8 @@ def parseArgs():
cleanup()
if args.verbose:
LogToConsole = True
+ if args.nokvm:
+ NoKVM = True
for flavor in args.flavor:
if flavor not in isoURLs:
print "Unknown build flavor:", flavor