Add TESTS parameters, multiple tests with +
It's very useful to be able to pass parameters to tests. Unfortunately, our previous --test argument syntax didn't permit it, because , was used as a delimiter for multiple tests. With this change, we change , to become a delimiter for arguments, as it is with other options to mn. For now, we introduce + as a separator, as it is legal in filenames and therefore shouldn't conflict with special characters used by Unix shells. We also reorganize mn a bit to make it hopefully slightly clearer.
This commit is contained in:
@@ -21,7 +21,7 @@ if 'PYTHONPATH' in os.environ:
|
|||||||
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
|
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
|
||||||
|
|
||||||
from mininet.clean import cleanup
|
from mininet.clean import cleanup
|
||||||
from mininet.cli import CLI
|
from mininet.cli import CLI as CLI
|
||||||
from mininet.log import lg, LEVELS, info, debug, warn, error
|
from mininet.log import lg, LEVELS, info, debug, warn, error
|
||||||
from mininet.net import Mininet, MininetWithControlNet, VERSION
|
from mininet.net import Mininet, MininetWithControlNet, VERSION
|
||||||
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
||||||
@@ -87,16 +87,48 @@ LINKS = { 'default': Link,
|
|||||||
'tc': TCLink,
|
'tc': TCLink,
|
||||||
'ovs': OVSLink }
|
'ovs': OVSLink }
|
||||||
|
|
||||||
|
# TESTS dict can contain functions and/or Mininet() method names
|
||||||
|
# XXX: it would be nice if we could specify a default test, but
|
||||||
|
# this may be tricky
|
||||||
|
TESTS = { name: True
|
||||||
|
for name in ( 'pingall', 'pingpair', 'iperf', 'iperfudp' ) }
|
||||||
|
|
||||||
# Names of tests that are Mininet() methods
|
|
||||||
TESTNAMES = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
|
|
||||||
'none' ]
|
|
||||||
|
|
||||||
# Map to alternate functions and/or spellings of Mininet() methods
|
# Locally defined tests
|
||||||
TESTS = { 'pingall': 'pingAll',
|
def allTest( net ):
|
||||||
'pingpair': 'pingPair',
|
"Run ping and iperf tests"
|
||||||
'iperfudp': 'iperfUdp',
|
net.waitConnected()
|
||||||
'iperfUDP': 'iperfUdp' }
|
net.start()
|
||||||
|
net.ping()
|
||||||
|
net.iperf()
|
||||||
|
def nullTest( net ):
|
||||||
|
"Null 'test' (does nothing)"
|
||||||
|
pass
|
||||||
|
TESTS.update( all=allTest, none=nullTest, build=nullTest )
|
||||||
|
|
||||||
|
# Map to alternate spellings of Mininet() methods
|
||||||
|
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
|
||||||
|
'iperfudp': 'iperfUdp' }
|
||||||
|
|
||||||
|
def runTests( mn, options ):
|
||||||
|
"""Run tests
|
||||||
|
mn: Mininet object
|
||||||
|
option: list of test optinos """
|
||||||
|
# Split option into test name and parameters
|
||||||
|
for option in options:
|
||||||
|
# Multiple tests may be separated by '+' for now
|
||||||
|
for test in option.split( '+' ):
|
||||||
|
test, args, kwargs = splitArgs( test )
|
||||||
|
test = ALTSPELLING.get( test.lower(), test )
|
||||||
|
testfn = TESTS.get( test, test )
|
||||||
|
if callable( testfn ):
|
||||||
|
testfn( mn, *args, **kwargs )
|
||||||
|
elif hasattr( mn, test ):
|
||||||
|
mn.waitConnected()
|
||||||
|
getattr( mn, test )( *args, **kwargs )
|
||||||
|
else:
|
||||||
|
raise Exception( 'Test %s is unknown - please specify one of '
|
||||||
|
'%s ' % ( test, TESTS.keys() ) )
|
||||||
|
|
||||||
|
|
||||||
def addDictOption( opts, choicesDict, default, name, **kwargs ):
|
def addDictOption( opts, choicesDict, default, name, **kwargs ):
|
||||||
@@ -117,7 +149,7 @@ def addDictOption( opts, choicesDict, default, name, **kwargs ):
|
|||||||
|
|
||||||
def version( *_args ):
|
def version( *_args ):
|
||||||
"Print Mininet version and exit"
|
"Print Mininet version and exit"
|
||||||
print( "%s" % VERSION )
|
info( "%s\n" % VERSION )
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
@@ -210,9 +242,8 @@ class MininetRunner( object ):
|
|||||||
type='string',
|
type='string',
|
||||||
help='read custom classes or params from .py file(s)'
|
help='read custom classes or params from .py file(s)'
|
||||||
)
|
)
|
||||||
testList = TESTNAMES + TESTS.keys()
|
|
||||||
opts.add_option( '--test', default=[], action='append',
|
opts.add_option( '--test', default=[], action='append',
|
||||||
dest='tests', help='|'.join( testList ) )
|
dest='test', help='|'.join( TESTS.keys() ) )
|
||||||
opts.add_option( '--xterms', '-x', action='store_true',
|
opts.add_option( '--xterms', '-x', action='store_true',
|
||||||
default=False, help='spawn xterms for each node' )
|
default=False, help='spawn xterms for each node' )
|
||||||
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
|
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
|
||||||
@@ -269,9 +300,9 @@ class MininetRunner( object ):
|
|||||||
|
|
||||||
# set logging verbosity
|
# set logging verbosity
|
||||||
if LEVELS[self.options.verbosity] > LEVELS['output']:
|
if LEVELS[self.options.verbosity] > LEVELS['output']:
|
||||||
print( '*** WARNING: selected verbosity level (%s) will hide CLI '
|
warn( '*** WARNING: selected verbosity level (%s) will hide CLI '
|
||||||
'output!\n'
|
'output!\n'
|
||||||
'Please restart Mininet with -v [debug, info, output].'
|
'Please restart Mininet with -v [debug, info, output].\n'
|
||||||
% self.options.verbosity )
|
% self.options.verbosity )
|
||||||
lg.setLogLevel( self.options.verbosity )
|
lg.setLogLevel( self.options.verbosity )
|
||||||
|
|
||||||
@@ -281,108 +312,84 @@ class MininetRunner( object ):
|
|||||||
def begin( self ):
|
def begin( self ):
|
||||||
"Create and run mininet."
|
"Create and run mininet."
|
||||||
|
|
||||||
if self.options.cluster:
|
opts = self.options
|
||||||
servers = self.options.cluster.split( ',' )
|
|
||||||
|
if opts.cluster:
|
||||||
|
servers = opts.cluster.split( ',' )
|
||||||
for server in servers:
|
for server in servers:
|
||||||
ClusterCleanup.add( server )
|
ClusterCleanup.add( server )
|
||||||
|
|
||||||
if self.options.clean:
|
if opts.clean:
|
||||||
cleanup()
|
cleanup()
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
if not self.options.controller:
|
if not opts.controller:
|
||||||
# Update default based on available controllers
|
# Update default based on available controllers
|
||||||
CONTROLLERS[ 'default' ] = findController()
|
CONTROLLERS[ 'default' ] = findController()
|
||||||
self.options.controller = [ 'default' ]
|
opts.controller = [ 'default' ]
|
||||||
if not CONTROLLERS[ 'default' ]:
|
if not CONTROLLERS[ 'default' ]:
|
||||||
self.options.controller = [ 'none' ]
|
opts.controller = [ 'none' ]
|
||||||
if self.options.switch == 'default':
|
if opts.switch == 'default':
|
||||||
info( '*** No default OpenFlow controller found '
|
info( '*** No default OpenFlow controller found '
|
||||||
'for default switch!\n' )
|
'for default switch!\n' )
|
||||||
info( '*** Falling back to OVS Bridge\n' )
|
info( '*** Falling back to OVS Bridge\n' )
|
||||||
self.options.switch = 'ovsbr'
|
opts.switch = 'ovsbr'
|
||||||
elif self.options.switch not in ( 'ovsbr', 'lxbr' ):
|
elif opts.switch not in ( 'ovsbr', 'lxbr' ):
|
||||||
raise Exception( "Could not find a default controller "
|
raise Exception( "Could not find a default controller "
|
||||||
"for switch %s" %
|
"for switch %s" %
|
||||||
self.options.switch )
|
opts.switch )
|
||||||
|
|
||||||
topo = buildTopo( TOPOS, self.options.topo )
|
topo = buildTopo( TOPOS, opts.topo )
|
||||||
switch = customClass( SWITCHES, self.options.switch )
|
switch = customClass( SWITCHES, opts.switch )
|
||||||
host = customClass( HOSTS, self.options.host )
|
host = customClass( HOSTS, opts.host )
|
||||||
controller = [ customClass( CONTROLLERS, c )
|
controller = [ customClass( CONTROLLERS, c )
|
||||||
for c in self.options.controller ]
|
for c in opts.controller ]
|
||||||
link = customClass( LINKS, self.options.link )
|
link = customClass( LINKS, opts.link )
|
||||||
|
|
||||||
if self.validate:
|
if self.validate:
|
||||||
self.validate( self.options )
|
self.validate( opts )
|
||||||
|
|
||||||
ipBase = self.options.ipbase
|
if opts.nolistenport:
|
||||||
xterms = self.options.xterms
|
opts.listenport = None
|
||||||
mac = self.options.mac
|
|
||||||
arp = self.options.arp
|
|
||||||
pin = self.options.pin
|
|
||||||
listenPort = None
|
|
||||||
if not self.options.nolistenport:
|
|
||||||
listenPort = self.options.listenport
|
|
||||||
|
|
||||||
# Handle inNamespace, cluster options
|
# Handle innamespace, cluster options
|
||||||
inNamespace = self.options.innamespace
|
if opts.innamespace and opts.cluster:
|
||||||
cluster = self.options.cluster
|
error( "Please specify --innamespace OR --cluster\n" )
|
||||||
if inNamespace and cluster:
|
|
||||||
print( "Please specify --innamespace OR --cluster" )
|
|
||||||
exit()
|
exit()
|
||||||
Net = MininetWithControlNet if inNamespace else Mininet
|
Net = MininetWithControlNet if opts.innamespace else Mininet
|
||||||
cli = ClusterCLI if cluster else CLI
|
if opts.cluster:
|
||||||
if cluster:
|
|
||||||
warn( '*** WARNING: Experimental cluster mode!\n'
|
warn( '*** WARNING: Experimental cluster mode!\n'
|
||||||
'*** Using RemoteHost, RemoteOVSSwitch, RemoteLink\n' )
|
'*** Using RemoteHost, RemoteOVSSwitch, RemoteLink\n' )
|
||||||
host, switch, link = RemoteHost, RemoteOVSSwitch, RemoteLink
|
host, switch, link = RemoteHost, RemoteOVSSwitch, RemoteLink
|
||||||
Net = partial( MininetCluster, servers=servers,
|
Net = partial( MininetCluster, servers=servers,
|
||||||
placement=PLACEMENT[ self.options.placement ] )
|
placement=PLACEMENT[ opts.placement ] )
|
||||||
|
global CLI
|
||||||
|
CLI = ClusterCLI
|
||||||
|
|
||||||
mn = Net( topo=topo,
|
mn = Net( topo=topo,
|
||||||
switch=switch, host=host, controller=controller,
|
switch=switch, host=host, controller=controller, link=link,
|
||||||
link=link,
|
ipBase=opts.ipbase, inNamespace=opts.innamespace,
|
||||||
ipBase=ipBase,
|
xterms=opts.xterms, autoSetMacs=opts.mac,
|
||||||
inNamespace=inNamespace,
|
autoStaticArp=opts.arp, autoPinCpus=opts.pin,
|
||||||
xterms=xterms, autoSetMacs=mac,
|
listenPort=opts.listenport )
|
||||||
autoStaticArp=arp, autoPinCpus=pin,
|
|
||||||
listenPort=listenPort )
|
|
||||||
|
|
||||||
if self.options.ensure_value( 'nat', False ):
|
if opts.ensure_value( 'nat', False ):
|
||||||
nat = mn.addNAT( *self.options.nat_args,
|
mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault()
|
||||||
**self.options.nat_kwargs )
|
|
||||||
nat.configDefault()
|
|
||||||
|
|
||||||
if self.options.pre:
|
if opts.pre:
|
||||||
cli( mn, script=self.options.pre )
|
CLI( mn, script=opts.pre )
|
||||||
|
|
||||||
mn.start()
|
mn.start()
|
||||||
|
|
||||||
if not self.options.tests:
|
if opts.test:
|
||||||
cli( mn )
|
runTests( mn, opts.test )
|
||||||
|
else:
|
||||||
|
CLI( mn )
|
||||||
|
|
||||||
for test in self.options.tests:
|
if opts.post:
|
||||||
test = TESTS.get( test, test )
|
CLI( mn, script=opts.post )
|
||||||
if callable( test ): # user added TESTMAP={'mytest': testfn}
|
|
||||||
test( mn )
|
|
||||||
elif test == 'none':
|
|
||||||
pass
|
|
||||||
elif test == 'all':
|
|
||||||
mn.waitConnected()
|
|
||||||
mn.start()
|
|
||||||
mn.ping()
|
|
||||||
mn.iperf()
|
|
||||||
elif test == 'cli':
|
|
||||||
cli( mn )
|
|
||||||
elif test != 'build':
|
|
||||||
mn.waitConnected()
|
|
||||||
getattr( mn, test )()
|
|
||||||
|
|
||||||
if self.options.post:
|
|
||||||
cli( mn, script=self.options.post )
|
|
||||||
|
|
||||||
mn.stop()
|
mn.stop()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user