Stratum Support for Segement Rounting Suite
- Add Stratum Bmv2 switch support for SRDhcpRelay and SRRouting tests
- Add Support for 0x1 topology on a Stratum Tofino HW switch
- Support for dockerized mininet with Stratum BMv2 switches
- Update scapy driver to work with newer versions of scapy
- Simple parsing for scapy ping output
- Add support for fetching and installing external onos apps
- Add support for onos-diagnostics profiles
- Move onos log levels to params file
- Add onos cfg settings to SR tests
Change-Id: I7c4a71484c8fd5735da9ef09b96d8990283b199b
(cherry picked from commit bef6d9bd943996483fed32130cb30ad26a06aac0)
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 55a106f..94664ad 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -63,6 +63,8 @@
self.scapyPrompt = ">>>"
self.graph = Graph()
self.sudoRequired = True
+ self.mExecDir = None
+ self.hostHome = None
def connect( self, **connectargs ):
"""
@@ -109,6 +111,8 @@
self.user_name +
"@" +
self.ip_address )
+ self.handle.sendline( "bash -i" )
+ self.handle.expect( self.bashPrompt )
return main.TRUE
else:
main.log.error( "Connection failed to the host " +
@@ -608,7 +612,10 @@
cmds = []
if self.getIPAddress( host ):
flushCmd = "{} ip neigh flush all".format( host )
- cmds.append( "{} arping -c 1 -w {} {}".format( host, wait, dstIp ) )
+ intf = hosts[ host ][ 'interfaces' ][ 0 ].get( 'name' )
+ intfStr = "-i {}".format( intf ) if intf else ""
+ cmds.append( "{} arping -c 1 -w {} {} {}".format(
+ host, wait, intfStr, dstIp ) )
main.log.debug( "Sending IPv4 arping from host {}".format( host ) )
elif self.getIPAddress( host, proto='IPV6' ):
flushCmd = "{} ip -6 neigh flush all".format( host )
@@ -827,10 +834,11 @@
timeout=wait + 5 )
# For some reason we need to send something
# Otherwise ping results won't be read by handle
+ response = self.handle.before
self.handle.sendline( "" )
self.handle.expect( self.hostPrompt )
if i == 0:
- response = self.handle.before
+ response += self.handle.before
if not re.search( ',\s0\%\spacket\sloss', response ):
main.log.debug( "Ping failed between %s and %s" % ( self.name, dstIP ) )
isReachable = main.FALSE
@@ -1145,19 +1153,23 @@
pattern = ''
if proto == 'IPV4':
- pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)\s\sBcast"
+ ip4Pat = r"(\d+\.\d+\.\d+\.\d+)"
+ pattern = r"inet\s(addr:)?(?P<ip>" + ip4Pat + ")\s\s((Bcast:" + ip4Pat + "\s\s|netmask\s" + ip4Pat + "\s\sbroadcast\s" + ip4Pat + "))"
else:
- pattern = "inet6\saddr:\s([\w,:]*)/\d+\sScope:Global"
+ inet6Pat = r'(?P<ip>((?:[0-9a-fA-F]{1,4})?(?:[:0-9a-fA-F]{1,4}){1,7}(?:::)?(?:[:0-9a-fA-F]{1,4}){1,7}))'
+ pattern = r"inet6\s(addr:\s)?" + inet6Pat + r"(/\d+)?\s(Scope:(Global|Link)|\sprefixlen\s(\d)+\s\sscopeid 0x(\d+)\<(link|global>))"
ipAddressSearch = re.search( pattern, response )
if not ipAddressSearch:
+ main.log.debug( response )
+ main.log.warn( "Could not find %s address" % proto )
return None
main.log.info(
self.name +
": IP-Address of Host " +
host +
" is " +
- ipAddressSearch.group( 1 ) )
- return ipAddressSearch.group( 1 )
+ ipAddressSearch.group( 'ip' ) )
+ return ipAddressSearch.group( 'ip' )
else:
main.log.error( self.name + ": Connection failed to the host" )
@@ -3613,14 +3625,23 @@
"""
updates the port address and status information for
each port in mn"""
- # TODO: Add error checking. currently the mininet command has no output
main.log.info( "Updating MN port information" )
try:
self.handle.sendline( "" )
self.handle.expect( "mininet>" )
+ # If update command isn't available, do it manually
self.handle.sendline( "update" )
- self.handle.expect( "mininet>", timeout )
+ self.handle.expect( "update" )
+ i = self.handle.expect( [ "Unknown command: update", "mininet>" ], timeout )
+ if i == 0:
+ main.log.debug( self.handle.before + self.handle.after )
+ main.log.warn( "Mininet cli does not have update command, attempting to update interfaces without it" )
+ self.handle.expect( "mininet>" )
+ self.handle.sendline( "px [i.updateAddr() for h in net.hosts for i in h.intfs.values() ] " )
+ self.handle.expect( "mininet>", timeout )
+ self.handle.sendline( "px [i.updateAddr() for s in net.switches for i in h.intfs.values() ] " )
+ self.handle.expect( "mininet>", timeout )
self.handle.sendline( "" )
self.handle.expect( "mininet>" )
@@ -3777,7 +3798,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
return main.FALSE
- def createHostComponent( self, name ):
+ def createHostComponent( self, name, execDir=None, hostHome=None ):
"""
Creates a new mininet cli component with the same parameters as self.
This new component is intended to be used to login to the hosts created
@@ -3795,7 +3816,17 @@
# namespace is clear, creating component
main.componentDictionary[ name ] = main.componentDictionary[ self.name ].copy()
main.componentDictionary[ name ][ 'connect_order' ] = str( int( main.componentDictionary[ name ][ 'connect_order' ] ) + 1 )
- main.componentInit( name )
+ component = main.componentInit( name )
+ if execDir is not None:
+ component.mExecDir = execDir
+ else:
+ component.mExecDir = self.mExecDir
+
+ if hostHome is not None:
+ component.hostHome = hostHome
+ else:
+ component.hostHome = self.hostHome
+ component.hostPrompt = self.hostPrompt
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
main.log.error( self.name + ": " + self.handle.before )
@@ -3840,17 +3871,31 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def startHostCli( self, host=None ):
+ def startHostCli( self, host=None, execDir=None, hostHome=None ):
"""
Use the mininet m utility to connect to the host's cli
+ mnexec tries to cd to cwd after it connects to the host. If execDir
+ is set, this will change cwd to execDir before executing m.
+ If hostHome is set, the function will export the value to the HOME
+ environment variable.
"""
# These are fields that can be used by scapy packets. Initialized to None
self.hostIp = None
self.hostMac = None
+ if execDir is not None:
+ self.mExecDir = execDir
+ if hostHome is not None:
+ self.hostHome = hostHome
try:
if not host:
host = self.name
+ if self.mExecDir:
+ self.handle.sendline( "cd %s" % self.mExecDir )
+ self.handle.expect( self.prompt )
+
self.handle.sendline( self.home + "/util/m " + host )
+ if self.hostHome:
+ self.handle.sendline( "export HOME=%s" % self.hostHome )
self.handle.sendline( "cd" )
self.handle.expect( self.hostPrompt )
self.handle.sendline( "" )
@@ -3858,6 +3903,7 @@
return main.TRUE
except pexpect.TIMEOUT:
main.log.exception( self.name + ": Command timed out" )
+ main.log.debug( self.handle.before )
return main.FALSE
except pexpect.EOF:
main.log.exception( self.name + ": connection closed." )
diff --git a/TestON/drivers/common/cli/emulator/mininethostdriver.py b/TestON/drivers/common/cli/emulator/mininethostdriver.py
index 360fd9a..7c87136 100644
--- a/TestON/drivers/common/cli/emulator/mininethostdriver.py
+++ b/TestON/drivers/common/cli/emulator/mininethostdriver.py
@@ -22,13 +22,8 @@
import pexpect
import re
-import sys
-import types
import os
-import time
-from math import pow
from drivers.common.cli.emulatordriver import Emulator
-from core.graph import Graph
class MininetHostDriver( Emulator ):
@@ -82,10 +77,11 @@
pwd=self.pwd )
if self.handle:
- main.log.info( "Connection successful to the " +
+ main.log.info( "Connection successful to " +
self.user_name +
"@" +
self.ip_address )
+ self.handle.sendline( "bash -i" )
self.handle.sendline( "~/mininet/util/m " + self.shortName )
self.handle.sendline( "cd" )
self.handle.expect( self.hostPrompt )
diff --git a/TestON/drivers/common/cli/emulator/scapyclidriver.py b/TestON/drivers/common/cli/emulator/scapyclidriver.py
index 6a24aa2..e2d5b0b 100644
--- a/TestON/drivers/common/cli/emulator/scapyclidriver.py
+++ b/TestON/drivers/common/cli/emulator/scapyclidriver.py
@@ -27,7 +27,6 @@
import pexpect
import re
import sys
-import types
import os
from drivers.common.cli.emulatordriver import Emulator
@@ -58,6 +57,20 @@
self.home = self.options[ 'home' ] if 'home' in self.options.keys() else "~/"
self.name = self.options[ 'name' ]
self.ifaceName = self.options[ 'ifaceName' ] if 'ifaceName' in self.options.keys() else self.name + "-eth0"
+
+ # Parse route config
+ self.routes = []
+ routes = self.options.get( 'routes' )
+ if routes:
+ for route in routes:
+ route = routes[ route ]
+ iface = route.get( 'interface' )
+ if not iface:
+ iface = None
+ self.routes.append( { 'network': route[ 'network' ],
+ 'netmask': route[ 'netmask' ],
+ 'gw': route.get( 'gw' ),
+ 'interface': iface } )
try:
if os.getenv( str( self.ip_address ) ) is not None:
self.ip_address = os.getenv( str( self.ip_address ) )
@@ -67,11 +80,11 @@
self.ip_address )
except KeyError:
- main.log.info( "Invalid host name," +
+ main.log.info( self.name + ": Invalid host name," +
" connecting to local host instead" )
self.ip_address = 'localhost'
except Exception as inst:
- main.log.error( "Uncaught exception: " + str( inst ) )
+ main.log.error( self.name + ": Uncaught exception: " + str( inst ) )
self.handle = super(
ScapyCliDriver,
@@ -82,7 +95,7 @@
pwd=self.pwd )
if self.handle:
- main.log.info( "Connection successful to the host " +
+ main.log.info( self.name + ": Connection successful to the host " +
self.user_name +
"@" +
self.ip_address )
@@ -107,6 +120,7 @@
Called at the end of the test to stop the scapy component and
disconnect the handle.
"""
+ main.log.debug( self.name + ": Disconnecting" )
response = main.TRUE
try:
if self.handle:
@@ -120,12 +134,13 @@
response = main.FALSE
return response
- def startScapy( self, mplsPath="" ):
+ def startScapy( self, mplsPath="", ifaceName=None ):
"""
Start the Scapy cli
optional:
mplsPath - The path where the MPLS class is located
NOTE: This can be a relative path from the user's home dir
+ ifaceName - the name of the default interface to use.
"""
mplsLines = [ 'import imp',
'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format( mplsPath ),
@@ -135,17 +150,35 @@
'bind_layers(MPLS, IP)' ]
try:
+ main.log.debug( self.name + ": Starting scapy" )
self.handle.sendline( "sudo scapy" )
self.handle.expect( self.scapyPrompt )
self.handle.sendline( "conf.color_theme = NoTheme()" )
self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
+ self.handle.sendline( "conf.fancy_prompt = False" )
+ self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
+ self.handle.sendline( "conf.interactive = False" )
+ self.handle.expect( "interactive" )
+ self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
+ self.handle.sendline( "" )
+ self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
if mplsPath:
- main.log.info( "Adding MPLS class" )
- main.log.info( "MPLS class path: " + mplsPath )
+ main.log.debug( self.name + ": Adding MPLS class" )
+ main.log.debug( self.name + ": MPLS class path: " + mplsPath )
for line in mplsLines:
- main.log.info( "sending line: " + line )
+ main.log.debug( self.name + ": sending line: " + line )
self.handle.sendline( line )
self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
+
+ # Set interface
+ if ifaceName:
+ self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
+ self.clearBuffer()
return main.TRUE
except pexpect.TIMEOUT:
main.log.exception( self.name + ": Command timed out" )
@@ -162,6 +195,7 @@
Exit the Scapy cli
"""
try:
+ main.log.debug( self.name + ": Stopping scapy" )
self.handle.sendline( "exit()" )
self.handle.expect( self.hostPrompt )
return main.TRUE
@@ -191,6 +225,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building Ethernet Frame" )
# Set the Ethernet frame
cmd = 'ether = Ether( '
options = []
@@ -202,15 +237,17 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
self.handle.sendline( "packet = ether" )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -249,6 +286,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building IP Frame" )
# Set the IP frame
cmd = 'ip = IP( '
options = []
@@ -260,15 +298,17 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
self.handle.sendline( "packet = ether/ip" )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -302,6 +342,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building IPv6 Frame" )
# Set the IPv6 frame
cmd = 'ipv6 = IPv6( '
options = []
@@ -313,15 +354,17 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
self.handle.sendline( "packet = ether/ipv6" )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -366,6 +409,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building TCP" )
# Set the TCP frame
cmd = 'tcp = TCP( '
options = []
@@ -375,9 +419,10 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
if str( ipVersion ) is '4':
self.handle.sendline( "packet = ether/ip/tcp" )
@@ -388,9 +433,10 @@
repr( ipVersion ) )
return main.FALSE
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -428,6 +474,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building UDP Frame" )
# Set the UDP frame
cmd = 'udp = UDP( '
options = []
@@ -437,9 +484,10 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
if str( ipVersion ) is '4':
self.handle.sendline( "packet = ether/ip/udp" )
@@ -450,9 +498,10 @@
repr( ipVersion ) )
return main.FALSE
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -490,6 +539,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building SCTP Frame" )
# Set the SCTP frame
cmd = 'sctp = SCTP( '
options = [ ]
@@ -499,9 +549,10 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
if str( ipVersion ) is '4':
self.handle.sendline( "packet = ether/ip/sctp" )
@@ -512,9 +563,10 @@
repr( ipVersion ) )
return main.FALSE
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -554,6 +606,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building ARP Frame" )
# Set the ARP frame
cmd = 'arp = ARP( '
options = []
@@ -565,15 +618,17 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
self.handle.sendline( "packet = ether/arp" )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -608,6 +663,7 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Building ICMP Frame" )
# Set the ICMP frame
if str( ipVersion ) is '4':
cmd = 'icmp = ICMP( '
@@ -626,9 +682,10 @@
cmd += ' )'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
if str( ipVersion ) is '4':
@@ -640,9 +697,10 @@
repr( ipVersion ) )
return main.FALSE
self.handle.expect( self.scapyPrompt )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( "Error in sending command: " + response )
return main.FALSE
return main.TRUE
except pexpect.TIMEOUT:
@@ -655,7 +713,26 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def sendPacket( self, iface=None, packet=None, timeout=1 ):
+ def clearBuffer( self, debug=False ):
+ """
+ Keep reading from buffer until its empty
+ Everything seems to be printed twice in newer versions of
+ scapy, even when turning off fancy output
+ """
+ i = 0
+ response = ''
+ while True:
+ try:
+ i += 1
+ # clear buffer
+ if debug:
+ main.log.warn( "%s expect loop iteration" % i )
+ self.handle.expect( self.scapyPrompt, timeout=1 )
+ response += self.cleanOutput( self.handle.before, debug )
+ except pexpect.TIMEOUT:
+ return response
+
+ def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
"""
Send a packet with either the given scapy packet command, or use the
packet saved in the variable 'packet'.
@@ -672,8 +749,13 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.debug( self.name + ": Sending Packet" )
+ if debug:
+ self.handle.sendline( "packet.summary()" )
+ self.handle.expect( self.scapyPrompt )
+ self.clearBuffer()
# TODO: add all params, or use kwargs
- sendCmd = 'srp( '
+ sendCmd = 'sendp( '
if packet:
sendCmd += packet
else:
@@ -681,13 +763,15 @@
if iface:
sendCmd += ", iface='{}'".format( iface )
- sendCmd += ', timeout=' + str( timeout ) + ')'
+ if debug:
+ sendCmd += ', return_packets=True).summary()' # show packet(s) sent
self.handle.sendline( sendCmd )
self.handle.expect( self.scapyPrompt )
- # main.log.warn( "Send packet response: {}".format( self.handle.before ) )
- if "Traceback" in self.handle.before:
+ response = self.cleanOutput( self.handle.before )
+ main.log.debug( self.name + ": Send packet response: {}".format( response ) )
+ if "Traceback" in response:
# KeyError, SyntaxError, ...
- main.log.error( "Error in sending command: " + self.handle.before )
+ main.log.error( self.name + ": Error in sending command: " + response )
return main.FALSE
# TODO: Check # of packets sent?
return main.TRUE
@@ -715,24 +799,30 @@
Returns main.TRUE or main.FALSE on error
"""
try:
+ main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
# TODO: add all params, or use kwargs
ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
# Set interface
self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
+ self.handle.expect( ifaceName )
+ self.cleanOutput( self.handle.before + self.handle.after )
+ self.cleanOutput( self.handle.before )
self.handle.expect( self.scapyPrompt )
- cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
- ', filter = "' + str( pktFilter ) + '")'
- main.log.info( "Filter on " + self.name + ' > ' + cmd )
+ response = self.handle.before + self.handle.after
+ self.cleanOutput( response )
+ cmd = 'pkts = sniff(count = %s, filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, pktFilter )
+ main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
self.handle.sendline( cmd )
- self.handle.expect( '"\)\r\n' )
+ response = self.clearBuffer()
+
# Make sure the sniff function didn't exit due to failures
i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
+ response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
if i == 0:
# sniff exited
main.log.error( self.name + ": sniff function exited" )
- main.log.error( self.name + ": " + self.handle.before )
+ main.log.error( self.name + ": " + response )
return main.FALSE
- # TODO: parse this?
return main.TRUE
except pexpect.TIMEOUT:
main.log.exception( self.name + ": Command timed out" )
@@ -746,10 +836,16 @@
def checkFilter( self, timeout=10 ):
"""
- Check that a filter returned and returns the reponse
+ Check if a filter is still running.
+ Returns:
+ main.TRUE if the filter stopped
+ main.FALSE if the filter is still running
"""
try:
+ main.log.debug( self.name + ": Checking Filter" )
+ self.handle.sendline( "" )
i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
+ response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
if i == 0:
return main.TRUE
else:
@@ -766,9 +862,11 @@
Kill a scapy filter
"""
try:
+ main.log.debug( self.name + ": Killing scapy filter" )
self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
self.handle.expect( self.scapyPrompt )
- return self.handle.before
+ output = self.cleanOutput( self.handle.before, debug=True )
+ return output
except pexpect.TIMEOUT:
main.log.exception( self.name + ": Command timed out" )
return None
@@ -784,9 +882,13 @@
Read all the packets captured by the previous filter
"""
try:
- self.handle.sendline( "for p in pkt: p \n")
- self.handle.expect( "for p in pkt: p \r\n... \r\n" )
- self.handle.expect( self.scapyPrompt )
+ main.log.debug( self.name + ": Reading Packets" )
+ main.log.debug( self.name + ": Begin clear buffer" )
+ self.clearBuffer()
+ main.log.debug( self.name + ": end clear buffer" )
+
+ self.handle.sendline( "pkts.summary()")
+ output = self.clearBuffer()
except pexpect.TIMEOUT:
main.log.exception( self.name + ": Command timed out" )
return None
@@ -796,7 +898,7 @@
except Exception:
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- return self.handle.before
+ return output
def updateSelf( self, IPv6=False ):
"""
@@ -817,8 +919,9 @@
cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
- match = re.search( pattern, self.handle.before )
+ match = re.search( pattern, response )
if match:
return match.group()
else:
@@ -851,11 +954,12 @@
cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
self.handle.sendline( cmd )
self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
if IPv6:
pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
- match = re.search( pattern, self.handle.before )
+ match = re.search( pattern, response )
if match:
# NOTE: The command will return 0.0.0.0 if the iface doesn't exist
if IPv6 is not True:
@@ -908,6 +1012,50 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
+ def addRoute( self, network, gateway, interface=None ):
+ """
+ Add a route to the current scapy session
+ """
+ main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
+ if gateway is None:
+ main.log.error( self.name + ": Gateway is None, cannot set route" )
+ return main.FALSE
+ try:
+ cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
+ if interface:
+ cmdStr += ', dev="%s"' % interface
+ cmdStr += ')'
+ self.handle.sendline( cmdStr )
+ self.handle.expect( self.scapyPrompt )
+ response = self.cleanOutput( self.handle.before )
+ if "Traceback" in response:
+ main.log.error( self.name + ": Error in adding route to scappy session" )
+ main.log.debug( response )
+ return main.FALSE
+ return main.TRUE
+ except pexpect.TIMEOUT:
+ main.log.exception( self.name + ": Command timed out" )
+ return None
+ except pexpect.EOF:
+ main.log.exception( self.name + ": connection closed." )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
+ def addRoutes( self ):
+ """
+ Add any routes configured for the host
+ """
+ returnValues = []
+ for route in self.routes:
+ gw = route.get( 'gw' )
+ iface = route.get( 'interface' )
+ returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
+ gw if gw else main.Cluster.active(0).ipAddress,
+ interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
+ return returnValues
+
def getIfList( self ):
"""
Return List of Interfaces
@@ -915,7 +1063,8 @@
try:
self.handle.sendline( 'get_if_list()' )
self.handle.expect( self.scapyPrompt )
- ifList = self.handle.before.split( '\r\n' )
+ response = self.cleanOutput( self.handle.before )
+ ifList = response.split( '\r\n' )
ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
return ifList
diff --git a/TestON/drivers/common/cli/hostdriver.py b/TestON/drivers/common/cli/hostdriver.py
index 7c7cd80..e14a38d 100644
--- a/TestON/drivers/common/cli/hostdriver.py
+++ b/TestON/drivers/common/cli/hostdriver.py
@@ -22,11 +22,7 @@
import pexpect
import re
-import sys
-import types
import os
-import time
-from math import pow
from drivers.common.cli.emulator.scapyclidriver import ScapyCliDriver
class HostDriver( ScapyCliDriver ):
@@ -60,7 +56,7 @@
self.interfaces.append( { 'ips': [ self.options[ 'ip' ] ],
'isUp': True,
'mac': self.options[ 'mac' ],
- 'name': None } )
+ 'name': self.options.get( 'interfaceName', None ) } )
try:
if os.getenv( str( self.ip_address ) ) is not None:
@@ -121,18 +117,18 @@
i = self.handle.expect( [ "closed", pexpect.TIMEOUT ] )
if i == 1:
main.log.error( self.name + ": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
+ main.log.error( self.name + ": response: " + str( self.handle.before ) )
else:
self.handle.sendline( "" )
i = self.handle.expect( [ self.prompt, pexpect.TIMEOUT ], timeout=2 )
if i == 1:
main.log.warn( self.name + ": timeout when waiting for response" )
- main.log.warn( "response: " + str( self.handle.before ) )
+ main.log.warn( self.name + ": response: " + str( self.handle.before ) )
self.handle.sendline( "exit" )
i = self.handle.expect( [ "closed", pexpect.TIMEOUT ], timeout=2 )
if i == 1:
main.log.warn( self.name + ": timeout when waiting for response" )
- main.log.warn( "response: " + str( self.handle.before ) )
+ main.log.warn( self.name + ": response: " + str( self.handle.before ) )
return main.TRUE
except TypeError:
main.log.exception( self.name + ": Object not as expected" )
@@ -201,7 +197,7 @@
i = self.handle.expect( [ "closed", pexpect.TIMEOUT ], timeout=2 )
if i == 1:
main.log.error( self.name + ": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
+ main.log.error( self.name + ": response: " + str( self.handle.before ) )
return main.TRUE
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
@@ -212,7 +208,7 @@
main.log.error( self.name + ": " + self.handle.before )
return main.FALSE
- def ping( self, dst, ipv6=False, wait=3 ):
+ def ping( self, dst, ipv6=False, interface=None, wait=3 ):
"""
Description:
Ping from this host to another
@@ -220,10 +216,13 @@
dst: IP address of destination host
Optional:
ipv6: will use ping6 command if True; otherwise use ping command
+ interface: Specify which interface to use for the ping
wait: timeout for ping command
"""
try:
command = "ping6" if ipv6 else "ping"
+ if interface:
+ command += " -I %s " % interface
command += " -c 1 -i 1 -W " + str( wait ) + " " + str( dst )
main.log.info( self.name + ": Sending: " + command )
self.handle.sendline( command )
@@ -233,7 +232,7 @@
main.log.error(
self.name +
": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
+ main.log.error( self.name + ": response: " + str( self.handle.before ) )
self.handle.sendline( "" )
self.handle.expect( self.prompt )
response = self.handle.before
@@ -314,7 +313,7 @@
main.log.error(
self.name +
": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
+ main.log.error( self.name + ": response: " + str( self.handle.before ) )
response = self.handle.before
return response
except pexpect.EOF:
@@ -337,7 +336,7 @@
timeout=wait + 5 )
if i == 1:
main.log.error( self.name + ": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
+ main.log.error( self.name + ": response: " + str( self.handle.before ) )
response = self.handle.before
return response
except pexpect.EOF:
@@ -348,7 +347,7 @@
main.log.exception( self.name + ": uncaught exception!" )
main.cleanAndExit()
- def command( self, cmd, wait=3 ):
+ def command( self, cmd, wait=3, debug=False):
"""
Run shell command on host and return output
Required:
@@ -359,10 +358,12 @@
self.handle.sendline( cmd )
i = self.handle.expect( [ self.prompt, pexpect.TIMEOUT ],
timeout=wait + 5 )
+ response = self.handle.before
+ if debug:
+ main.log.debug( response )
if i == 1:
main.log.error( self.name + ": timeout when waiting for response" )
- main.log.error( "response: " + str( self.handle.before ) )
- response = self.handle.before
+ main.log.error( self.name + ": response: " + str( response ) )
return response
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
diff --git a/TestON/drivers/common/cli/networkdriver.py b/TestON/drivers/common/cli/networkdriver.py
index 1cd242c..968973d 100755
--- a/TestON/drivers/common/cli/networkdriver.py
+++ b/TestON/drivers/common/cli/networkdriver.py
@@ -31,6 +31,9 @@
import os
import re
import types
+import time
+import itertools
+import random
from drivers.common.clidriver import CLI
from core.graph import Graph
@@ -126,7 +129,7 @@
try:
for key, value in main.componentDictionary.items():
if hasattr( main, key ):
- if value[ 'type' ] in [ 'MininetSwitchDriver', 'OFDPASwitchDriver' ]:
+ if value[ 'type' ] in [ 'MininetSwitchDriver', 'OFDPASwitchDriver', 'StratumOSSwitchDriver' ]:
component = getattr( main, key )
shortName = component.options[ 'shortName' ]
localName = self.name + "-" + shortName
@@ -275,7 +278,12 @@
continue
if not includeStopped and not switchComponent.isup:
continue
- dpid = switchComponent.dpid.replace( '0x', '' ).zfill( 16 )
+ try:
+ dpid = switchComponent.dpid
+ except AttributeError:
+ main.log.warn( "Switch has no dpid, ignore this if not an OpenFlow switch" )
+ dpid = "0x0"
+ dpid = dpid.replace( '0x', '' ).zfill( 16 )
ports = switchComponent.ports
swClass = 'Unknown'
pid = None
@@ -344,7 +352,6 @@
"""
Return MAC address of a host
"""
- import re
try:
hostComponent = self.hosts[ host ]
response = hostComponent.ifconfig()
@@ -460,8 +467,6 @@
main.TRUE if pingall completes with no pings dropped
otherwise main.FALSE
"""
- import time
- import itertools
try:
timeout = int( timeout )
main.log.info( self.name + ": Checking reachabilty to the hosts using ping" )
@@ -495,7 +500,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def pingallHosts( self, hostList, wait=1 ):
+ def pingallHosts( self, hostList, ipv6=False, wait=1, useScapy=False ):
"""
Ping all specified IPv4 hosts
@@ -507,8 +512,6 @@
Returns main.FALSE if one or more of hosts specified
cannot reach each other"""
- import time
- import itertools
hostComponentList = []
for hostName in hostList:
hostComponent = self.hosts[ hostName ]
@@ -522,8 +525,49 @@
hostPairs = itertools.permutations( list( hostComponentList ), 2 )
for hostPair in list( hostPairs ):
pingResponse += hostPair[ 0 ].options[ 'shortName' ] + " -> "
- ipDst = hostPair[ 1 ].options[ 'ip6' ] if ipv6 else hostPair[ 1 ].options[ 'ip' ]
- pingResult = hostPair[ 0 ].ping( ipDst, wait=int( wait ) )
+ ipDst = hostPair[ 1 ].options.get( 'ip6', hostPair[ 1 ].options[ 'ip' ] ) if ipv6 else hostPair[ 1 ].options[ 'ip' ]
+ srcIface = hostPair[ 0 ].interfaces[0].get( 'name' )
+ dstIface = hostPair[ 1 ].interfaces[0].get( 'name' )
+ srcMac = hostPair[0].interfaces[0].get( 'mac' )
+ dstMac = hostPair[1].interfaces[0].get( 'mac' )
+ if useScapy:
+ main.log.debug( "Pinging from " + str( hostPair[ 0 ].shortName ) + " to " + str( hostPair[ 1 ].shortName ) )
+ srcIPs = hostPair[ 0 ].interfaces[0].get( 'ips' )
+ dstIPs = hostPair[ 1 ].interfaces[0].get( 'ips' )
+ # Use scapy to send and recieve packets
+ hostPair[ 1 ].startScapy( ifaceName=dstIface )
+ hostPair[ 1 ].addRoutes()
+ hostPair[ 1 ].startFilter( ifaceName=dstIface, pktFilter="ether host %s and ip host %s" % ( srcMac, srcIPs[0] ) )
+
+ hostPair[ 0 ].startScapy( ifaceName=srcIface )
+ hostPair[ 0 ].addRoutes()
+ hostPair[ 0 ].buildEther( dst=dstMac )
+ hostPair[ 0 ].buildIP( src=srcIPs, dst=dstIPs )
+ hostPair[ 0 ].buildICMP( )
+ hostPair[ 0 ].sendPacket( iface=srcIface )
+
+ waiting = not hostPair[ 1 ].checkFilter()
+ if not waiting:
+ pingResult = main.FALSE
+ packets = hostPair[ 1 ].readPackets()
+ main.log.warn( packets )
+ for packet in packets.splitlines():
+ main.log.debug( packet )
+ if srcIPs[0] in packet:
+ pingResult = main.TRUE
+ else:
+ main.log.warn( "Did not receive packets, killing filter" )
+ kill = hostPair[ 1 ].killFilter()
+ main.log.debug( kill )
+ hostPair[ 1 ].handle.sendline( "" )
+ hostPair[ 1 ].handle.expect( hostPair[ 1 ].scapyPrompt )
+ main.log.debug( hostPair[ 1 ].handle.before )
+ # One of the host to host pair is unreachable
+ pingResult = main.FALSE
+ hostPair[ 0 ].stopScapy()
+ hostPair[ 1 ].stopScapy()
+ else:
+ pingResult = hostPair[ 0 ].ping( ipDst, interface=srcIface, wait=int( wait ) )
if pingResult:
pingResponse += hostPair[ 1 ].options[ 'shortName' ]
else:
@@ -538,6 +582,122 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
+ def pingallHostsUnidirectional( self, srcList, dstList, ipv6=False, wait=1, acceptableFailed=0, useScapy=False ):
+ """
+ Verify ping from each host in srcList to each host in dstList
+
+ acceptableFailed: max number of acceptable failed pings
+
+ Returns main.TRUE if all src hosts can reach all dst hosts
+ Returns main.FALSE if one or more of src hosts cannot reach one or more of dst hosts
+ """
+ try:
+ main.log.info( "Verifying ping from each src host to each dst host" )
+
+ srcComponentList = []
+ for hostName in srcList:
+ hostComponent = self.hosts[ hostName ]
+ if hostComponent:
+ main.log.debug( repr( hostComponent ) )
+ srcComponentList.append( hostComponent )
+ dstComponentList = []
+ for hostName in dstList:
+ hostComponent = self.hosts[ hostName ]
+ if hostComponent:
+ main.log.debug( repr( hostComponent ) )
+ dstComponentList.append( hostComponent )
+
+ isReachable = main.TRUE
+ wait = int( wait )
+ cmd = " ping" + ("6" if ipv6 else "") + " -c 1 -i 1 -W " + str( wait ) + " "
+ pingResponse = "Ping output:\n"
+ failedPingsTotal = 0
+ for srcHost in srcComponentList:
+ pingResponse += str( str( srcHost.shortName ) + " -> " )
+ for dstHost in dstComponentList:
+ failedPings = 0
+ dstIP = dstHost.ip
+ assert dstIP, "Not able to get IP address of host {}".format( dstHost )
+ for iface in srcHost.interfaces:
+ # FIXME This only works if one iface name is configured
+ # NOTE: We can use an IP with -I instead of an interface name as well
+ name = iface.get( 'name' )
+ if name:
+ cmd += " -I %s " % name
+
+ if useScapy:
+ while failedPings <= acceptableFailed:
+ main.log.debug( "Pinging from " + str( srcHost.shortName ) + " to " + str( dstHost.shortName ) )
+ # Use scapy to send and recieve packets
+ dstHost.startFilter()
+ srcHost.buildEther( dst=srcHost.interfaces[0].get( 'mac') )
+ srcHost.sendPacket()
+ output = dstHost.checkFilter()
+ main.log.debug( output )
+ if output:
+ #TODO: parse output?
+ packets = dstHost.readPackets()
+ for packet in packets.splitlines():
+ main.log.debug( packet )
+ pingResponse += " " + str( dstHost.shortName )
+ break
+ else:
+ kill = dstHost.killFilter()
+ main.log.debug( kill )
+ dstHost.handle.sendline( "" )
+ dstHost.handle.expect( dstHost.scapyPrompt )
+ main.log.debug( dstHost.handle.before )
+ failedPings += 1
+ time.sleep(1)
+ if failedPings > acceptableFailed:
+ # One of the host to host pair is unreachable
+ pingResponse += " X"
+ isReachable = main.FALSE
+ failedPingsTotal += 1
+
+ else:
+ pingCmd = cmd + str( dstIP )
+ while failedPings <= acceptableFailed:
+ main.log.debug( "Pinging from " + str( srcHost.shortName ) + " to " + str( dstHost.shortName ) )
+ self.handle.sendline( pingCmd )
+ self.handle.expect( self.prompt, timeout=wait + 5 )
+ response = self.handle.before
+ if re.search( ',\s0\%\spacket\sloss', response ):
+ pingResponse += " " + str( dstHost.shortName )
+ break
+ else:
+ failedPings += 1
+ time.sleep(1)
+ if failedPings > acceptableFailed:
+ # One of the host to host pair is unreachable
+ pingResponse += " X"
+ isReachable = main.FALSE
+ failedPingsTotal += 1
+ pingResponse += "\n"
+ main.log.info( pingResponse + "Failed pings: " + str( failedPingsTotal ) )
+ return isReachable
+ except AssertionError:
+ main.log.exception( "" )
+ return main.FALSE
+ except pexpect.TIMEOUT:
+ main.log.exception( self.name + ": TIMEOUT exception" )
+ response = self.handle.before
+ # NOTE: Send ctrl-c to make sure command is stopped
+ self.exitFromCmd( [ "Interrupt", self.prompt ] )
+ response += self.handle.before + self.handle.after
+ self.handle.sendline( "" )
+ self.handle.expect( self.prompt )
+ response += self.handle.before + self.handle.after
+ main.log.debug( response )
+ return main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
def iperftcp( self, host1="h1", host2="h2", timeout=6 ):
'''
Creates an iperf TCP test between two hosts. Returns main.TRUE if test results
@@ -658,7 +818,6 @@
Any link that has either end included in skipLinks will be excluded.
Returns the link as a list, e.g. [ 's1', 's2' ].
"""
- import random
candidateLinks = []
try:
if not nonCut:
@@ -708,7 +867,6 @@
Switches specified in skipSwitches will be excluded.
Returns the name of the chosen switch.
"""
- import random
candidateSwitches = []
try:
if not nonCut:
@@ -896,9 +1054,11 @@
for host in hostList:
flushCmd = ""
cmd = ""
- if self.getIPAddress( host ):
+ if self.getIPAddress( host ) or hosts[host]['interfaces'][0].get( 'ips', False ) :
flushCmd = "sudo ip neigh flush all"
- cmd = "arping -c 1 -w {} {}".format( wait, dstIp )
+ intf = hosts[host]['interfaces'][0].get( 'name' )
+ intfStr = "-i {}".format( intf ) if intf else ""
+ cmd = "sudo arping -c 1 -w {} {} {}".format( wait, intfStr, dstIp )
main.log.debug( "Sending IPv4 arping from host {}".format( host ) )
elif self.getIPAddress( host, proto='IPV6' ):
flushCmd = "sudo ip -6 neigh flush all"
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 10a015d..c317fb0 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -442,6 +442,7 @@
return main.TRUE
except pexpect.TIMEOUT:
main.log.exception( self.name + ": TIMEOUT exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
if noExit:
main.cleanup()
return None
@@ -564,11 +565,7 @@
main.log.debug( self.name + ": karafEscape output" )
main.log.debug( self.name + ": " + repr( response ) )
# Remove ANSI color control strings from output
- ansiEscape = re.compile( r'((\x9b|\x1b\[)[0-?]*[ -/]*[@-~])' )
- response = ansiEscape.sub( '', response )
- if debug:
- main.log.debug( self.name + ": ansiEscape output" )
- main.log.debug( self.name + ": " + repr( response ) )
+ response = self.cleanOutput( response, debug )
# Remove ANSI color control strings from output
# NOTE: karaf is sometimes adding a single character then two
@@ -1290,7 +1287,6 @@
main.TRUE if host is discovered on all locations provided
main.FALSE otherwise
"""
- import json
locations = [ location ] if isinstance( location, str ) else location
assert isinstance( locations, list ), "Wrong type of location: {}".format( type( location ) )
try:
@@ -1344,7 +1340,6 @@
main.TRUE if all hosts have specific IP address assigned;
main.FALSE otherwise
"""
- import json
try:
hosts = self.hosts()
hosts = json.loads( hosts )
@@ -1366,6 +1361,8 @@
hostList.remove( hostId )
if hostList:
main.log.warn( self.name + ": failed to verify IP on following hosts: " + str( hostList) )
+ # Print info for debugging
+ main.log.debug( self.name + ": hosts output: " + str( hosts ) )
return main.FALSE
else:
return main.TRUE
@@ -3232,7 +3229,6 @@
Return:
topology = current ONOS topology
"""
- import json
try:
# either onos:topology or 'topology' will work in CLI
topology = json.loads( topologyOutput )
@@ -3265,7 +3261,6 @@
main.FALSE if the number of switches and links is incorrect,
and main.ERROR otherwise
"""
- import json
try:
summary = self.summary()
summary = json.loads( summary )
diff --git a/TestON/drivers/common/cli/onosdriver.py b/TestON/drivers/common/cli/onosdriver.py
index 6e4c71d..a0a8dd1 100755
--- a/TestON/drivers/common/cli/onosdriver.py
+++ b/TestON/drivers/common/cli/onosdriver.py
@@ -2679,7 +2679,7 @@
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
- def onosDiagnostics( self, onosIPs, dstDir, suffix, timeout=300 ):
+ def onosDiagnostics( self, onosIPs, dstDir, suffix, timeout=300, profile="TRELLIS_PROFILE" ):
"""
Run onos-diagnostics with given ONOS instance IPs and save output to dstDir
with suffix specified E.g. onos-diags-suffix.tar.gz
@@ -2691,6 +2691,8 @@
main.FALSE if there's an error executing the command, and main.TRUE otherwise
"""
try:
+ self.handle.sendline( "export DIAGS_PROFILE=%s" % profile )
+ self.handle.expect( self.prompt )
cmd = "onos-diagnostics"
assert isinstance( onosIPs, list )
for ip in onosIPs:
@@ -2894,3 +2896,71 @@
except Exception:
main.log.exception( self.name + ": Uncaught exception!" )
main.cleanAndExit()
+
+ def onosFetchApp( self, url, dstPath=None ):
+ """
+ Fetch an external onos app
+
+ Required:
+ url - url for where to download the app
+ dstPath - where the file will be saved
+
+ Returns main.TRUE on successfully fetching file, and main.FALSE if
+ there is an error.
+ """
+ try:
+ cmd = "wget -q --backups=1 "
+ if dstPath:
+ cmd += "-P %s " % ( dstPath )
+ cmd += str( url )
+ main.log.info( "Sending: " + cmd )
+ main.ONOSbench.handle.sendline( cmd )
+ main.ONOSbench.handle.expect( self.prompt )
+ output = self.handle.before
+ main.log.debug( output )
+ if "Error" in output or "No such file or directory" in output:
+ main.log.error( self.name + ": " + output + self.handle.after )
+ return main.FALSE
+ return main.TRUE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
+ def onosApp( self, onosIP, option, fileName, filePath='~/onos/'):
+ """
+ Wrapper for onos-app script
+
+ Required:
+ - onosIP - The ip address of the onos instance
+ - option - What command are we doing?
+ [ list|install|install!|reinstall|reinstall!|activate|deactivate|uninstall ]
+ - fileName - The name of the app file
+ Optional Arguments:
+ - filePath - The location of the file
+
+ Returns main.TRUE on successfully executing the command, and main.FALSE if
+ there is an error.
+ """
+ # FIXME: Not all options may work, more testing is required, only tested with install(!)
+ try:
+ cmd = "onos-app %s %s %s/%s" % ( onosIP, option, filePath, fileName )
+ main.log.info( "Sending: " + cmd )
+ main.ONOSbench.handle.sendline( cmd )
+ main.ONOSbench.handle.expect( self.prompt )
+ handle = self.handle.before
+ main.log.debug( handle )
+ if "Error" in handle or "usage: " in handle or "curl: " in handle:
+ main.log.error( self.name + ": " + handle + self.handle.after )
+ return main.FALSE
+ return main.TRUE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
diff --git a/TestON/drivers/common/cli/stratumosswitchdriver.py b/TestON/drivers/common/cli/stratumosswitchdriver.py
new file mode 100644
index 0000000..79f1d89
--- /dev/null
+++ b/TestON/drivers/common/cli/stratumosswitchdriver.py
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+"""
+Copyright 2020 Open Networking Foundation (ONF)
+
+Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
+the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
+or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
+
+TestON is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+( at your option ) any later version.
+
+TestON is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with TestON. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import pexpect
+import types
+import os
+from drivers.common.clidriver import CLI
+
+class StratumOSSwitchDriver( CLI ):
+
+ def __init__( self ):
+ """
+ Initialize client
+ """
+ super( CLI, self ).__init__()
+ self.name = None
+ self.shortName = None
+ self.handle = None
+ self.prompt = "~(/TestON)?#"
+ self.dockerPrompt = "/run/stratum#"
+
+ self.home = "/root"
+ # Local home for functions using scp
+ self.tempDirectory = "/tmp/"
+ self.ports = []
+ self.isup = True
+
+ def connect( self, **connectargs ):
+ """
+ Creates ssh handle for cli.
+ """
+ try:
+ # Parse keys in xml object
+ for key in connectargs:
+ vars( self )[ key ] = connectargs[ key ]
+ # Get the name
+ self.name = self.options[ 'name' ]
+ self.shortName = self.options[ 'shortName' ]
+ # Parse the IP address
+ try:
+ if os.getenv( str( self.ip_address ) ) is not None:
+ self.ip_address = os.getenv( str( self.ip_address ) )
+ # Otherwise is an ip address
+ else:
+ main.log.info( self.name + ": Trying to connect to " + self.ip_address )
+ # Error handling
+ except KeyError:
+ main.log.info( "Invalid host name," + " connecting to local host instead" )
+ self.ip_address = 'localhost'
+ except Exception as inst:
+ main.log.error( "Uncaught exception: " + str( inst ) )
+ self.handle = super( StratumOSSwitchDriver, self ).connect(
+ user_name=self.user_name,
+ ip_address=self.ip_address,
+ port=None,
+ pwd=self.pwd)
+ # Successful connection
+ if self.handle:
+ main.log.info( "Connection successful to the host " + self.user_name + "@" + self.ip_address )
+ self.handle.sendline( "" )
+ self.handle.expect( self.prompt )
+ return main.TRUE
+ # Connection failed
+ else:
+ main.log.error( "Connection failed to the host " + self.user_name + "@" + self.ip_address )
+ main.log.error( "Failed to connect to the Stratum Switch" )
+ return main.FALSE
+ # Error handling
+ except TypeError:
+ main.log.exception( self.name + ": Object not as expected" )
+ return None
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanup()
+ main.exit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanup()
+ main.exit()
+
+ def disconnect( self ):
+ """
+ Called when Test is complete to disconnect the component handle.
+ """
+ response = main.TRUE
+ try:
+ if self.handle:
+ # Stop the agent
+ self.stopSwitchAgent()
+ main.log.debug( self.name + ": Disconnected" )
+ # Disconnect from the device
+ self.handle.sendline( "" )
+ self.handle.expect( self.prompt )
+ self.handle.sendline( "exit" )
+ self.handle.expect( "closed" )
+ # Errors handling
+ except pexpect.TIMEOUT:
+ main.log.error( self.name + ": pexpect.TIMEOUT found" )
+ main.log.debug( self.handle.before )
+ return main.FALSE
+ except TypeError:
+ main.log.exception( self.name + ": Object not as expected" )
+ response = main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ except ValueError:
+ main.log.exception( "Exception in disconnect of " + self.name )
+ response = main.TRUE
+ except Exception:
+ main.log.exception( self.name + ": Connection failed to the host" )
+ response = main.FALSE
+ return response
+
+ def assignSwController( self, ip, updateConf=True, **kwargs ):
+ """
+ Description:
+ Edit the config file for the switch and upload it to the onos
+ controller to connect the switch and controller
+
+ NOTE that this function is available on all switch drivers,
+ and the name is a hold over from ovs switches.
+ kwargs contains any arguments for other types of switches
+ Required:
+ ip - Ip addresses of controllers. This can be a list or a string.
+ updateConf - whether to pull and update configurations and scripts
+ Return:
+ Returns main.TRUE if the switch is correctly assigned to controllers,
+ otherwise it will return main.FALSE or an appropriate exception(s)
+ """
+ assignResult = main.TRUE
+ onosIp = ""
+ # Parses the controller option
+ # We only need one onos ip
+ try:
+ if isinstance( ip, types.StringType ):
+ onosIp = str( ip )
+ elif isinstance( ip, types.ListType ):
+ onosIp = ip[ 0 ]
+ else:
+ main.log.error( self.name + ": Invalid controller ip address" )
+ return main.FALSE
+ if updateConf:
+ self.setupContainer()
+ main.ONOSbench.onosNetCfg( onosIp, self.options[ 'onosConfigPath' ], self.options[ 'onosConfigFile' ] )
+
+ assignResult = self.startSwitchAgent()
+ if not assignResult:
+ self.isup = False
+ else:
+ self.isup = True
+ # Done return true
+ return assignResult
+ # Errors handling
+ except pexpect.TIMEOUT:
+ main.log.error( self.name + ": pexpect.TIMEOUT found" )
+ return main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
+ def setupContainer( self ):
+ """
+ Prepare for the container to be run. Includes pulling scripts
+ and modifying them
+ """
+ try:
+ #TODO Remove hardcoding
+ main.log.info( "Creating working directory" )
+ self.handle.sendline( "mkdir TestON" )
+ self.handle.expect( self.prompt )
+ self.handle.sendline( "cd TestON" )
+ self.handle.expect( self.prompt )
+
+ main.log.info( "Getting start container script" )
+ # TODO: Parameterize this
+ self.handle.sendline( "wget --backups=1 https://raw.githubusercontent.com/stratum/stratum/master/stratum/hal/bin/barefoot/docker/start-stratum-container.sh" )
+ self.handle.expect( self.prompt )
+ main.log.info( "Modify start container script" )
+ self.handle.sendline( "sed -i '/--privileged/a \ --name stratum \\\\' start-stratum-container.sh" )
+ self.handle.expect( self.prompt )
+ #self.handle.sendline( "sed -i '/LOG_DIR:\/var\/log\/stratum/a \ --entrypoint /bin/bash \\\\' start-stratum-container.sh" )
+ #self.handle.expect( self.prompt )
+ # TODO: Add docker pull command to the start-stratum-container.sh script
+
+ main.log.info( "Getting chassis config" )
+ # TODO: Parameterize this
+ self.handle.sendline( "wget --backups=1 https://raw.githubusercontent.com/stratum/stratum/master/stratum/hal/config/x86-64-accton-wedge100bf-32x-r0/chassis_config.pb.txt" )
+ self.handle.expect( self.prompt )
+ main.log.info( "Modify chassis config" )
+ # TODO: Parameterize this
+ self.handle.sendline( "sed -i '$!N;s/\(port: [5|6]\\n\ speed_bps: \)\([0-9]*\)/\\1 40000000000/;P;D' chassis_config.pb.txt" )
+ self.handle.expect( self.prompt )
+ self.handle.sendline( "export CHASSIS_CONFIG=~/TestON/chassis_config.pb.txt" )
+ self.handle.expect( self.prompt )
+ self.handle.sendline( "chmod +x start-stratum-container.sh" )
+ self.handle.expect( self.prompt )
+ except pexpect.TIMEOUT:
+ main.log.error( self.name + ": pexpect.TIMEOUT found" )
+ main.log.debug( self.handle.before )
+ return main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
+ def startSwitchAgent( self ):
+ """
+ Start the stratum agent on the device
+ """
+ try:
+ main.log.info( "Starting switch agent" )
+ self.handle.sendline( "./start-stratum-container.sh --bf-sim" )
+ self.handle.expect( "Chassis config pushed successfully." )
+ return main.TRUE
+ except pexpect.TIMEOUT:
+ main.log.error( self.name + ": pexpect.TIMEOUT found" )
+ main.log.debug( self.handle.before )
+ return main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()
+
+ def stopSwitchAgent( self ):
+ """
+ Stop the strratum agent on the device
+ """
+ try:
+ main.log.info( self.name + ": stopping Stratum Switch agent" )
+ while True:
+ self.handle.sendline( "" )
+ i = self.handle.expect( [ self.prompt, self.dockerPrompt, pexpect.TIMEOUT, "Aborted at" ] )
+ if i == 2:
+ self.handle.send( "\x03" ) # ctrl-c to close switch agent
+ self.handle.sendline( "" )
+ elif i == 1:
+ self.handle.sendline( "exit" ) # exit docker
+ self.handle.expect( self.prompt )
+ elif i == 0:
+ self.handle.sendline( "docker stop stratum" ) # Make sure the container is stopped
+ self.handle.expect( self.prompt )
+ main.log.debug( self.name + ": Stratum Switch agent stopped" )
+ return
+ elif i == 3:
+ main.log.error( "Stratum agent aborted" )
+ # TODO: Find and save any extra logs
+ output = self.handle.before + self.handle.after
+ self.handle.sendline( "" )
+ self.handle.expect( self.prompt )
+ output += self.handle.before + self.handle.after
+ main.log.debug( output )
+ main.cleanAndExit()
+ except pexpect.TIMEOUT:
+ main.log.error( self.name + ": pexpect.TIMEOUT found" )
+ main.log.debug( self.handle.before )
+ return main.FALSE
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanAndExit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanAndExit()