blob: 4ff3a85a265093c006bbb7aa805594350c7f102a [file] [log] [blame]
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jon Hall1efcb3f2016-08-23 13:42:15 -070021import os
Jon Hall1efcb3f2016-08-23 13:42:15 -070022import time
23import json
24import urllib
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -070025import re
Jon Hallf6aeda22020-07-28 09:12:56 -070026import pexpect
Jon Hall1efcb3f2016-08-23 13:42:15 -070027from core import utilities
28
29
30class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070031
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070032 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070033
Jon Hall1efcb3f2016-08-23 13:42:15 -070034 @staticmethod
35 def initTest( main ):
36 """
37 - Construct tests variables
38 - GIT ( optional )
39 - Checkout ONOS master branch
40 - Pull latest ONOS code
41 - Building ONOS ( optional )
42 - Install ONOS package
43 - Build ONOS package
44 """
Devin Lim58046fa2017-07-05 16:55:00 -070045 try:
46 from tests.dependencies.ONOSSetup import ONOSSetup
47 main.testSetUp = ONOSSetup()
48 except ImportError:
49 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070050 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080051 from tests.dependencies.Network import Network
Jon Hall627b1572020-12-01 12:01:15 -080052 main.persistentSetup = main.params.get( "persistent_setup" )
You Wangd5873482018-01-24 12:30:00 -080053 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070054 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080055 main.testSetUp.envSetupDescription( False )
Jon Hall39570262020-11-17 12:18:19 -080056 main.logdirBase = main.logdir
Devin Lim58046fa2017-07-05 16:55:00 -070057 stepResult = main.FALSE
58 try:
Devin Lim58046fa2017-07-05 16:55:00 -070059 # Test variables
60 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
61 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070062 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080063 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
64 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
65 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080066 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
67 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
68 else:
69 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070070 if main.useBmv2:
71 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
72 else:
73 main.switchType = "ovs"
74
Devin Lim57221b02018-02-14 15:45:36 -080075 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070076 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080077 main.forJson = "json/"
Siddeshde1d1692021-09-15 18:12:57 +000078 # main.forcfg = "netcfg/"
Devin Lim57221b02018-02-14 15:45:36 -080079 main.forChart = "chart/"
80 main.forConfig = "conf/"
81 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080082 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080083 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070084 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070085 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080086 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
87 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080088 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070089 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070090 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070091 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070092 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070093 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070094
Devin Lim0c972b72018-02-08 14:53:59 -080095 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070096 except Exception as e:
97 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070098
Jon Hallaa1d9b82020-07-30 13:49:42 -070099 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall32c90f32021-06-24 16:32:44 -0700100
Siddesh167bc882021-03-23 21:03:43 +0000101 @staticmethod
102 def getTopo():
103 topo = dict()
104 # TODO: Check minFlowCount of leaf for BMv2 switch
105 # (number of spine switch, number of leaf switch, dual-homed, description, minFlowCount - leaf (OvS), minFlowCount - leaf (BMv2))
106 topo[ '0x1' ] = { 'spines': 0,'leaves': 1, 'mininetArgs': "--leaf=1 --spine=0", 'dual-homed': False,'description': 'single ToR','minFlow-OvS': 28,'minFlow-Stratum': 20,'dual-linked': False }
107 topo[ '0x2' ] = {'spines': 0,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=0", 'dual-homed': True,'description': 'dual-homed ToR','minFlow-OvS': 37,'minFlow-Stratum': 37,'dual-linked': True }
108 topo[ '2x2' ] = {'spines': 2,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 leaf-spine topology','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': False }
109 topo[ '2x2 dual-linked' ] = {'spines': 2, 'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 aether dual-linked','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': True }
110 topo[ '2x4' ] = { 'spines':2,'leaves': 4, 'mininetArgs': "--leaf=4 --spine=2",'dual-homed': True,'description': '2x4 dual-homed leaf-spine topology','minFlow-OvS': 53,'minFlow-Stratum': 53, 'dual-linked': False }
111 topo[ '4x4' ] = {'spines': 4,'leaves': 4, 'dual-homed': True, 'description': '4x4 dual-homed leaf-spine topology','dual-linked': True }
112 topo[ '2x2staging' ] = { 'spines': 2, 'leaves': 2,'dual-homed': True, 'description': '2x2 leaf-spine topology', 'minFlowOvS': 37, 'minFlow-Stratum': 32 }
113 return topo
Jon Hall1efcb3f2016-08-23 13:42:15 -0700114 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800115 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
116 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700117 """
118 - Set up cell
119 - Create cell file
120 - Set cell file
121 - Verify cell file
122 - Kill ONOS process
123 - Uninstall ONOS cluster
124 - Verify ONOS start up
125 - Install ONOS cluster
126 - Connect to cli
127 """
Siddesh13492972021-03-12 21:09:32 +0000128 # Check params file for local repos on external apps. cd to repos, run the build command, potentially move o/p file to a different location
129
Jon Hall1efcb3f2016-08-23 13:42:15 -0700130 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700131 try:
Jon Hall627b1572020-12-01 12:01:15 -0800132 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700133 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800134 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700135 main.ONOSbench.onosFetchApp( url )
136 if not main.apps:
137 main.log.error( "App list is empty" )
138 except Exception as e:
139 main.log.debug( e )
140 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800141 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
142 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700143 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800144 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800145 skipPack=skipPackage,
146 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800147 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700148 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700149 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800150 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700151 attempts=10 )
152 if ready:
153 ready = main.TRUE
154 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700155 onpass="ONOS summary command succeded",
156 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700157 if not ready:
158 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700159 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700160
You Wang5bf49592020-07-08 18:47:46 -0700161 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700162 appInstallResult = main.TRUE
163 if main.trellisOar:
164 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700165 if main.t3Oar:
166 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
167 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
168 onpass="SR app installation succeded",
169 onfail="SR app installation failed" )
170 if not appInstallResult:
171 main.cleanAndExit()
172
Jon Hall43060f62020-06-23 13:13:33 -0700173 # FIXME: move to somewhere else?
174 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
175 # TODO: Support other pipeconfs/making this configurable
176 if switchPrefix == "tofino":
177 # It seems to take some time for the pipeconfs to be loaded
178 ctrl = main.Cluster.next()
179 for i in range( 120 ):
180 try:
181 main.log.debug( "Checking to see if pipeconfs are loaded" )
182 output = ctrl.CLI.sendline( "pipeconfs" )
183 if "tofino" in output:
184 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
185 break
186 time.sleep( 1 )
187 except Exception as e:
188 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700189
Jon Hall627b1572020-12-01 12:01:15 -0800190 # Install segmentrouting and t3 app
191 appInstallResult = main.TRUE
192 if not main.persistentSetup:
193 if main.trellisOar:
194 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
195 if main.t3Oar:
196 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
197 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
198 onpass="SR app installation succeded",
199 onfail="SR app installation failed" )
200 if not appInstallResult:
201 main.cleanAndExit()
202
Jon Hall43060f62020-06-23 13:13:33 -0700203 Testcaselib.setOnosLogLevels( main )
204 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700205
Jon Hall1efcb3f2016-08-23 13:42:15 -0700206 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800207 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700208 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
209 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800210
211 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700212 def loadJson( main, suffix='' ):
213 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
214 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800215 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
216
217 @staticmethod
Siddesh606bd872021-06-29 23:42:36 +0000218 def loadNewJson( main, suffix='' ):
219 returnValue = main.TRUE
Siddeshde1d1692021-09-15 18:12:57 +0000220 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
Siddesh606bd872021-06-29 23:42:36 +0000221 main.cfgName, suffix ) ) as cfg:
222 desiredJSON = json.load ( cfg )
223 for device in desiredJSON ["ports"].keys():
224 deviceCfg = desiredJSON[ "ports" ][ device ]
225 currentJSON = main.Cluster.active( 0 ).REST.getNetCfg( subjectClass = "ports", subjectKey = device )
226
227 currentJSON = json.loads( currentJSON )
228 if currentJSON['interfaces'][0]['ips'] != deviceCfg['interfaces'][0]['ips']:
Siddeshd9840842021-08-06 19:26:05 +0000229 currentJSON['interfaces'][0]['ips'] = deviceCfg['interfaces'][0]['ips']
Siddesh606bd872021-06-29 23:42:36 +0000230 data = { 'interfaces': currentJSON['interfaces'] }
231 A = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
232 returnValue = returnValue and A
233 currentJSON['interfaces'] = deviceCfg['interfaces']
234 data = { 'interfaces': currentJSON['interfaces'] }
235 B = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
236 returnValue = returnValue and B
237 return returnValue
238
239 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700240 def loadXconnects( main, suffix='' ):
241 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
242 main.cfgName, suffix ) ) as cfg:
243 for xconnect in json.load( cfg ).get('xconnects'):
244 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
245
246 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800247 def loadChart( main ):
248 try:
Jon Hall32c90f32021-06-24 16:32:44 -0700249 filename = "%s%s.chart" % ( main.configPath + main.forChart,
250 main.cfgName )
251 with open( filename ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700252 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800253 except IOError:
Jon Hall32c90f32021-06-24 16:32:44 -0700254 main.log.warn( "No chart file found at %s" % filename )
Devin Lim57221b02018-02-14 15:45:36 -0800255
256 @staticmethod
257 def loadHost( main ):
258 with open( "%s%s.host" % ( main.configPath + main.forHost,
259 main.cfgName ) ) as host:
260 main.expectedHosts = json.load( host )
261
262 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800263 def loadSwitchFailureChart( main ):
264 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
265 main.cfgName ) ) as sfc:
266 main.switchFailureChart = json.load( sfc )
267
268 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800269 def loadLinkFailureChart( main ):
270 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700271 main.cfgName ) ) as lfc:
272 main.linkFailureChart = json.load( lfc )
273
274 @staticmethod
275 def loadMulticastConfig( main ):
276 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
277 main.cfgName ) ) as cfg:
278 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800279
280 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700281 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700282 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800283 copyResult = main.ONOSbench.scp( main.Mininet1,
284 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700285 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800286 direction="to" )
287 if main.topologyLib:
288 for lib in main.topologyLib.split(","):
289 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
290 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700291 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800292 direction="to" )
293 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700294 import re
295 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
296 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700297 destDir = "~/"
298 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
299 destDir = "/tmp/mn_conf/"
300 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800301 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700302 # Update zebra configurations with correct ONOS instance IP
303 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
304 ip = controllerIPs[ index ]
305 index = ( index + 1 ) % len( controllerIPs )
306 with open( main.configPath + main.forConfig + conf ) as f:
307 s = f.read()
308 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
309 with open( main.configPath + main.forConfig + conf, "w" ) as f:
310 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800311 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800312 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700313 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800314 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800315 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700316 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800317 main.Mininet1.home + "custom",
318 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700319
320 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
321 # move the config files into home
322 main.Mininet1.handle.sendline( "cp config/* . " )
323 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
324 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
325 main.Mininet1.handle.sendline( "ls -al " )
326 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
327 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
328
You Wangd87b2312018-01-30 12:47:17 -0800329 stepResult = copyResult
330 utilities.assert_equals( expect=main.TRUE,
331 actual=stepResult,
332 onpass="Successfully copied topo files",
333 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700334 if main.stratumRoot:
335 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700336 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700337 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700338 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700339 main.topology = topology
340 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700341 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700342 stepResult = topoResult
343 utilities.assert_equals( expect=main.TRUE,
344 actual=stepResult,
345 onpass="Successfully loaded topology",
346 onfail="Failed to load topology" )
347 # Exit if topology did not load properly
348 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700349 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700350 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700351 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700352 # Upload the net-cfg file created for each switch
353 filename = "onos-netcfg.json"
354 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700355 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700356 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
357 path = "/tmp/mn-stratum/%s/" % switch
358 dstPath = "/tmp/"
359 dstFileName = "%s-onos-netcfg.json" % switch
360 main.ONOSbench1.scp( main.Mininet1,
361 "%s%s" % ( path, filename ),
362 "%s%s" % ( dstPath, dstFileName ),
363 "from" )
364 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700365 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700366 # Configure managementAddress
367 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
368 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
369 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
370 # Configure device id
371 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
372 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
373 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
374 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800375 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s:%s\",' %s%s" % ( switchPrefix, switch, dstPath, dstFileName ) )
Jon Hall43060f62020-06-23 13:13:33 -0700376 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
377 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700378 node = main.Cluster.active(0)
379 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
380 dstPath,
381 dstFileName,
382 user=node.REST.user_name,
383 password=node.REST.pwd )
384 # Stop test if we fail to push switch netcfg
385 utilities.assert_equals( expect=main.TRUE,
386 actual=switchNetCfg,
387 onpass="Successfully pushed switch netcfg",
388 onfail="Failed to configure switches in onos" )
389 if not switchNetCfg:
390 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700391 # Make sure hosts make some noise
392 Testcaselib.discoverHosts( main )
393
394 @staticmethod
395 def discoverHosts( main ):
396 # TODO add option to only select specific hosts
397 if hasattr( main, "Mininet1" ):
398 network = main.Mininet1
399 elif hasattr( main, "NetworkBench" ):
400 network = main.NetworkBench
401 else:
402 main.log.warn( "Could not find component for test network, skipping host discovery" )
403 return
404 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700405
406 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800407 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800408 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700409 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800410 topoResult = main.NetworkBench.connectToNet()
411 stepResult = topoResult
412 utilities.assert_equals( expect=main.TRUE,
413 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700414 onpass="Successfully connected to topology",
415 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800416 # Exit if topology did not load properly
417 if not topoResult:
418 main.cleanAndExit()
419
Jon Hall627b1572020-12-01 12:01:15 -0800420 if not main.persistentSetup:
421 # Perform any optional setup
422 for switch in main.NetworkBench.switches:
423 if hasattr( switch, "setup" ):
424 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700425
Jon Hall627b1572020-12-01 12:01:15 -0800426 main.step( "Assign switches to controllers." )
427 stepResult = main.TRUE
428 switches = main.NetworkBench.getSwitches()
429 pool = []
430 for name in switches.keys():
431 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
432 # e.g. push onos net-cfg for stratum switches
433 thread = main.Thread( target=main.NetworkBench.assignSwController,
434 name="assignSwitchToController",
435 args=[ name, main.Cluster.getIps(), '6653' ] )
436 pool.append( thread )
437 thread.start()
438 for thread in pool:
439 thread.join( 300 )
440 if not thread.result:
441 stepResult = main.FALSE
442 utilities.assert_equals( expect=main.TRUE,
443 actual=stepResult,
444 onpass="Successfully assign switches to controllers",
445 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800446
You Wang4cc61912018-08-28 10:10:58 -0700447 # Check devices
448 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700449 # Connecting to hosts that only have data plane connectivity
450 main.step( "Connecting inband hosts" )
451 stepResult = main.Network.connectInbandHosts()
452 utilities.assert_equals( expect=main.TRUE,
453 actual=stepResult,
454 onpass="Successfully connected inband hosts",
455 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800456 if hostDiscovery:
457 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700458
You Wang84f981d2018-01-12 16:11:50 -0800459 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700460 def saveOnosDiagnostics( main ):
461 """
462 Get onos-diags.tar.gz and save it to the log directory.
463 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
464 """
465 main.log.info( "Collecting onos-diags..." )
Siddesha2938fe2021-04-06 02:46:06 +0000466 for ctrl in main.Cluster.runningNodes:
467 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir,"-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
You Wang5df1c6d2018-04-06 18:02:02 -0700468
469 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700470 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700471 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700472
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700473 main.failures = int( main.params[ 'failures' ] )
474 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700475
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700476 if main.cfgName == '2x2':
477 spine = {}
478 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
479 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
480 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700481
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700482 spine = {}
483 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
484 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
485 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700486
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700487 elif main.cfgName == '4x4':
488 spine = {}
489 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
490 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
491 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700492
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700493 spine = {}
494 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
495 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
496 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700497
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700498 spine = {}
499 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
500 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
501 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700502
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700503 spine = {}
504 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
505 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
506 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700507
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700508 else:
Piera2a7e1b2016-10-04 11:51:43 -0700509 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700510 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800511
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800512 @staticmethod
513 def addStaticOnosRoute( main, subnet, intf):
514 """
515 Adds an ONOS static route with the use route-add command.
516 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800517 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
518
Piera2a7e1b2016-10-04 11:51:43 -0700519 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700520 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700521 """
522 Check number of groups for each subnet on device deviceId and matches
523 it with an expected value. subnetDict is a dictionarty containing values
524 of the type "10.0.1.0/24" : 5.
525 """
You Wangc02f3be2018-05-18 12:14:23 -0700526 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
527 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
528 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700529
You Wangc02f3be2018-05-18 12:14:23 -0700530 result = main.TRUE
531 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700532 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700533 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700534 # this will match the group id that this flow entry points to, for example :
535 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700536 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700537 count = 0
538 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700539 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700540 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700541 if count - 1 != numberInSelect:
542 result = main.FALSE
543 main.log.warn( "Mismatch in number of buckets of select group, found {0}, expected {1} for subnet {2} on device {3}".format( count - 1, numberInSelect, subnet, deviceId ) )
544 utilities.assert_equals( expect=main.TRUE, actual=result,
545 onpass="All bucket numbers are as expected",
546 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700547
548 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700549 def checkFlows( main, minFlowCount, tag="", dumpFlows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700550 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800551 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900552 if tag == "":
553 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700554 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700555 main.FALSE,
556 kwargs={ 'min': minFlowCount },
557 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800558 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800559 if count == main.FALSE:
560 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700561 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700562 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800563 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700564 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
565 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700566
567 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700568 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700569 main.FALSE,
570 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800571 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800572 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700573 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700574 expect=main.TRUE,
575 actual=flowCheck,
576 onpass="Flow status is correct!",
577 onfail="Flow status is wrong!" )
Jon Hall32c90f32021-06-24 16:32:44 -0700578 if dumpFlows:
Devin Lim142b5342017-07-20 15:22:39 -0700579 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700580 "flows",
581 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800582 tag + "_FlowsBefore",
583 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700584 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700585 "groups",
586 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800587 tag + "_GroupsBefore",
588 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700589
590 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700591 def checkDevices( main, switches, tag="", sleep=10 ):
592 main.step(
593 "Check whether the switches count is equal to %s" % switches )
594 if tag == "":
595 tag = 'CASE%d' % main.CurrentTestCaseNumber
596 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
597 main.FALSE,
598 kwargs={ 'numoswitch': switches},
599 attempts=10,
600 sleep=sleep )
601 utilities.assert_equals( expect=main.TRUE, actual=result,
602 onpass="Device up successful",
603 onfail="Failed to boot up devices?" )
604
605 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800606 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
607 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800608 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800609 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
610 main.FALSE,
611 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800612 attempts=5,
613 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800614 if count == main.FALSE:
615 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800616 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800617 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800618 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800619 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800620 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800621
622 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700623 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800624 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700625 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800626 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
627 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700628 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800629 attempts=5,
630 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800631 if count == main.FALSE:
632 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800633 utilities.assertEquals(
634 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800635 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700636 onpass="Flow count looks correct: " + str( count ) ,
637 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800638
639 @staticmethod
640 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
641 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700642 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800643 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
644 main.FALSE,
645 args=( dpid, groupCount, False, 1),
646 attempts=5,
647 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800648 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800649 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800650 utilities.assertEquals(
651 expect=True,
652 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700653 onpass="Group count looks correct: " + str( count ) ,
654 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800655
656 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700657 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800658
659 for dpid, values in main.count.items():
660 flowCount = values["flows"]
661 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700662 main.log.report( "Check flow count for dpid " + str( dpid ) +
663 ", should be " + str( flowCount ) )
664 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800665
Jon Hall9677ed32018-04-24 11:16:23 -0700666 main.log.report( "Check group count for dpid " + str( dpid ) +
667 ", should be " + str( groupCount ) )
668 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800669
670 return
671
672 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700673 def pingAll( main, tag="", dumpFlows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800674 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800675 '''
You Wangba231e72018-03-01 13:18:21 -0800676 Verify connectivity between hosts according to the ping chart
677 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800678 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800679 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800680 '''
You Wangba231e72018-03-01 13:18:21 -0800681 main.log.report( "Check host connectivity" )
682 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800683 if tag == "":
684 tag = 'CASE%d' % main.CurrentTestCaseNumber
685 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800686 main.log.debug( "Entry in ping chart: %s" % entry )
687 expect = entry[ 'expect' ]
688 if expect == "Unidirectional":
689 # Verify ping from each src host to each dst host
690 src = entry[ 'src' ]
691 dst = entry[ 'dst' ]
692 expect = main.TRUE
693 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
694 if basedOnIp:
695 if ("v4" in src[0]):
696 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
697 utilities.assert_equals( expect=expect, actual=pa,
698 onpass="IPv4 connectivity successfully tested",
699 onfail="IPv4 connectivity failed" )
700 if ("v6" in src[0]):
701 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
702 utilities.assert_equals( expect=expect, actual=pa,
703 onpass="IPv6 connectivity successfully tested",
704 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700705 elif main.physicalNet:
706 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
707 utilities.assert_equals( expect=expect, actual=pa,
708 onpass="IP connectivity successfully tested",
709 onfail="IP connectivity failed" )
710
You Wangba231e72018-03-01 13:18:21 -0800711 else:
712 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
713 utilities.assert_equals( expect=expect, actual=pa,
714 onpass="IP connectivity successfully tested",
715 onfail="IP connectivity failed" )
716 else:
717 # Verify ping between each host pair
718 hosts = entry[ 'hosts' ]
719 try:
720 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
721 except:
722 expect = main.FALSE
723 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
724 if basedOnIp:
725 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800726 pa = utilities.retry( main.Network.pingallHosts,
727 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700728 args=(hosts, ),
729 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800730 attempts=retryAttempts,
731 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800732 utilities.assert_equals( expect=expect, actual=pa,
733 onpass="IPv4 connectivity successfully tested",
734 onfail="IPv4 connectivity failed" )
735 if ("v6" in hosts[0]):
736 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
737 utilities.assert_equals( expect=expect, actual=pa,
738 onpass="IPv6 connectivity successfully tested",
739 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700740 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800741 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700742 utilities.assert_equals( expect=expect, actual=pa,
743 onpass="IP connectivity successfully tested",
744 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800745 else:
You Wangf19d9f42018-02-23 16:34:19 -0800746 pa = main.Network.pingallHosts( hosts )
747 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800748 onpass="IP connectivity successfully tested",
749 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700750 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700751 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700752 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700753 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700754 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800755
Jon Hall32c90f32021-06-24 16:32:44 -0700756 if dumpFlows:
757 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
758 "flows",
759 main.logdir,
760 tag + "_FlowsOn",
761 cliPort=main.Cluster.active(0).CLI.karafPort )
762 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
763 "groups",
764 main.logdir,
765 tag + "_GroupsOn",
766 cliPort=main.Cluster.active(0).CLI.karafPort )
767
768 @staticmethod
769 def pingAllFabricIntfs( main, srcList, tag="", dumpFlows=True, skipOnFail=False ):
770 '''
771 Verify connectivity between hosts and their fabric interfaces
772 '''
773 main.log.report( "Check host connectivity with fabric" )
774 if tag == "":
775 tag = 'CASE%d' % main.CurrentTestCaseNumber
776 expect = main.TRUE
777 import json
778 import re
779 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
780 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
781 for hostname in srcList:
782 try:
783 hostComponent = main.Network.hosts[ str( hostname ) ]
784 srcIface = hostComponent.interfaces[0].get( 'name' )
785 main.step( "Verify fabric connectivity for %s with tag %s" % ( str( hostname ), tag ) )
786 #Get host location, check netcfg for that port's ip
787 hostIp = hostComponent.getIPAddress( iface=srcIface )
788 main.log.warn( "Looking for %s" % hostIp )
789 ips = []
790 for obj in hostsJson:
791 if hostIp in obj['ipAddresses']:
792 for location in obj['locations']:
793 main.log.debug( location )
794 did = location['elementId'].encode( 'utf-8' )
795 port = location['port'].encode( 'utf-8' )
796 m = re.search( '\((\d+)\)', port )
797 if m:
798 port = m.group(1)
799 portId = "%s/%s" % ( did, port )
800 # Lookup ip assigned to this network port
801 ips.extend( [ x.encode( 'utf-8' ) for x in netcfgJson[ portId ][ 'interfaces' ][0][ 'ips' ] ] )
802 ips = set( ips )
803 ipRE = r'(\d+\.\d+\.\d+\.\d+)/\d+|([\w,:]*)/\d+'
804 for ip in ips:
805 ipMatch = re.search( ipRE, ip )
806 if ipMatch:
807 fabricIntfIp = ipMatch.group(1)
808 main.log.debug( "Found %s as gateway ip for %s" % ( fabricIntfIp, hostname ) )
809 pa = hostComponent.ping( fabricIntfIp, interface=srcIface )
810 utilities.assert_equals( expect=expect, actual=pa,
811 onpass="IP connectivity successfully tested",
812 onfail="IP connectivity failed" )
813 if pa != expect:
814 Testcaselib.saveOnosDiagnostics( main )
815 if skipOnFail:
816 Testcaselib.cleanup( main, copyKarafLog=False )
817 main.skipCase()
818 except ValueError:
819 main.log.exception( "Could not get gateway ip for %s" % hostname )
820
821 if dumpFlows:
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800822 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
823 "flows",
824 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800825 tag + "_FlowsOn",
826 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800827 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
828 "groups",
829 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800830 tag + "_GroupsOn",
831 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800832
833 @staticmethod
Jon Hall326501b2021-08-31 10:14:55 -0700834 def populateHostsVlan( main, hostList ):
835 """
836 Set the vlan for each host.
837 Checks what interface the host is configured on and reads the netcfg for that interface
838 """
839 import json
840 import re
841 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
842 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
843 for hostname in hostList:
844 try:
845 hostComponent = main.Network.hosts[ str( hostname ) ]
846 srcIface = hostComponent.interfaces[0].get( 'name' )
847 #Get host location, check netcfg for that port's ip
848 hostIp = hostComponent.getIPAddress( iface=srcIface )
Siddeshde1d1692021-09-15 18:12:57 +0000849 if not hostIp:
850 hostIp=hostComponent.interfaces[0].get( 'ips' )[0]
Jon Hall326501b2021-08-31 10:14:55 -0700851 main.log.warn( "Looking for allowed vlans for %s" % hostIp )
852 vlans = []
853 for obj in hostsJson:
854 if hostIp in obj['ipAddresses']:
855 for location in obj['locations']:
856 did = location['elementId'].encode( 'utf-8' )
857 port = location['port'].encode( 'utf-8' )
858 m = re.search( '\((\d+)\)', port )
859 if m:
860 port = m.group(1)
861 portId = "%s/%s" % ( did, port )
862 # Lookup ip assigned to this network port
863 # Valid host vlans:
864 # None if vlan-untagged
865 # vlanid if vlan-tagged: vlanid
866 # None if vlan-native + any vlan ids from vlan-tagged
867 intf = netcfgJson[ portId ][ 'interfaces' ][0]
Siddeshde1d1692021-09-15 18:12:57 +0000868 main.log.debug( intf )
Jon Hall326501b2021-08-31 10:14:55 -0700869 for field in intf.keys():
870 if "vlan-untagged" in field:
871 vlans.append( None )
872 if "vlan-tagged" in field:
Siddeshde1d1692021-09-15 18:12:57 +0000873 for VLAN in intf[ field ]:
874 vlans.append( VLAN )
Jon Hall326501b2021-08-31 10:14:55 -0700875 if "vlan-native" in field:
876 vlans.append( None )
877 if len( vlans ) == 0:
878 main.log.debug( "Could not find vlan setting for %s" % hostname )
879 vlans = set( vlans )
Siddeshd9840842021-08-06 19:26:05 +0000880 hostComponent.interfaces[0][ 'vlan' ] = list( vlans )
Jon Hall326501b2021-08-31 10:14:55 -0700881 main.log.debug( repr( hostComponent.interfaces[0] ) )
882 main.log.debug( repr( hostComponent.interfaces[0].get( 'vlan' ) ) )
883 except ValueError:
884 main.log.exception( "Error getting vlans for %s" % hostname )
885
886
887 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700888 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700889 """
890 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
891 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
892 Kill a link and verify ONOS can see the proper link change
893 """
Jon Halla604fd42018-05-04 14:27:27 -0700894 if sleep is None:
895 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
896 else:
897 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700898 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700899 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
900 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700901 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
902 onpass="Link down successful",
903 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700904 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700905 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700906 "Waiting %s seconds for link down to be discovered" % sleep )
907 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700908 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700909 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700910 main.FALSE,
911 kwargs={ 'numoswitch': switches,
912 'numolink': links },
913 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700914 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700915 utilities.assert_equals( expect=main.TRUE, actual=topology,
916 onpass="Topology after link down is correct",
917 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700918
919 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700920 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800921 """
922 links = list of links (src, dst) to bring down.
923 """
924
925 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700926 if sleep is None:
927 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
928 else:
929 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800930
931 for end1, end2 in links:
932 main.Network.link( END1=end1, END2=end2, OPTION="down")
933 main.Network.link( END1=end2, END2=end1, OPTION="down")
934
Jon Halla604fd42018-05-04 14:27:27 -0700935 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800936 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700937 "Waiting %s seconds for links down to be discovered" % sleep )
938 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800939
940 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
941 main.FALSE,
942 kwargs={ 'numoswitch': switches,
943 'numolink': linksAfter },
944 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700945 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800946
You Wang2854bce2018-03-30 10:15:32 -0700947 utilities.assert_equals( expect=main.TRUE, actual=topology,
948 onpass="Link batch down successful",
949 onfail="Link batch down failed" )
950
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800951 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700952 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800953 """
954 links = list of link (src, dst) to bring up again.
955 """
956
957 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700958 if sleep is None:
959 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
960 else:
961 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800962
963 for end1, end2 in links:
964 main.Network.link( END1=end1, END2=end2, OPTION="up")
965 main.Network.link( END1=end2, END2=end1, OPTION="up")
966
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800967 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700968 "Waiting %s seconds for links up to be discovered" % sleep )
969 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800970
971 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
972 main.FALSE,
973 kwargs={ 'numoswitch': switches,
974 'numolink': linksAfter },
975 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700976 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800977
You Wang2854bce2018-03-30 10:15:32 -0700978 utilities.assert_equals( expect=main.TRUE, actual=topology,
979 onpass="Link batch up successful",
980 onfail="Link batch up failed" )
981
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800982 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700983 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
984 """
985 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
986 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
987 switches, links: number of expected switches and links after link change, ex.: '4', '6'
988 """
989 if sleep is None:
990 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
991 else:
992 sleep = float( sleep )
993 main.step( "Disable a batch of ports" )
994 for dpid, port in ports:
995 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
996 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
997 time.sleep( sleep )
998 if switches and links:
999 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1000 numolink=links )
1001 utilities.assert_equals( expect=main.TRUE, actual=result,
1002 onpass="Port down successful",
1003 onfail="Port down failed" )
1004
1005 @staticmethod
1006 def enablePortBatch( main, ports, switches, links, sleep=None ):
1007 """
1008 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1009 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
1010 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1011 """
1012 if sleep is None:
1013 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1014 else:
1015 sleep = float( sleep )
1016 main.step( "Enable a batch of ports" )
1017 for dpid, port in ports:
1018 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
1019 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
1020 time.sleep( sleep )
1021 if switches and links:
1022 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1023 numolink=links )
1024 utilities.assert_equals( expect=main.TRUE, actual=result,
1025 onpass="Port up successful",
1026 onfail="Port up failed" )
1027
1028 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -07001029 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -07001030 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001031 """
1032 Params:
1033 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -07001034 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -07001035 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
1036 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
1037 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
1038 Kill a link and verify ONOS can see the proper link change
1039 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001040 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -07001041 if sleep is None:
1042 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1043 else:
1044 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001045 result = False
1046 count = 0
1047 while True:
1048 count += 1
Jon Halla604fd42018-05-04 14:27:27 -07001049 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -08001050 main.Network.link( END1=end1, END2=end2, OPTION="up" )
1051 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001052 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001053 "Waiting %s seconds for link up to be discovered" % sleep )
1054 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -07001055
You Wangc02d8352018-04-17 16:42:10 -07001056 if portUp:
1057 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
1058 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -07001059 main.log.info(
1060 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -07001061 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001062
Jon Halla604fd42018-05-04 14:27:27 -07001063 result = ctrl.CLI.checkStatus( numoswitch=switches,
1064 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001065 if count > 5 or result:
1066 break
1067 utilities.assert_equals( expect=main.TRUE, actual=result,
1068 onpass="Link up successful",
1069 onfail="Failed to bring link up" )
1070
1071 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001072 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001073 """
1074 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
1075 Completely kill a switch and verify ONOS can see the proper change
1076 """
Jon Halla604fd42018-05-04 14:27:27 -07001077 if sleep is None:
1078 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1079 else:
1080 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -07001081 switch = switch if isinstance( switch, list ) else [ switch ]
1082 main.step( "Kill " + str( switch ) )
1083 for s in switch:
1084 main.log.info( "Stopping " + s )
1085 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001086 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -07001087
1088 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -07001089 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001090 sleep ) )
1091 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001092 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001093 main.FALSE,
1094 kwargs={ 'numoswitch': switches,
1095 'numolink': links },
1096 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001097 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001098 utilities.assert_equals( expect=main.TRUE, actual=topology,
1099 onpass="Kill switch successful",
1100 onfail="Failed to kill switch?" )
1101
1102 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001103 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001104 """
1105 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
1106 Recover a switch and verify ONOS can see the proper change
1107 """
Jon Halla604fd42018-05-04 14:27:27 -07001108 if sleep is None:
1109 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1110 else:
1111 sleep = float( sleep )
1112 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -07001113 switch = switch if isinstance( switch, list ) else [ switch ]
1114 main.step( "Recovering " + str( switch ) )
1115 for s in switch:
1116 main.log.info( "Starting " + s )
1117 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001118 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001119 sleep ) )
1120 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001121 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -07001122 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001123 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001124 sleep ) )
1125 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001126
Devin Lim142b5342017-07-20 15:22:39 -07001127 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001128 main.FALSE,
1129 kwargs={ 'numoswitch': switches,
1130 'numolink': links },
1131 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001132 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001133 utilities.assert_equals( expect=main.TRUE, actual=topology,
1134 onpass="Switch recovery successful",
1135 onfail="Failed to recover switch?" )
1136
Jonghwan Hyun25c98a62018-05-04 13:59:09 -07001137 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -07001138 def killRouter( main, router, sleep=None ):
1139 """
1140 Kill bgpd process on a quagga router
1141 router: name of the router to be killed. E.g. "bgp1"
1142 """
1143 sleep = float( sleep )
1144 main.step( "Kill " + str( router ) )
1145 if hasattr( main, 'Mininet1' ):
1146 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1147 main.Mininet1.handle.expect( "mininet>" )
1148 else:
1149 # TODO: support killing router in physical network
1150 pass
1151 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1152 time.sleep( sleep )
1153
1154 @staticmethod
1155 def recoverRouter( main, router, sleep=None ):
1156 """
1157 Restart bgpd process on a quagga router
1158 router: name of the router to be recovered. E.g. "bgp1"
1159 """
1160 sleep = float( sleep )
1161 main.step( "Recovering " + str( router ) )
1162 if hasattr( main, 'Mininet1' ):
1163 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1164 main.Mininet1.handle.expect( "mininet>" )
1165 else:
1166 # TODO: support recovering router in physical network
1167 pass
1168 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1169 time.sleep( sleep )
1170
1171 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001172 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001173 """
1174 Stop Onos-cluster.
1175 Stops Mininet
1176 Copies ONOS log
1177 """
You Wang4cc61912018-08-28 10:10:58 -07001178 from tests.dependencies.utils import Utils
1179 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001180 if not main.persistentSetup:
1181 for ctrl in main.Cluster.active():
1182 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001183 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001184 if hasattr( main, "scapyHosts" ):
1185 scapyResult = main.TRUE
1186 for host in main.scapyHosts:
1187 scapyResult = host.stopScapy() and scapyResult
1188 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1189 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001190 if hasattr( main, 'Mininet1' ):
1191 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1192 else:
1193 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001194 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1195 main.scapyHosts = []
1196
You Wang5da39c82018-04-26 22:55:08 -07001197 if removeHostComponent:
Jon Hall22a3bcf2021-07-23 11:40:11 -07001198 try:
1199 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1200 if hasattr( main, host ):
1201 if hasattr( main, 'Mininet1' ):
1202 pass
1203 else:
1204 getattr( main, host ).disconnectInband()
1205 main.Network.removeHostComponent( host )
1206 except AttributeError as e:
1207 main.log.warn( "Could not cleanup host components: " + repr( e ) )
You Wang5da39c82018-04-26 22:55:08 -07001208
You Wang5df1c6d2018-04-06 18:02:02 -07001209 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001210 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001211 else:
1212 main.Network.disconnectInbandHosts()
1213 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001214
You Wang5df1c6d2018-04-06 18:02:02 -07001215 if copyKarafLog:
1216 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001217
Jon Hall627b1572020-12-01 12:01:15 -08001218 if not main.persistentSetup:
1219 for ctrl in main.Cluster.active():
1220 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001221 else:
1222 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001223 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001224
1225 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001226 def verifyNodes( main ):
1227 """
1228 Verifies Each active node in the cluster has an accurate view of other node's and their status
1229
1230 Params:
1231 nodes, integer array with position of the ONOS nodes in the CLIs array
1232 """
1233 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1234 False,
1235 attempts=10,
1236 sleep=10 )
1237 utilities.assert_equals( expect=True, actual=nodeResults,
1238 onpass="Nodes check successful",
1239 onfail="Nodes check NOT successful" )
1240
1241 if not nodeResults:
1242 for ctrl in main.Cluster.runningNodes:
1243 main.log.debug( "{} components not ACTIVE: \n{}".format(
1244 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001245 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001246 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001247 main.cleanAndExit()
1248
1249 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001250 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001251 """
1252 Verifies that the ONOS cluster has an acuurate view of the topology
1253
1254 Params:
1255 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
Jon Hall39570262020-11-17 12:18:19 -08001256 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001257 """
1258 main.step( "Check number of topology elements" )
1259 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1260 main.FALSE,
1261 kwargs={ 'numoswitch': switches,
1262 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001263 'numoctrl': expNodes,
1264 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001265 attempts=10,
1266 sleep=12 )
1267 utilities.assert_equals( expect=main.TRUE, actual=topology,
1268 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001269 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001270
1271 @staticmethod
1272 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001273 """
1274 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1275 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1276 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1277 """
Jon Halla604fd42018-05-04 14:27:27 -07001278 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001279 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001280 if sleep is None:
1281 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1282 else:
1283 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001284
Jon Hall214f88b2020-09-21 10:21:42 -07001285 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001286 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001287 node = main.Cluster.runningNodes[ i ]
1288 if node.inDocker:
1289 killResult = node.server.dockerStop( node.name )
1290 else:
1291 killResult = main.ONOSbench.onosDie( node.ipAddress )
1292 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001293 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001294 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1295 onpass="ONOS instance Killed",
1296 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001297 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001298 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001299 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001300
Devin Lim142b5342017-07-20 15:22:39 -07001301 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001302 Testcaselib.verifyNodes( main )
1303 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001304
1305 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001306 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001307 """
1308 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1309 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1310 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1311 """
Jon Hall3c910162018-03-07 14:42:16 -08001312 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001313 if sleep is None:
1314 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1315 else:
1316 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001317 for i in nodes:
1318 node = main.Cluster.runningNodes[ i ]
1319 if node.inDocker:
1320 main.Cluster.startONOSDockerNode( i )
1321 else:
1322 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001323 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001324 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001325 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001326 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001327 if node.inDocker:
1328 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1329 isUp = isUp and node.CLI.prepareForCLI()
1330 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1331 else:
1332 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001333 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1334 onpass="ONOS service is ready",
1335 onfail="ONOS service did not start properly" )
1336 for i in nodes:
1337 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001338 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001339 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001340 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1341 commandlineTimeout=60,
1342 onosStartTimeout=100 )
1343 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001344 utilities.assert_equals( expect=main.TRUE,
1345 actual=cliResult,
1346 onpass="ONOS CLI is ready",
1347 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001348
Jon Halla604fd42018-05-04 14:27:27 -07001349 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001350 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001351 Testcaselib.verifyNodes( main )
1352 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001353
Devin Lim142b5342017-07-20 15:22:39 -07001354 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001355 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001356 attempts=10,
1357 sleep=12 )
1358 if ready:
1359 ready = main.TRUE
1360 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001361 onpass="ONOS summary command succeded",
1362 onfail="ONOS summary command failed" )
1363 if not ready:
1364 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001365 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001366
1367 @staticmethod
1368 def addHostCfg( main ):
1369 """
1370 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001371 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001372 """
1373 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001374 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001375 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001376 hostCfg = json.load( template )
1377 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1378 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001379 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001380 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1381 subjectClass="hosts",
1382 subjectKey=urllib.quote( mac,
1383 safe='' ),
1384 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001385 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1386 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001387 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001388 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1389 subjectClass="hosts",
1390 subjectKey=urllib.quote( mac,
1391 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001392 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001393 main.pingChart.update( { 'vlan1': { "expect": "True",
1394 "hosts": [ "olt1", "vsg1" ] } } )
1395 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1396 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001397 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1398 vlanId=1,
1399 port1=5,
1400 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001401
1402 @staticmethod
1403 def delHostCfg( main ):
1404 """
1405 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001406 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001407 """
1408 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001409 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001410 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001411 hostCfg = json.load( template )
1412 main.step( "Removing host configuration" )
1413 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001414 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001415 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1416 subjectKey=urllib.quote(
1417 mac,
1418 safe='' ),
1419 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001420 main.step( "Removing configuration" )
1421 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001422 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001423 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1424 subjectKey=urllib.quote(
1425 mac,
1426 safe='' ),
1427 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001428 main.step( "Removing vlan configuration" )
1429 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001430 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1431 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001432
1433 @staticmethod
1434 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1435 """
1436 Verifies IP address assignment from the hosts
1437 """
1438 main.step( "Verify IP address assignment from hosts" )
1439 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001440 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001441 # Find out names of disconnected hosts
1442 disconnectedHosts = []
1443 if hasattr( main, "disconnectedIpv4Hosts" ):
1444 for host in main.disconnectedIpv4Hosts:
1445 disconnectedHosts.append( host )
1446 if hasattr( main, "disconnectedIpv6Hosts" ):
1447 for host in main.disconnectedIpv6Hosts:
1448 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001449 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001450 # Exclude disconnected hosts
1451 if hostName in disconnectedHosts:
1452 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1453 continue
You Wang53dba1e2018-02-02 17:45:44 -08001454 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1455 main.FALSE,
1456 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001457 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001458 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001459 attempts=attempts,
1460 sleep=sleep )
1461 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1462 onpass="Verify network host IP succeded",
1463 onfail="Verify network host IP failed" )
1464
1465 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001466 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001467 """
1468 Verifies host IP address assignment from ONOS
1469 """
1470 main.step( "Verify host IP address assignment in ONOS" )
1471 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001472 # Find out IPs of disconnected hosts
1473 disconnectedIps = []
1474 if hasattr( main, "disconnectedIpv4Hosts" ):
1475 for host in main.disconnectedIpv4Hosts:
1476 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1477 if hasattr( main, "disconnectedIpv6Hosts" ):
1478 for host in main.disconnectedIpv6Hosts:
1479 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001480 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001481 # Exclude disconnected hosts
1482 if ip in disconnectedIps:
1483 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1484 continue
You Wang53dba1e2018-02-02 17:45:44 -08001485 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1486 main.FALSE,
1487 kwargs={ 'hostList': [ hostName ],
1488 'prefix': ip },
1489 attempts=attempts,
1490 sleep=sleep )
1491 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1492 onpass="Verify ONOS host IP succeded",
1493 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001494 if not ipResult and skipOnFail:
1495 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001496 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001497 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001498
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001499 @staticmethod
1500 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1501 """
1502 Description:
1503 Updates interface configuration in ONOS, with given IP and vlan parameters
1504 Required:
1505 * connectPoint: connect point to update configuration
1506 Optional:
1507 * ips: list of IP addresses, combined with '/xx' subnet representation,
1508 corresponding to 'ips' field in the configuration
1509 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1510 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1511 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1512 """
1513 cfg = dict()
1514 cfg[ "ports" ] = dict()
1515 cfg[ "ports" ][ connectPoint ] = dict()
1516 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1517 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1518 if untagged > 0:
1519 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1520 else:
1521 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1522 if native > 0:
1523 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1524
1525 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001526
1527 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001528 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001529 """
1530 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001531 scapyNames: list of names that will be used as component names for scapy hosts
1532 mininetNames: used when scapy host names are different from the host names
1533 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1534 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001535 """
1536 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001537 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1538 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001539 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001540 if hasattr( main, 'Mininet1' ):
1541 main.Scapy.createHostComponent( scapyName )
1542 scapyHandle = getattr( main, scapyName )
1543 if mininetNames:
1544 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1545 else:
1546 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001547 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1548 scapyHandle.mExecDir = "/tmp"
1549 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1550 main.log.debug( "start mn host component in docker" )
1551 scapyHandle.startHostCli( mininetName,
1552 execDir="/tmp",
1553 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1554 else:
1555 main.log.debug( "start mn host component" )
1556 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001557 else:
You Wang0fc21702018-11-02 17:49:18 -07001558 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001559 scapyHandle = getattr( main, scapyName )
1560 scapyHandle.connectInband()
1561 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001562 scapyHandle.startScapy()
1563 scapyHandle.updateSelf()
1564 main.log.debug( scapyHandle.name )
1565 main.log.debug( scapyHandle.hostIp )
1566 main.log.debug( scapyHandle.hostMac )
1567
1568 @staticmethod
1569 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1570 """
1571 Verify unicast traffic by pinging from source hosts to the destination IP
1572 and capturing the packets at the destination host using Scapy.
1573 srcHosts: List of host names to send the ping packets
1574 dstIp: destination IP of the ping packets
1575 dstHost: host that runs Scapy to capture the packets
1576 dstIntf: name of the interface on the destination host
1577 expect: use True if the ping is expected to be captured at destination;
1578 Otherwise False
1579 skipOnFail: skip the rest of this test case if result is not expected
1580 maxRetry: number of retries allowed
1581 """
1582 from tests.dependencies.topology import Topology
1583 try:
1584 main.topo
1585 except ( NameError, AttributeError ):
1586 main.topo = Topology()
1587 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1588 result = main.TRUE
1589 for srcHost in srcHosts:
1590 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1591 expect, maxRetry, True )
1592 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001593 result = main.FALSE
1594 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1595 utilities.assert_equals( expect=main.TRUE,
1596 actual=result,
1597 onpass="Verify traffic to {}: Pass".format( dstIp ),
1598 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1599 if skipOnFail and result != main.TRUE:
1600 Testcaselib.saveOnosDiagnostics( main )
1601 Testcaselib.cleanup( main, copyKarafLog=False )
1602 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001603
1604 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001605 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001606 """
1607 Verify multicast traffic using scapy
1608 """
You Wangc564c6f2018-05-01 15:24:57 -07001609 from tests.dependencies.topology import Topology
1610 try:
1611 main.topo
1612 except ( NameError, AttributeError ):
1613 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001614 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001615 routeData = main.multicastConfig[ routeName ]
1616 srcs = main.mcastRoutes[ routeName ][ "src" ]
1617 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1618 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1619 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001620 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001621 for src in srcs:
1622 srcEntry = routeData[ "src" ][ src ]
1623 for dst in dsts:
1624 dstEntry = routeData[ "dst" ][ dst ]
1625 sender = getattr( main, srcEntry[ "host" ] )
1626 receiver = getattr( main, dstEntry[ "host" ] )
1627 main.Network.addRoute( str( srcEntry[ "host" ] ),
1628 str( routeData[ "group" ] ),
1629 str( srcEntry[ "interface" ] ),
1630 True if routeData[ "ipVersion" ] == 6 else False )
1631 # Build the packet
1632 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1633 if routeData[ "ipVersion" ] == 4:
1634 sender.buildIP( dst=str( routeData[ "group" ] ) )
1635 elif routeData[ "ipVersion" ] == 6:
1636 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1637 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1638 sIface = srcEntry[ "interface" ]
1639 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1640 pktFilter = srcEntry[ "filter" ]
1641 pkt = srcEntry[ "packet" ]
1642 # Send packet and check received packet
1643 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001644 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001645 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001646 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1647 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001648 if not trafficResult:
1649 result = main.FALSE
1650 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1651 dstEntry[ "host" ] ) )
1652 utilities.assert_equals( expect=main.TRUE,
1653 actual=result,
1654 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1655 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001656 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001657 Testcaselib.saveOnosDiagnostics( main )
1658 Testcaselib.cleanup( main, copyKarafLog=False )
1659 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001660
1661 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001662 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001663 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1664 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001665 """
1666 Verify reachability from each host in srcList to each host in dstList
1667 """
1668 from tests.dependencies.topology import Topology
1669 try:
1670 main.topo
1671 except ( NameError, AttributeError ):
1672 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001673 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001674 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001675 utilities.assert_equals( expect=main.TRUE,
1676 actual=pingResult,
1677 onpass="{}: Pass".format( stepMsg ),
1678 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001679 if not pingResult and skipOnFail:
1680 Testcaselib.saveOnosDiagnostics( main )
1681 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1682 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001683
1684 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001685 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001686 """
1687 Verify if the specified host is discovered by ONOS on the given locations
1688 Required:
You Wang85747762018-05-11 15:51:50 -07001689 locationDict: a dictionary that maps host names to expected locations.
1690 locations could be a string or a list.
1691 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001692 Returns:
1693 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1694 """
You Wang85747762018-05-11 15:51:50 -07001695 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1696 result = main.TRUE
1697 for hostName, locations in locationDict.items():
1698 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1699 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1700 if not hostIp:
1701 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1702 if not hostIp:
1703 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1704 result = main.FALSE
1705 continue
1706 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1707 main.FALSE,
1708 args=( hostIp, locations ),
1709 attempts=retry + 1,
1710 sleep=10 )
1711 if not locationResult:
1712 result = main.FALSE
1713 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001714 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001715 onpass="Location verification passed",
1716 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001717
1718 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001719 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001720 """
1721 Move specified host from srcSw to dstSw.
1722 If srcSw and dstSw are same, the host will be moved from current port to
1723 next available port.
1724 Required:
1725 hostName: name of the host. e.g., "h1"
1726 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1727 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1728 gw: ip address of the gateway of the new location
1729 Optional:
1730 macAddr: if specified, change MAC address of the host to the specified MAC address.
1731 prefixLen: prefix length
1732 cfg: port configuration as JSON string
1733 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001734 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001735 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001736 if not hasattr( main, 'Mininet1' ):
1737 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1738 return
1739
You Wang6e5b48e2018-07-23 16:17:38 -07001740 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1741 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1742 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001743 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001744 if cfg:
1745 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1746 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001747 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001748 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001749 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001750
1751 main.Mininet1.discoverHosts( [ hostName, ] )
1752
1753 # Update expectedHost when MAC address is changed.
1754 if macAddr is not None:
1755 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1756 if ipAddr is not None:
1757 for hostName, ip in main.expectedHosts[ "onos" ].items():
1758 if ip == ipAddr:
1759 vlan = hostName.split( "/" )[ -1 ]
1760 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001761 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001762 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001763
1764 @staticmethod
1765 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001766 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001767 """
1768 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1769 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1770 to next available port.
1771 Required:
1772 hostName: name of the host. e.g., "h1"
1773 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1774 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1775 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1776 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1777 gw: ip address of the gateway of the new location
1778 Optional:
1779 macAddr: if specified, change MAC address of the host to the specified MAC address.
1780 prefixLen: prefix length
1781 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001782 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001783 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001784 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001785 if not hasattr( main, 'Mininet1' ):
1786 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1787 return
1788
You Wang6e5b48e2018-07-23 16:17:38 -07001789 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1790 srcSw, srcPairSw, dstSw, dstPairSw ) )
1791 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1792 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1793 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001794 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001795 if cfg:
1796 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1797 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001798 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001799 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001800 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001801
1802 main.Mininet1.discoverHosts( [ hostName, ] )
1803
1804 # Update expectedHost when MAC address is changed.
1805 if macAddr is not None:
1806 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1807 if ipAddr is not None:
1808 for hostName, ip in main.expectedHosts[ "onos" ].items():
1809 if ip == ipAddr:
1810 vlan = hostName.split( "/" )[ -1 ]
1811 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001812 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001813
1814 @staticmethod
1815 def mnDockerSetup( main ):
1816 """
1817 Optionally start and setup docker image for mininet
1818 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001819 try:
1820 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001821
Jon Hall9b0de1f2020-08-24 15:38:04 -07001822 main.log.info( "Creating Mininet Docker" )
1823 handle = main.Mininet1.handle
1824 # build docker image
1825 dockerFilePath = "%s/../dependencies/" % main.testDir
1826 dockerName = "trellis_mininet"
1827 # Stop any leftover container
1828 main.Mininet1.dockerStop( dockerName )
1829 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001830 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001831
Jon Hall9b0de1f2020-08-24 15:38:04 -07001832 confDir = "/tmp/mn_conf/"
1833 # Try to ensure the destination exists
1834 main.log.info( "Create folder for network config files" )
1835 handle.sendline( "rm -rf %s" % confDir )
1836 handle.expect( main.Mininet1.Prompt() )
1837 main.log.debug( handle.before + handle.after )
1838 handle.sendline( "mkdir -p %s" % confDir )
1839 handle.expect( main.Mininet1.Prompt() )
1840 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001841 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1842 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001843 # Make sure permissions are correct
1844 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1845 handle.expect( main.Mininet1.Prompt() )
1846 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1847 handle.expect( main.Mininet1.Prompt() )
1848 main.log.debug( handle.before + handle.after )
1849 # Start docker container
1850 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1851 dockerName,
1852 main.params[ 'MN_DOCKER' ][ 'args' ] )
1853 if runResponse == main.FALSE:
1854 main.log.error( "Docker container already running, aborting test" )
1855 main.cleanup()
1856 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001857
Jon Hall9b0de1f2020-08-24 15:38:04 -07001858 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1859 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001860
Jon Hall9b0de1f2020-08-24 15:38:04 -07001861 # Fow when we create component handles
1862 main.Mininet1.mExecDir = "/tmp"
1863 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1864 main.Mininet1.hostPrompt = "/home/root#"
1865
1866 # For some reason docker isn't doing this
1867 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1868 main.Mininet1.handle.expect( "etc/hosts" )
1869 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1870 except Exception as e:
1871 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001872 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001873
1874 @staticmethod
1875 def mnDockerTeardown( main ):
1876 """
1877 Optionally stop and cleanup docker image for mininet
1878 """
1879
1880 if hasattr( main, 'Mininet1' ):
1881 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001882 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001883
1884 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001885 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001886 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001887 main.Mininet1.sudoRequired = True
1888 except Exception as e:
1889 main.log.error( e )
1890
Jon Hall39570262020-11-17 12:18:19 -08001891 # Save docker logs
1892 copyResult = main.ONOSbench.scp( main.Mininet1,
1893 "/tmp/mn-stratum/*",
1894 main.logdir,
1895 direction="from",
1896 options="-rp" )
1897
1898
Jon Hall43060f62020-06-23 13:13:33 -07001899 @staticmethod
1900 def setOnosConfig( main ):
1901 """
1902 Read and Set onos configurations from the params file
1903 """
1904 main.step( "Set ONOS configurations" )
1905 config = main.params.get( 'ONOS_Configuration' )
1906 if config:
1907 main.log.debug( config )
1908 checkResult = main.TRUE
1909 for component in config:
1910 for setting in config[ component ]:
1911 value = config[ component ][ setting ]
1912 check = main.Cluster.next().setCfg( component, setting, value )
1913 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1914 checkResult = check and checkResult
1915 utilities.assert_equals( expect=main.TRUE,
1916 actual=checkResult,
1917 onpass="Successfully set config",
1918 onfail="Failed to set config" )
1919 else:
1920 main.log.warn( "No configurations were specified to be changed after startup" )
1921
1922 @staticmethod
1923 def setOnosLogLevels( main ):
1924 """
1925 Read and Set onos log levels from the params file
1926 """
1927 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001928 # Get original values incase we want to reset them
1929 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001930 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001931 ctrl.CLI.logList()
1932
Jon Hall43060f62020-06-23 13:13:33 -07001933 logging = True
1934 try:
1935 logs = main.params.get( 'ONOS_Logging', False )
1936 if logs:
1937 for namespace, level in logs.items():
1938 for ctrl in main.Cluster.active():
1939 ctrl.CLI.logSet( level, namespace )
1940 except AttributeError:
1941 logging = False
1942 utilities.assert_equals( expect=True, actual=logging,
1943 onpass="Set log levels",
1944 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001945
1946 @staticmethod
1947 def resetOnosLogLevels( main ):
1948 """
1949 Read and reset onos log levels to a previously read set of values
1950 """
1951 main.step( 'Reset logging levels' )
1952 # Get original values incase we want to reset them
1953 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001954 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001955 currentLevels = ctrl.CLI.logList( saveValues=False )
1956 origLevels = ctrl.CLI.logLevels
1957 toBeSet = {}
1958 for logger, level in currentLevels.iteritems():
1959 if logger not in origLevels:
1960 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1961 else:
1962 oldLevel = origLevels[ logger ]
1963 if level != oldLevel:
1964 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001965 # In case a previous test didn't reset
1966 logs = main.params.get( 'ONOS_Logging_Reset', False )
1967 if logs:
1968 for namespace, level in logs.items():
1969 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001970 logging = True
1971 try:
1972 for logger, level in toBeSet.iteritems():
1973 for ctrl in main.Cluster.active():
1974 ctrl.CLI.logSet( level, logger )
1975 except AttributeError:
1976 logging = False
1977 utilities.assert_equals( expect=True, actual=logging,
1978 onpass="Reset log levels",
1979 onfail="Failed to reset log levels" )