blob: 4ce89342da7e199cac99b2fbc839cffd880a3557 [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
52 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070053 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080054 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070055 stepResult = main.FALSE
56 try:
Devin Lim58046fa2017-07-05 16:55:00 -070057 # Test variables
58 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
59 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070060 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080061 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
62 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
63 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080064 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
65 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
66 else:
67 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070068 if main.useBmv2:
69 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
70 else:
71 main.switchType = "ovs"
72
Devin Lim57221b02018-02-14 15:45:36 -080073 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070074 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080075 main.forJson = "json/"
76 main.forChart = "chart/"
77 main.forConfig = "conf/"
78 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080079 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080080 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070081 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070082 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080083 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
84 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080085 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070086 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070087 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070088 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070089 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070090 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070091
Devin Lim0c972b72018-02-08 14:53:59 -080092 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070093 except Exception as e:
94 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070095
Jon Hallaa1d9b82020-07-30 13:49:42 -070096 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070097
Jon Hall1efcb3f2016-08-23 13:42:15 -070098 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080099 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
100 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700101 """
102 - Set up cell
103 - Create cell file
104 - Set cell file
105 - Verify cell file
106 - Kill ONOS process
107 - Uninstall ONOS cluster
108 - Verify ONOS start up
109 - Install ONOS cluster
110 - Connect to cli
111 """
112 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700113 try:
114 if main.params.get( 'EXTERNAL_APPS' ):
115 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
116 main.log.info( "Downloading %s app from %s" )
117 main.ONOSbench.onosFetchApp( url )
118 if not main.apps:
119 main.log.error( "App list is empty" )
120 except Exception as e:
121 main.log.debug( e )
122 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800123 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
124 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700125 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800126 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800127 skipPack=skipPackage,
128 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800129 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700130 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700131 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800132 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700133 attempts=10 )
134 if ready:
135 ready = main.TRUE
136 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700137 onpass="ONOS summary command succeded",
138 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700139 if not ready:
140 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700141 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700142
You Wang5bf49592020-07-08 18:47:46 -0700143 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700144 appInstallResult = main.TRUE
145 if main.trellisOar:
146 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700147 if main.t3Oar:
148 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
149 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
150 onpass="SR app installation succeded",
151 onfail="SR app installation failed" )
152 if not appInstallResult:
153 main.cleanAndExit()
154
Jon Hall43060f62020-06-23 13:13:33 -0700155 # FIXME: move to somewhere else?
156 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
157 # TODO: Support other pipeconfs/making this configurable
158 if switchPrefix == "tofino":
159 # It seems to take some time for the pipeconfs to be loaded
160 ctrl = main.Cluster.next()
161 for i in range( 120 ):
162 try:
163 main.log.debug( "Checking to see if pipeconfs are loaded" )
164 output = ctrl.CLI.sendline( "pipeconfs" )
165 if "tofino" in output:
166 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
167 break
168 time.sleep( 1 )
169 except Exception as e:
170 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700171
Jon Hall43060f62020-06-23 13:13:33 -0700172 Testcaselib.setOnosLogLevels( main )
173 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700174
Jon Hall1efcb3f2016-08-23 13:42:15 -0700175 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800176 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700177 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
178 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800179
180 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700181 def loadJson( main, suffix='' ):
182 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
183 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800184 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
185
186 @staticmethod
187 def loadChart( main ):
188 try:
189 with open( "%s%s.chart" % ( main.configPath + main.forChart,
190 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700191 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800192 except IOError:
193 main.log.warn( "No chart file found." )
194
195 @staticmethod
196 def loadHost( main ):
197 with open( "%s%s.host" % ( main.configPath + main.forHost,
198 main.cfgName ) ) as host:
199 main.expectedHosts = json.load( host )
200
201 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800202 def loadSwitchFailureChart( main ):
203 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
204 main.cfgName ) ) as sfc:
205 main.switchFailureChart = json.load( sfc )
206
207 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800208 def loadLinkFailureChart( main ):
209 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700210 main.cfgName ) ) as lfc:
211 main.linkFailureChart = json.load( lfc )
212
213 @staticmethod
214 def loadMulticastConfig( main ):
215 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
216 main.cfgName ) ) as cfg:
217 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800218
219 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700220 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700221 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800222 copyResult = main.ONOSbench.scp( main.Mininet1,
223 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700224 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800225 direction="to" )
226 if main.topologyLib:
227 for lib in main.topologyLib.split(","):
228 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
229 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700230 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800231 direction="to" )
232 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700233 import re
234 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
235 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700236 destDir = "~/"
237 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
238 destDir = "/tmp/mn_conf/"
239 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800240 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700241 # Update zebra configurations with correct ONOS instance IP
242 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
243 ip = controllerIPs[ index ]
244 index = ( index + 1 ) % len( controllerIPs )
245 with open( main.configPath + main.forConfig + conf ) as f:
246 s = f.read()
247 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
248 with open( main.configPath + main.forConfig + conf, "w" ) as f:
249 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800250 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800251 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700252 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800253 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800254 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700255 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800256 main.Mininet1.home + "custom",
257 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700258
259 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
260 # move the config files into home
261 main.Mininet1.handle.sendline( "cp config/* . " )
262 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
263 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
264 main.Mininet1.handle.sendline( "ls -al " )
265 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
266 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
267
You Wangd87b2312018-01-30 12:47:17 -0800268 stepResult = copyResult
269 utilities.assert_equals( expect=main.TRUE,
270 actual=stepResult,
271 onpass="Successfully copied topo files",
272 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700273 if main.stratumRoot:
274 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700275 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700276 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700277 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700278 main.topology = topology
279 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700280 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700281 stepResult = topoResult
282 utilities.assert_equals( expect=main.TRUE,
283 actual=stepResult,
284 onpass="Successfully loaded topology",
285 onfail="Failed to load topology" )
286 # Exit if topology did not load properly
287 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700288 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700289 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700290 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700291 # Upload the net-cfg file created for each switch
292 filename = "onos-netcfg.json"
293 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700294 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700295 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
296 path = "/tmp/mn-stratum/%s/" % switch
297 dstPath = "/tmp/"
298 dstFileName = "%s-onos-netcfg.json" % switch
299 main.ONOSbench1.scp( main.Mininet1,
300 "%s%s" % ( path, filename ),
301 "%s%s" % ( dstPath, dstFileName ),
302 "from" )
303 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 -0700304 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700305 # Configure managementAddress
306 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
307 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
308 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
309 # Configure device id
310 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
311 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
312 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
313 # Configure device name
314 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s\",' %s%s" % ( switch, dstPath, dstFileName ) )
315 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
316 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700317 node = main.Cluster.active(0)
318 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
319 dstPath,
320 dstFileName,
321 user=node.REST.user_name,
322 password=node.REST.pwd )
323 # Stop test if we fail to push switch netcfg
324 utilities.assert_equals( expect=main.TRUE,
325 actual=switchNetCfg,
326 onpass="Successfully pushed switch netcfg",
327 onfail="Failed to configure switches in onos" )
328 if not switchNetCfg:
329 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700330 # Make sure hosts make some noise
331 Testcaselib.discoverHosts( main )
332
333 @staticmethod
334 def discoverHosts( main ):
335 # TODO add option to only select specific hosts
336 if hasattr( main, "Mininet1" ):
337 network = main.Mininet1
338 elif hasattr( main, "NetworkBench" ):
339 network = main.NetworkBench
340 else:
341 main.log.warn( "Could not find component for test network, skipping host discovery" )
342 return
343 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700344
345 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700346 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800347 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700348 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800349 topoResult = main.NetworkBench.connectToNet()
350 stepResult = topoResult
351 utilities.assert_equals( expect=main.TRUE,
352 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700353 onpass="Successfully connected to topology",
354 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800355 # Exit if topology did not load properly
356 if not topoResult:
357 main.cleanAndExit()
358
Jon Hall43060f62020-06-23 13:13:33 -0700359 # Perform any optional setup
360 for switch in main.NetworkBench.switches:
361 if hasattr( switch, "setup" ):
362 switch.setup() # We might not need this
363
You Wang84f981d2018-01-12 16:11:50 -0800364 main.step( "Assign switches to controllers." )
Jon Hall43060f62020-06-23 13:13:33 -0700365 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700366 switches = main.NetworkBench.getSwitches()
367 pool = []
368 for name in switches.keys():
Jon Hall43060f62020-06-23 13:13:33 -0700369 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
370 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700371 thread = main.Thread( target=main.NetworkBench.assignSwController,
372 name="assignSwitchToController",
373 args=[ name, main.Cluster.getIps(), '6653' ] )
374 pool.append( thread )
375 thread.start()
376 for thread in pool:
377 thread.join( 300 )
378 if not thread.result:
379 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800380 utilities.assert_equals( expect=main.TRUE,
381 actual=stepResult,
382 onpass="Successfully assign switches to controllers",
383 onfail="Failed to assign switches to controllers" )
384
You Wang4cc61912018-08-28 10:10:58 -0700385 # Check devices
386 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700387 # Connecting to hosts that only have data plane connectivity
388 main.step( "Connecting inband hosts" )
389 stepResult = main.Network.connectInbandHosts()
390 utilities.assert_equals( expect=main.TRUE,
391 actual=stepResult,
392 onpass="Successfully connected inband hosts",
393 onfail="Failed to connect inband hosts" )
Jon Hall43060f62020-06-23 13:13:33 -0700394 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700395
You Wang84f981d2018-01-12 16:11:50 -0800396 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700397 def saveOnosDiagnostics( main ):
398 """
399 Get onos-diags.tar.gz and save it to the log directory.
400 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
401 """
402 main.log.info( "Collecting onos-diags..." )
403 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
404 main.logdir,
405 "-CASE%d" % main.CurrentTestCaseNumber )
406
407 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700408 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700409 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700410
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700411 main.failures = int( main.params[ 'failures' ] )
412 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700413
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700414 if main.cfgName == '2x2':
415 spine = {}
416 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
417 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
418 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700419
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700420 spine = {}
421 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
422 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
423 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700424
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700425 elif main.cfgName == '4x4':
426 spine = {}
427 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
428 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
429 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700430
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700431 spine = {}
432 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
433 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
434 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700435
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700436 spine = {}
437 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
438 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
439 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700440
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700441 spine = {}
442 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
443 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
444 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700445
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700446 else:
Piera2a7e1b2016-10-04 11:51:43 -0700447 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700448 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800449
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800450 @staticmethod
451 def addStaticOnosRoute( main, subnet, intf):
452 """
453 Adds an ONOS static route with the use route-add command.
454 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800455 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
456
Piera2a7e1b2016-10-04 11:51:43 -0700457 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700458 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700459 """
460 Check number of groups for each subnet on device deviceId and matches
461 it with an expected value. subnetDict is a dictionarty containing values
462 of the type "10.0.1.0/24" : 5.
463 """
You Wangc02f3be2018-05-18 12:14:23 -0700464 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
465 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
466 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700467
You Wangc02f3be2018-05-18 12:14:23 -0700468 result = main.TRUE
469 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700470 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700471 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700472 # this will match the group id that this flow entry points to, for example :
473 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700474 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700475 count = 0
476 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700477 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700478 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700479 if count - 1 != numberInSelect:
480 result = main.FALSE
481 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 ) )
482 utilities.assert_equals( expect=main.TRUE, actual=result,
483 onpass="All bucket numbers are as expected",
484 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700485
486 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900487 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700488 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800489 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900490 if tag == "":
491 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700492 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700493 main.FALSE,
494 kwargs={ 'min': minFlowCount },
495 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800496 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800497 if count == main.FALSE:
498 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700499 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700500 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800501 actual=( count > minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700502 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
503 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700504
505 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700506 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700507 main.FALSE,
508 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800509 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800510 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700511 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700512 expect=main.TRUE,
513 actual=flowCheck,
514 onpass="Flow status is correct!",
515 onfail="Flow status is wrong!" )
516 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700517 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700518 "flows",
519 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900520 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700521 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700522 "groups",
523 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900524 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700525
526 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700527 def checkDevices( main, switches, tag="", sleep=10 ):
528 main.step(
529 "Check whether the switches count is equal to %s" % switches )
530 if tag == "":
531 tag = 'CASE%d' % main.CurrentTestCaseNumber
532 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
533 main.FALSE,
534 kwargs={ 'numoswitch': switches},
535 attempts=10,
536 sleep=sleep )
537 utilities.assert_equals( expect=main.TRUE, actual=result,
538 onpass="Device up successful",
539 onfail="Failed to boot up devices?" )
540
541 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800542 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
543 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700544 "Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800545 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
546 main.FALSE,
547 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800548 attempts=5,
549 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800550 if count == main.FALSE:
551 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800552 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800553 expect=True,
554 actual=( count > minFlowCount ),
555 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800556 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800557
558 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700559 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800560 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700561 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800562 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
563 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700564 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800565 attempts=5,
566 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800567 if count == main.FALSE:
568 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800569 utilities.assertEquals(
570 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800571 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700572 onpass="Flow count looks correct: " + str( count ) ,
573 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800574
575 @staticmethod
576 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
577 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700578 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800579 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
580 main.FALSE,
581 args=( dpid, groupCount, False, 1),
582 attempts=5,
583 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800584 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800585 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800586 utilities.assertEquals(
587 expect=True,
588 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700589 onpass="Group count looks correct: " + str( count ) ,
590 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800591
592 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700593 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800594
595 for dpid, values in main.count.items():
596 flowCount = values["flows"]
597 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700598 main.log.report( "Check flow count for dpid " + str( dpid ) +
599 ", should be " + str( flowCount ) )
600 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800601
Jon Hall9677ed32018-04-24 11:16:23 -0700602 main.log.report( "Check group count for dpid " + str( dpid ) +
603 ", should be " + str( groupCount ) )
604 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800605
606 return
607
608 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700609 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
610 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800611 '''
You Wangba231e72018-03-01 13:18:21 -0800612 Verify connectivity between hosts according to the ping chart
613 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800614 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800615 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800616 '''
You Wangba231e72018-03-01 13:18:21 -0800617 main.log.report( "Check host connectivity" )
618 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800619 if tag == "":
620 tag = 'CASE%d' % main.CurrentTestCaseNumber
621 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800622 main.log.debug( "Entry in ping chart: %s" % entry )
623 expect = entry[ 'expect' ]
624 if expect == "Unidirectional":
625 # Verify ping from each src host to each dst host
626 src = entry[ 'src' ]
627 dst = entry[ 'dst' ]
628 expect = main.TRUE
629 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
630 if basedOnIp:
631 if ("v4" in src[0]):
632 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
633 utilities.assert_equals( expect=expect, actual=pa,
634 onpass="IPv4 connectivity successfully tested",
635 onfail="IPv4 connectivity failed" )
636 if ("v6" in src[0]):
637 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
638 utilities.assert_equals( expect=expect, actual=pa,
639 onpass="IPv6 connectivity successfully tested",
640 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700641 elif main.physicalNet:
642 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
643 utilities.assert_equals( expect=expect, actual=pa,
644 onpass="IP connectivity successfully tested",
645 onfail="IP connectivity failed" )
646
You Wangba231e72018-03-01 13:18:21 -0800647 else:
648 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
649 utilities.assert_equals( expect=expect, actual=pa,
650 onpass="IP connectivity successfully tested",
651 onfail="IP connectivity failed" )
652 else:
653 # Verify ping between each host pair
654 hosts = entry[ 'hosts' ]
655 try:
656 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
657 except:
658 expect = main.FALSE
659 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
660 if basedOnIp:
661 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800662 pa = utilities.retry( main.Network.pingallHosts,
663 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700664 args=(hosts, ),
665 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800666 attempts=retryAttempts,
667 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800668 utilities.assert_equals( expect=expect, actual=pa,
669 onpass="IPv4 connectivity successfully tested",
670 onfail="IPv4 connectivity failed" )
671 if ("v6" in hosts[0]):
672 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
673 utilities.assert_equals( expect=expect, actual=pa,
674 onpass="IPv6 connectivity successfully tested",
675 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700676 elif main.physicalNet:
677 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
678 utilities.assert_equals( expect=expect, actual=pa,
679 onpass="IP connectivity successfully tested",
680 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800681 else:
You Wangf19d9f42018-02-23 16:34:19 -0800682 pa = main.Network.pingallHosts( hosts )
683 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800684 onpass="IP connectivity successfully tested",
685 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700686 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700687 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700688 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700689 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700690 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800691
692 if dumpflows:
693 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
694 "flows",
695 main.logdir,
696 tag + "_FlowsOn" )
697 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
698 "groups",
699 main.logdir,
700 tag + "_GroupsOn" )
701
702 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700703 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700704 """
705 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
706 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
707 Kill a link and verify ONOS can see the proper link change
708 """
Jon Halla604fd42018-05-04 14:27:27 -0700709 if sleep is None:
710 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
711 else:
712 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700713 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700714 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
715 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
716 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700717 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700718 "Waiting %s seconds for link down to be discovered" % sleep )
719 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700720 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700721 main.FALSE,
722 kwargs={ 'numoswitch': switches,
723 'numolink': links },
724 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700725 sleep=sleep )
726 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700727 utilities.assert_equals( expect=main.TRUE, actual=result,
728 onpass="Link down successful",
729 onfail="Failed to turn off link?" )
730
731 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700732 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800733 """
734 links = list of links (src, dst) to bring down.
735 """
736
737 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700738 if sleep is None:
739 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
740 else:
741 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800742
743 for end1, end2 in links:
744 main.Network.link( END1=end1, END2=end2, OPTION="down")
745 main.Network.link( END1=end2, END2=end1, OPTION="down")
746
Jon Halla604fd42018-05-04 14:27:27 -0700747 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800748 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700749 "Waiting %s seconds for links down to be discovered" % sleep )
750 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800751
752 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
753 main.FALSE,
754 kwargs={ 'numoswitch': switches,
755 'numolink': linksAfter },
756 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700757 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800758
You Wang2854bce2018-03-30 10:15:32 -0700759 utilities.assert_equals( expect=main.TRUE, actual=topology,
760 onpass="Link batch down successful",
761 onfail="Link batch down failed" )
762
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800763 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700764 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800765 """
766 links = list of link (src, dst) to bring up again.
767 """
768
769 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700770 if sleep is None:
771 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
772 else:
773 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800774
775 for end1, end2 in links:
776 main.Network.link( END1=end1, END2=end2, OPTION="up")
777 main.Network.link( END1=end2, END2=end1, OPTION="up")
778
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800779 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700780 "Waiting %s seconds for links up to be discovered" % sleep )
781 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800782
783 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
784 main.FALSE,
785 kwargs={ 'numoswitch': switches,
786 'numolink': linksAfter },
787 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700788 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800789
You Wang2854bce2018-03-30 10:15:32 -0700790 utilities.assert_equals( expect=main.TRUE, actual=topology,
791 onpass="Link batch up successful",
792 onfail="Link batch up failed" )
793
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800794 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700795 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
796 """
797 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
798 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
799 switches, links: number of expected switches and links after link change, ex.: '4', '6'
800 """
801 if sleep is None:
802 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
803 else:
804 sleep = float( sleep )
805 main.step( "Disable a batch of ports" )
806 for dpid, port in ports:
807 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
808 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
809 time.sleep( sleep )
810 if switches and links:
811 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
812 numolink=links )
813 utilities.assert_equals( expect=main.TRUE, actual=result,
814 onpass="Port down successful",
815 onfail="Port down failed" )
816
817 @staticmethod
818 def enablePortBatch( main, ports, switches, links, sleep=None ):
819 """
820 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
821 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
822 switches, links: number of expected switches and links after link change, ex.: '4', '6'
823 """
824 if sleep is None:
825 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
826 else:
827 sleep = float( sleep )
828 main.step( "Enable a batch of ports" )
829 for dpid, port in ports:
830 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
831 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
832 time.sleep( sleep )
833 if switches and links:
834 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
835 numolink=links )
836 utilities.assert_equals( expect=main.TRUE, actual=result,
837 onpass="Port up successful",
838 onfail="Port up failed" )
839
840 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700841 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700842 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700843 """
844 Params:
845 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700846 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700847 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
848 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
849 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
850 Kill a link and verify ONOS can see the proper link change
851 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700852 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700853 if sleep is None:
854 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
855 else:
856 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700857 result = False
858 count = 0
859 while True:
860 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700861 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800862 main.Network.link( END1=end1, END2=end2, OPTION="up" )
863 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700864 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700865 "Waiting %s seconds for link up to be discovered" % sleep )
866 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700867
You Wangc02d8352018-04-17 16:42:10 -0700868 if portUp:
869 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
870 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700871 main.log.info(
872 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700873 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700874
Jon Halla604fd42018-05-04 14:27:27 -0700875 result = ctrl.CLI.checkStatus( numoswitch=switches,
876 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700877 if count > 5 or result:
878 break
879 utilities.assert_equals( expect=main.TRUE, actual=result,
880 onpass="Link up successful",
881 onfail="Failed to bring link up" )
882
883 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700884 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700885 """
886 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
887 Completely kill a switch and verify ONOS can see the proper change
888 """
Jon Halla604fd42018-05-04 14:27:27 -0700889 if sleep is None:
890 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
891 else:
892 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700893 switch = switch if isinstance( switch, list ) else [ switch ]
894 main.step( "Kill " + str( switch ) )
895 for s in switch:
896 main.log.info( "Stopping " + s )
897 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700898 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700899
900 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700901 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700902 sleep ) )
903 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700904 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700905 main.FALSE,
906 kwargs={ 'numoswitch': switches,
907 'numolink': links },
908 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700909 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700910 utilities.assert_equals( expect=main.TRUE, actual=topology,
911 onpass="Kill switch successful",
912 onfail="Failed to kill switch?" )
913
914 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700915 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700916 """
917 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
918 Recover a switch and verify ONOS can see the proper change
919 """
Jon Halla604fd42018-05-04 14:27:27 -0700920 if sleep is None:
921 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
922 else:
923 sleep = float( sleep )
924 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700925 switch = switch if isinstance( switch, list ) else [ switch ]
926 main.step( "Recovering " + str( switch ) )
927 for s in switch:
928 main.log.info( "Starting " + s )
929 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700930 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700931 sleep ) )
932 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700933 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700934 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700935 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700936 sleep ) )
937 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700938
Devin Lim142b5342017-07-20 15:22:39 -0700939 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700940 main.FALSE,
941 kwargs={ 'numoswitch': switches,
942 'numolink': links },
943 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700944 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700945 utilities.assert_equals( expect=main.TRUE, actual=topology,
946 onpass="Switch recovery successful",
947 onfail="Failed to recover switch?" )
948
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700949 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700950 def killRouter( main, router, sleep=None ):
951 """
952 Kill bgpd process on a quagga router
953 router: name of the router to be killed. E.g. "bgp1"
954 """
955 sleep = float( sleep )
956 main.step( "Kill " + str( router ) )
957 if hasattr( main, 'Mininet1' ):
958 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
959 main.Mininet1.handle.expect( "mininet>" )
960 else:
961 # TODO: support killing router in physical network
962 pass
963 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
964 time.sleep( sleep )
965
966 @staticmethod
967 def recoverRouter( main, router, sleep=None ):
968 """
969 Restart bgpd process on a quagga router
970 router: name of the router to be recovered. E.g. "bgp1"
971 """
972 sleep = float( sleep )
973 main.step( "Recovering " + str( router ) )
974 if hasattr( main, 'Mininet1' ):
975 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
976 main.Mininet1.handle.expect( "mininet>" )
977 else:
978 # TODO: support recovering router in physical network
979 pass
980 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
981 time.sleep( sleep )
982
983 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700984 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700985 """
986 Stop Onos-cluster.
987 Stops Mininet
988 Copies ONOS log
989 """
You Wang4cc61912018-08-28 10:10:58 -0700990 from tests.dependencies.utils import Utils
991 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -0700992 for ctrl in main.Cluster.active():
993 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -0700994 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700995 if hasattr( main, "scapyHosts" ):
996 scapyResult = main.TRUE
997 for host in main.scapyHosts:
998 scapyResult = host.stopScapy() and scapyResult
999 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1000 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001001 if hasattr( main, 'Mininet1' ):
1002 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1003 else:
1004 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001005 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1006 main.scapyHosts = []
1007
You Wang5da39c82018-04-26 22:55:08 -07001008 if removeHostComponent:
1009 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1010 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001011 if hasattr( main, 'Mininet1' ):
1012 pass
1013 else:
1014 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001015 main.Network.removeHostComponent( host )
1016
You Wang5df1c6d2018-04-06 18:02:02 -07001017 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001018 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001019 else:
1020 main.Network.disconnectInbandHosts()
1021 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001022
You Wang5df1c6d2018-04-06 18:02:02 -07001023 if copyKarafLog:
1024 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001025
Devin Lim142b5342017-07-20 15:22:39 -07001026 for ctrl in main.Cluster.active():
1027 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001028 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001029
1030 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001031 def verifyNodes( main ):
1032 """
1033 Verifies Each active node in the cluster has an accurate view of other node's and their status
1034
1035 Params:
1036 nodes, integer array with position of the ONOS nodes in the CLIs array
1037 """
1038 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1039 False,
1040 attempts=10,
1041 sleep=10 )
1042 utilities.assert_equals( expect=True, actual=nodeResults,
1043 onpass="Nodes check successful",
1044 onfail="Nodes check NOT successful" )
1045
1046 if not nodeResults:
1047 for ctrl in main.Cluster.runningNodes:
1048 main.log.debug( "{} components not ACTIVE: \n{}".format(
1049 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001050 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001051 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001052 main.cleanAndExit()
1053
1054 @staticmethod
1055 def verifyTopology( main, switches, links, expNodes ):
1056 """
1057 Verifies that the ONOS cluster has an acuurate view of the topology
1058
1059 Params:
1060 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1061 """
1062 main.step( "Check number of topology elements" )
1063 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1064 main.FALSE,
1065 kwargs={ 'numoswitch': switches,
1066 'numolink': links,
1067 'numoctrl': expNodes },
1068 attempts=10,
1069 sleep=12 )
1070 utilities.assert_equals( expect=main.TRUE, actual=topology,
1071 onpass="Number of topology elements are correct",
1072 onfail="Unexpected number of links, switches, and/or controllers" )
1073
1074 @staticmethod
1075 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001076 """
1077 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1078 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1079 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1080 """
Jon Halla604fd42018-05-04 14:27:27 -07001081 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001082 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001083 if sleep is None:
1084 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1085 else:
1086 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001087
Jon Hall1efcb3f2016-08-23 13:42:15 -07001088 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001089 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001090 utilities.assert_equals( expect=main.TRUE, actual=killResult,
1091 onpass="ONOS instance Killed",
1092 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -07001093 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -07001094 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001095 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001096 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001097
Devin Lim142b5342017-07-20 15:22:39 -07001098 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001099 Testcaselib.verifyNodes( main )
1100 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001101
1102 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001103 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001104 """
1105 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1106 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1107 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1108 """
Jon Hall3c910162018-03-07 14:42:16 -08001109 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001110 if sleep is None:
1111 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1112 else:
1113 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001114 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Hall43060f62020-06-23 13:13:33 -07001115 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001116 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001117 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001118 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001119 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1120 onpass="ONOS service is ready",
1121 onfail="ONOS service did not start properly" )
1122 for i in nodes:
1123 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001124 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001125 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001126 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1127 commandlineTimeout=60,
1128 onosStartTimeout=100 )
1129 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001130 utilities.assert_equals( expect=main.TRUE,
1131 actual=cliResult,
1132 onpass="ONOS CLI is ready",
1133 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001134
Jon Halla604fd42018-05-04 14:27:27 -07001135 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001136 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001137 Testcaselib.verifyNodes( main )
1138 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001139
Devin Lim142b5342017-07-20 15:22:39 -07001140 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001141 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001142 attempts=10,
1143 sleep=12 )
1144 if ready:
1145 ready = main.TRUE
1146 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001147 onpass="ONOS summary command succeded",
1148 onfail="ONOS summary command failed" )
1149 if not ready:
1150 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001151 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001152
1153 @staticmethod
1154 def addHostCfg( main ):
1155 """
1156 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001157 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001158 """
1159 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001160 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001161 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001162 hostCfg = json.load( template )
1163 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1164 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001165 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001166 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1167 subjectClass="hosts",
1168 subjectKey=urllib.quote( mac,
1169 safe='' ),
1170 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001171 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1172 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001173 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001174 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1175 subjectClass="hosts",
1176 subjectKey=urllib.quote( mac,
1177 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001178 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001179 main.pingChart.update( { 'vlan1': { "expect": "True",
1180 "hosts": [ "olt1", "vsg1" ] } } )
1181 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1182 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001183 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001184 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001185 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1186 subjectClass="apps",
1187 subjectKey="org.onosproject.segmentrouting",
1188 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001189
1190 @staticmethod
1191 def delHostCfg( main ):
1192 """
1193 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001194 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001195 """
1196 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001197 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001198 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001199 hostCfg = json.load( template )
1200 main.step( "Removing host configuration" )
1201 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001202 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001203 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1204 subjectKey=urllib.quote(
1205 mac,
1206 safe='' ),
1207 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001208 main.step( "Removing configuration" )
1209 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001210 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001211 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1212 subjectKey=urllib.quote(
1213 mac,
1214 safe='' ),
1215 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001216 main.step( "Removing vlan configuration" )
1217 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001218 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1219 subjectKey="org.onosproject.segmentrouting",
1220 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001221
1222 @staticmethod
1223 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1224 """
1225 Verifies IP address assignment from the hosts
1226 """
1227 main.step( "Verify IP address assignment from hosts" )
1228 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001229 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001230 # Find out names of disconnected hosts
1231 disconnectedHosts = []
1232 if hasattr( main, "disconnectedIpv4Hosts" ):
1233 for host in main.disconnectedIpv4Hosts:
1234 disconnectedHosts.append( host )
1235 if hasattr( main, "disconnectedIpv6Hosts" ):
1236 for host in main.disconnectedIpv6Hosts:
1237 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001238 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001239 # Exclude disconnected hosts
1240 if hostName in disconnectedHosts:
1241 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1242 continue
You Wang53dba1e2018-02-02 17:45:44 -08001243 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1244 main.FALSE,
1245 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001246 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001247 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001248 attempts=attempts,
1249 sleep=sleep )
1250 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1251 onpass="Verify network host IP succeded",
1252 onfail="Verify network host IP failed" )
1253
1254 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001255 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001256 """
1257 Verifies host IP address assignment from ONOS
1258 """
1259 main.step( "Verify host IP address assignment in ONOS" )
1260 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001261 # Find out IPs of disconnected hosts
1262 disconnectedIps = []
1263 if hasattr( main, "disconnectedIpv4Hosts" ):
1264 for host in main.disconnectedIpv4Hosts:
1265 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1266 if hasattr( main, "disconnectedIpv6Hosts" ):
1267 for host in main.disconnectedIpv6Hosts:
1268 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001269 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001270 # Exclude disconnected hosts
1271 if ip in disconnectedIps:
1272 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1273 continue
You Wang53dba1e2018-02-02 17:45:44 -08001274 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1275 main.FALSE,
1276 kwargs={ 'hostList': [ hostName ],
1277 'prefix': ip },
1278 attempts=attempts,
1279 sleep=sleep )
1280 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1281 onpass="Verify ONOS host IP succeded",
1282 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001283 if not ipResult and skipOnFail:
1284 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001285 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001286 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001287
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001288 @staticmethod
1289 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1290 """
1291 Description:
1292 Updates interface configuration in ONOS, with given IP and vlan parameters
1293 Required:
1294 * connectPoint: connect point to update configuration
1295 Optional:
1296 * ips: list of IP addresses, combined with '/xx' subnet representation,
1297 corresponding to 'ips' field in the configuration
1298 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1299 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1300 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1301 """
1302 cfg = dict()
1303 cfg[ "ports" ] = dict()
1304 cfg[ "ports" ][ connectPoint ] = dict()
1305 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1306 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1307 if untagged > 0:
1308 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1309 else:
1310 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1311 if native > 0:
1312 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1313
1314 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001315
1316 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001317 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001318 """
1319 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001320 scapyNames: list of names that will be used as component names for scapy hosts
1321 mininetNames: used when scapy host names are different from the host names
1322 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1323 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001324 """
1325 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001326 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1327 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001328 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001329 if hasattr( main, 'Mininet1' ):
1330 main.Scapy.createHostComponent( scapyName )
1331 scapyHandle = getattr( main, scapyName )
1332 if mininetNames:
1333 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1334 else:
1335 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001336 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1337 scapyHandle.mExecDir = "/tmp"
1338 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1339 main.log.debug( "start mn host component in docker" )
1340 scapyHandle.startHostCli( mininetName,
1341 execDir="/tmp",
1342 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1343 else:
1344 main.log.debug( "start mn host component" )
1345 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001346 else:
You Wang0fc21702018-11-02 17:49:18 -07001347 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001348 scapyHandle = getattr( main, scapyName )
1349 scapyHandle.connectInband()
1350 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001351 scapyHandle.startScapy()
1352 scapyHandle.updateSelf()
1353 main.log.debug( scapyHandle.name )
1354 main.log.debug( scapyHandle.hostIp )
1355 main.log.debug( scapyHandle.hostMac )
1356
1357 @staticmethod
1358 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1359 """
1360 Verify unicast traffic by pinging from source hosts to the destination IP
1361 and capturing the packets at the destination host using Scapy.
1362 srcHosts: List of host names to send the ping packets
1363 dstIp: destination IP of the ping packets
1364 dstHost: host that runs Scapy to capture the packets
1365 dstIntf: name of the interface on the destination host
1366 expect: use True if the ping is expected to be captured at destination;
1367 Otherwise False
1368 skipOnFail: skip the rest of this test case if result is not expected
1369 maxRetry: number of retries allowed
1370 """
1371 from tests.dependencies.topology import Topology
1372 try:
1373 main.topo
1374 except ( NameError, AttributeError ):
1375 main.topo = Topology()
1376 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1377 result = main.TRUE
1378 for srcHost in srcHosts:
1379 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1380 expect, maxRetry, True )
1381 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001382 result = main.FALSE
1383 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1384 utilities.assert_equals( expect=main.TRUE,
1385 actual=result,
1386 onpass="Verify traffic to {}: Pass".format( dstIp ),
1387 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1388 if skipOnFail and result != main.TRUE:
1389 Testcaselib.saveOnosDiagnostics( main )
1390 Testcaselib.cleanup( main, copyKarafLog=False )
1391 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001392
1393 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001394 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001395 """
1396 Verify multicast traffic using scapy
1397 """
You Wangc564c6f2018-05-01 15:24:57 -07001398 from tests.dependencies.topology import Topology
1399 try:
1400 main.topo
1401 except ( NameError, AttributeError ):
1402 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001403 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001404 routeData = main.multicastConfig[ routeName ]
1405 srcs = main.mcastRoutes[ routeName ][ "src" ]
1406 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1407 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1408 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001409 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001410 for src in srcs:
1411 srcEntry = routeData[ "src" ][ src ]
1412 for dst in dsts:
1413 dstEntry = routeData[ "dst" ][ dst ]
1414 sender = getattr( main, srcEntry[ "host" ] )
1415 receiver = getattr( main, dstEntry[ "host" ] )
1416 main.Network.addRoute( str( srcEntry[ "host" ] ),
1417 str( routeData[ "group" ] ),
1418 str( srcEntry[ "interface" ] ),
1419 True if routeData[ "ipVersion" ] == 6 else False )
1420 # Build the packet
1421 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1422 if routeData[ "ipVersion" ] == 4:
1423 sender.buildIP( dst=str( routeData[ "group" ] ) )
1424 elif routeData[ "ipVersion" ] == 6:
1425 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1426 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1427 sIface = srcEntry[ "interface" ]
1428 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1429 pktFilter = srcEntry[ "filter" ]
1430 pkt = srcEntry[ "packet" ]
1431 # Send packet and check received packet
1432 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001433 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001434 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001435 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1436 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001437 if not trafficResult:
1438 result = main.FALSE
1439 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1440 dstEntry[ "host" ] ) )
1441 utilities.assert_equals( expect=main.TRUE,
1442 actual=result,
1443 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1444 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001445 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001446 Testcaselib.saveOnosDiagnostics( main )
1447 Testcaselib.cleanup( main, copyKarafLog=False )
1448 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001449
1450 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001451 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001452 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1453 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001454 """
1455 Verify reachability from each host in srcList to each host in dstList
1456 """
1457 from tests.dependencies.topology import Topology
1458 try:
1459 main.topo
1460 except ( NameError, AttributeError ):
1461 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001462 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001463 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001464 utilities.assert_equals( expect=main.TRUE,
1465 actual=pingResult,
1466 onpass="{}: Pass".format( stepMsg ),
1467 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001468 if not pingResult and skipOnFail:
1469 Testcaselib.saveOnosDiagnostics( main )
1470 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1471 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001472
1473 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001474 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001475 """
1476 Verify if the specified host is discovered by ONOS on the given locations
1477 Required:
You Wang85747762018-05-11 15:51:50 -07001478 locationDict: a dictionary that maps host names to expected locations.
1479 locations could be a string or a list.
1480 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001481 Returns:
1482 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1483 """
You Wang85747762018-05-11 15:51:50 -07001484 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1485 result = main.TRUE
1486 for hostName, locations in locationDict.items():
1487 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1488 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1489 if not hostIp:
1490 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1491 if not hostIp:
1492 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1493 result = main.FALSE
1494 continue
1495 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1496 main.FALSE,
1497 args=( hostIp, locations ),
1498 attempts=retry + 1,
1499 sleep=10 )
1500 if not locationResult:
1501 result = main.FALSE
1502 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001503 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001504 onpass="Location verification passed",
1505 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001506
1507 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001508 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001509 """
1510 Move specified host from srcSw to dstSw.
1511 If srcSw and dstSw are same, the host will be moved from current port to
1512 next available port.
1513 Required:
1514 hostName: name of the host. e.g., "h1"
1515 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1516 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1517 gw: ip address of the gateway of the new location
1518 Optional:
1519 macAddr: if specified, change MAC address of the host to the specified MAC address.
1520 prefixLen: prefix length
1521 cfg: port configuration as JSON string
1522 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001523 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001524 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001525 if not hasattr( main, 'Mininet1' ):
1526 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1527 return
1528
You Wang6e5b48e2018-07-23 16:17:38 -07001529 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1530 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1531 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001532 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001533 if cfg:
1534 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1535 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001536 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001537 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001538 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001539
1540 main.Mininet1.discoverHosts( [ hostName, ] )
1541
1542 # Update expectedHost when MAC address is changed.
1543 if macAddr is not None:
1544 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1545 if ipAddr is not None:
1546 for hostName, ip in main.expectedHosts[ "onos" ].items():
1547 if ip == ipAddr:
1548 vlan = hostName.split( "/" )[ -1 ]
1549 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001550 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001551 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001552
1553 @staticmethod
1554 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001555 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001556 """
1557 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1558 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1559 to next available port.
1560 Required:
1561 hostName: name of the host. e.g., "h1"
1562 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1563 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1564 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1565 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1566 gw: ip address of the gateway of the new location
1567 Optional:
1568 macAddr: if specified, change MAC address of the host to the specified MAC address.
1569 prefixLen: prefix length
1570 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001571 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001572 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001573 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001574 if not hasattr( main, 'Mininet1' ):
1575 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1576 return
1577
You Wang6e5b48e2018-07-23 16:17:38 -07001578 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1579 srcSw, srcPairSw, dstSw, dstPairSw ) )
1580 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1581 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1582 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001583 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001584 if cfg:
1585 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1586 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001587 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001588 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001589 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001590
1591 main.Mininet1.discoverHosts( [ hostName, ] )
1592
1593 # Update expectedHost when MAC address is changed.
1594 if macAddr is not None:
1595 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1596 if ipAddr is not None:
1597 for hostName, ip in main.expectedHosts[ "onos" ].items():
1598 if ip == ipAddr:
1599 vlan = hostName.split( "/" )[ -1 ]
1600 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001601 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001602
1603 @staticmethod
1604 def mnDockerSetup( main ):
1605 """
1606 Optionally start and setup docker image for mininet
1607 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001608 try:
1609 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001610
Jon Hall9b0de1f2020-08-24 15:38:04 -07001611 main.log.info( "Creating Mininet Docker" )
1612 handle = main.Mininet1.handle
1613 # build docker image
1614 dockerFilePath = "%s/../dependencies/" % main.testDir
1615 dockerName = "trellis_mininet"
1616 # Stop any leftover container
1617 main.Mininet1.dockerStop( dockerName )
1618 # TODO: assert on these docker calls
1619 main.Mininet1.dockerBuild( dockerFilePath, dockerName )
Jon Hallf6aeda22020-07-28 09:12:56 -07001620
Jon Hall9b0de1f2020-08-24 15:38:04 -07001621 confDir = "/tmp/mn_conf/"
1622 # Try to ensure the destination exists
1623 main.log.info( "Create folder for network config files" )
1624 handle.sendline( "rm -rf %s" % confDir )
1625 handle.expect( main.Mininet1.Prompt() )
1626 main.log.debug( handle.before + handle.after )
1627 handle.sendline( "mkdir -p %s" % confDir )
1628 handle.expect( main.Mininet1.Prompt() )
1629 main.log.debug( handle.before + handle.after )
1630 # Make sure permissions are correct
1631 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1632 handle.expect( main.Mininet1.Prompt() )
1633 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1634 handle.expect( main.Mininet1.Prompt() )
1635 main.log.debug( handle.before + handle.after )
1636 # Start docker container
1637 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1638 dockerName,
1639 main.params[ 'MN_DOCKER' ][ 'args' ] )
1640 if runResponse == main.FALSE:
1641 main.log.error( "Docker container already running, aborting test" )
1642 main.cleanup()
1643 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001644
Jon Hall9b0de1f2020-08-24 15:38:04 -07001645 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1646 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001647
Jon Hall9b0de1f2020-08-24 15:38:04 -07001648 # Fow when we create component handles
1649 main.Mininet1.mExecDir = "/tmp"
1650 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1651 main.Mininet1.hostPrompt = "/home/root#"
1652
1653 # For some reason docker isn't doing this
1654 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1655 main.Mininet1.handle.expect( "etc/hosts" )
1656 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1657 except Exception as e:
1658 main.log.exception( "Error seting up mininet" )
1659 man.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001660
1661 @staticmethod
1662 def mnDockerTeardown( main ):
1663 """
1664 Optionally stop and cleanup docker image for mininet
1665 """
1666
1667 if hasattr( main, 'Mininet1' ):
1668 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001669 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001670
1671 # Detach from container
1672 handle = main.Mininet1.handle
1673 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001674 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001675 main.Mininet1.sudoRequired = True
1676 except Exception as e:
1677 main.log.error( e )
1678
1679 @staticmethod
1680 def setOnosConfig( main ):
1681 """
1682 Read and Set onos configurations from the params file
1683 """
1684 main.step( "Set ONOS configurations" )
1685 config = main.params.get( 'ONOS_Configuration' )
1686 if config:
1687 main.log.debug( config )
1688 checkResult = main.TRUE
1689 for component in config:
1690 for setting in config[ component ]:
1691 value = config[ component ][ setting ]
1692 check = main.Cluster.next().setCfg( component, setting, value )
1693 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1694 checkResult = check and checkResult
1695 utilities.assert_equals( expect=main.TRUE,
1696 actual=checkResult,
1697 onpass="Successfully set config",
1698 onfail="Failed to set config" )
1699 else:
1700 main.log.warn( "No configurations were specified to be changed after startup" )
1701
1702 @staticmethod
1703 def setOnosLogLevels( main ):
1704 """
1705 Read and Set onos log levels from the params file
1706 """
1707 main.step( 'Set logging levels' )
1708 logging = True
1709 try:
1710 logs = main.params.get( 'ONOS_Logging', False )
1711 if logs:
1712 for namespace, level in logs.items():
1713 for ctrl in main.Cluster.active():
1714 ctrl.CLI.logSet( level, namespace )
1715 except AttributeError:
1716 logging = False
1717 utilities.assert_equals( expect=True, actual=logging,
1718 onpass="Set log levels",
1719 onfail="Failed to set log levels" )