blob: e20e31a4624367fe982ff6f7ba366e9019de3a7a [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
Jon Hall10e2ab82020-09-15 17:14:54 -0700187 def loadXconnects( main, suffix='' ):
188 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
189 main.cfgName, suffix ) ) as cfg:
190 for xconnect in json.load( cfg ).get('xconnects'):
191 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
192
193 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800194 def loadChart( main ):
195 try:
196 with open( "%s%s.chart" % ( main.configPath + main.forChart,
197 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700198 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800199 except IOError:
200 main.log.warn( "No chart file found." )
201
202 @staticmethod
203 def loadHost( main ):
204 with open( "%s%s.host" % ( main.configPath + main.forHost,
205 main.cfgName ) ) as host:
206 main.expectedHosts = json.load( host )
207
208 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800209 def loadSwitchFailureChart( main ):
210 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
211 main.cfgName ) ) as sfc:
212 main.switchFailureChart = json.load( sfc )
213
214 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800215 def loadLinkFailureChart( main ):
216 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700217 main.cfgName ) ) as lfc:
218 main.linkFailureChart = json.load( lfc )
219
220 @staticmethod
221 def loadMulticastConfig( main ):
222 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
223 main.cfgName ) ) as cfg:
224 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800225
226 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700227 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700228 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800229 copyResult = main.ONOSbench.scp( main.Mininet1,
230 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700231 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800232 direction="to" )
233 if main.topologyLib:
234 for lib in main.topologyLib.split(","):
235 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
236 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700237 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800238 direction="to" )
239 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700240 import re
241 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
242 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700243 destDir = "~/"
244 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
245 destDir = "/tmp/mn_conf/"
246 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800247 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700248 # Update zebra configurations with correct ONOS instance IP
249 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
250 ip = controllerIPs[ index ]
251 index = ( index + 1 ) % len( controllerIPs )
252 with open( main.configPath + main.forConfig + conf ) as f:
253 s = f.read()
254 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
255 with open( main.configPath + main.forConfig + conf, "w" ) as f:
256 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800257 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800258 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700259 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800260 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800261 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700262 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800263 main.Mininet1.home + "custom",
264 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700265
266 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
267 # move the config files into home
268 main.Mininet1.handle.sendline( "cp config/* . " )
269 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
270 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
271 main.Mininet1.handle.sendline( "ls -al " )
272 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
273 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
274
You Wangd87b2312018-01-30 12:47:17 -0800275 stepResult = copyResult
276 utilities.assert_equals( expect=main.TRUE,
277 actual=stepResult,
278 onpass="Successfully copied topo files",
279 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700280 if main.stratumRoot:
281 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700282 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700283 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700284 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700285 main.topology = topology
286 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700287 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700288 stepResult = topoResult
289 utilities.assert_equals( expect=main.TRUE,
290 actual=stepResult,
291 onpass="Successfully loaded topology",
292 onfail="Failed to load topology" )
293 # Exit if topology did not load properly
294 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700295 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700296 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700297 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700298 # Upload the net-cfg file created for each switch
299 filename = "onos-netcfg.json"
300 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700301 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700302 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
303 path = "/tmp/mn-stratum/%s/" % switch
304 dstPath = "/tmp/"
305 dstFileName = "%s-onos-netcfg.json" % switch
306 main.ONOSbench1.scp( main.Mininet1,
307 "%s%s" % ( path, filename ),
308 "%s%s" % ( dstPath, dstFileName ),
309 "from" )
310 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 -0700311 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700312 # Configure managementAddress
313 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
314 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
315 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
316 # Configure device id
317 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
318 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
319 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
320 # Configure device name
321 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s\",' %s%s" % ( switch, dstPath, dstFileName ) )
322 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
323 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700324 node = main.Cluster.active(0)
325 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
326 dstPath,
327 dstFileName,
328 user=node.REST.user_name,
329 password=node.REST.pwd )
330 # Stop test if we fail to push switch netcfg
331 utilities.assert_equals( expect=main.TRUE,
332 actual=switchNetCfg,
333 onpass="Successfully pushed switch netcfg",
334 onfail="Failed to configure switches in onos" )
335 if not switchNetCfg:
336 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700337 # Make sure hosts make some noise
338 Testcaselib.discoverHosts( main )
339
340 @staticmethod
341 def discoverHosts( main ):
342 # TODO add option to only select specific hosts
343 if hasattr( main, "Mininet1" ):
344 network = main.Mininet1
345 elif hasattr( main, "NetworkBench" ):
346 network = main.NetworkBench
347 else:
348 main.log.warn( "Could not find component for test network, skipping host discovery" )
349 return
350 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700351
352 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700353 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800354 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700355 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800356 topoResult = main.NetworkBench.connectToNet()
357 stepResult = topoResult
358 utilities.assert_equals( expect=main.TRUE,
359 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700360 onpass="Successfully connected to topology",
361 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800362 # Exit if topology did not load properly
363 if not topoResult:
364 main.cleanAndExit()
365
Jon Hall43060f62020-06-23 13:13:33 -0700366 # Perform any optional setup
367 for switch in main.NetworkBench.switches:
368 if hasattr( switch, "setup" ):
369 switch.setup() # We might not need this
370
You Wang84f981d2018-01-12 16:11:50 -0800371 main.step( "Assign switches to controllers." )
Jon Hall43060f62020-06-23 13:13:33 -0700372 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700373 switches = main.NetworkBench.getSwitches()
374 pool = []
375 for name in switches.keys():
Jon Hall43060f62020-06-23 13:13:33 -0700376 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
377 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700378 thread = main.Thread( target=main.NetworkBench.assignSwController,
379 name="assignSwitchToController",
380 args=[ name, main.Cluster.getIps(), '6653' ] )
381 pool.append( thread )
382 thread.start()
383 for thread in pool:
384 thread.join( 300 )
385 if not thread.result:
386 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800387 utilities.assert_equals( expect=main.TRUE,
388 actual=stepResult,
389 onpass="Successfully assign switches to controllers",
390 onfail="Failed to assign switches to controllers" )
391
You Wang4cc61912018-08-28 10:10:58 -0700392 # Check devices
393 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700394 # Connecting to hosts that only have data plane connectivity
395 main.step( "Connecting inband hosts" )
396 stepResult = main.Network.connectInbandHosts()
397 utilities.assert_equals( expect=main.TRUE,
398 actual=stepResult,
399 onpass="Successfully connected inband hosts",
400 onfail="Failed to connect inband hosts" )
Jon Hall43060f62020-06-23 13:13:33 -0700401 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700402
You Wang84f981d2018-01-12 16:11:50 -0800403 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700404 def saveOnosDiagnostics( main ):
405 """
406 Get onos-diags.tar.gz and save it to the log directory.
407 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
408 """
409 main.log.info( "Collecting onos-diags..." )
410 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
411 main.logdir,
412 "-CASE%d" % main.CurrentTestCaseNumber )
413
414 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700415 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700416 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700417
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700418 main.failures = int( main.params[ 'failures' ] )
419 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700420
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700421 if main.cfgName == '2x2':
422 spine = {}
423 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
424 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
425 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700426
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700427 spine = {}
428 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
429 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
430 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700431
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700432 elif main.cfgName == '4x4':
433 spine = {}
434 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
435 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
436 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700437
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700438 spine = {}
439 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
440 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
441 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700442
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700443 spine = {}
444 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
445 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
446 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700447
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700448 spine = {}
449 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
450 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
451 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700452
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700453 else:
Piera2a7e1b2016-10-04 11:51:43 -0700454 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700455 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800456
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800457 @staticmethod
458 def addStaticOnosRoute( main, subnet, intf):
459 """
460 Adds an ONOS static route with the use route-add command.
461 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800462 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
463
Piera2a7e1b2016-10-04 11:51:43 -0700464 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700465 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700466 """
467 Check number of groups for each subnet on device deviceId and matches
468 it with an expected value. subnetDict is a dictionarty containing values
469 of the type "10.0.1.0/24" : 5.
470 """
You Wangc02f3be2018-05-18 12:14:23 -0700471 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
472 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
473 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700474
You Wangc02f3be2018-05-18 12:14:23 -0700475 result = main.TRUE
476 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700477 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700478 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700479 # this will match the group id that this flow entry points to, for example :
480 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700481 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700482 count = 0
483 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700484 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700485 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700486 if count - 1 != numberInSelect:
487 result = main.FALSE
488 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 ) )
489 utilities.assert_equals( expect=main.TRUE, actual=result,
490 onpass="All bucket numbers are as expected",
491 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700492
493 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900494 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700495 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800496 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900497 if tag == "":
498 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700499 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700500 main.FALSE,
501 kwargs={ 'min': minFlowCount },
502 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800503 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800504 if count == main.FALSE:
505 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700506 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700507 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800508 actual=( count > minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700509 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
510 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700511
512 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700513 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700514 main.FALSE,
515 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800516 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800517 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700518 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700519 expect=main.TRUE,
520 actual=flowCheck,
521 onpass="Flow status is correct!",
522 onfail="Flow status is wrong!" )
523 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700524 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700525 "flows",
526 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900527 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700528 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700529 "groups",
530 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900531 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700532
533 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700534 def checkDevices( main, switches, tag="", sleep=10 ):
535 main.step(
536 "Check whether the switches count is equal to %s" % switches )
537 if tag == "":
538 tag = 'CASE%d' % main.CurrentTestCaseNumber
539 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
540 main.FALSE,
541 kwargs={ 'numoswitch': switches},
542 attempts=10,
543 sleep=sleep )
544 utilities.assert_equals( expect=main.TRUE, actual=result,
545 onpass="Device up successful",
546 onfail="Failed to boot up devices?" )
547
548 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800549 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
550 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700551 "Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800552 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
553 main.FALSE,
554 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800555 attempts=5,
556 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800557 if count == main.FALSE:
558 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800559 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800560 expect=True,
561 actual=( count > minFlowCount ),
562 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800563 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800564
565 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700566 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800567 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700568 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800569 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
570 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700571 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800572 attempts=5,
573 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800574 if count == main.FALSE:
575 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800576 utilities.assertEquals(
577 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800578 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700579 onpass="Flow count looks correct: " + str( count ) ,
580 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800581
582 @staticmethod
583 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
584 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700585 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800586 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
587 main.FALSE,
588 args=( dpid, groupCount, False, 1),
589 attempts=5,
590 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800591 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800592 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800593 utilities.assertEquals(
594 expect=True,
595 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700596 onpass="Group count looks correct: " + str( count ) ,
597 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800598
599 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700600 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800601
602 for dpid, values in main.count.items():
603 flowCount = values["flows"]
604 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700605 main.log.report( "Check flow count for dpid " + str( dpid ) +
606 ", should be " + str( flowCount ) )
607 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800608
Jon Hall9677ed32018-04-24 11:16:23 -0700609 main.log.report( "Check group count for dpid " + str( dpid ) +
610 ", should be " + str( groupCount ) )
611 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800612
613 return
614
615 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700616 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
617 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800618 '''
You Wangba231e72018-03-01 13:18:21 -0800619 Verify connectivity between hosts according to the ping chart
620 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800621 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800622 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800623 '''
You Wangba231e72018-03-01 13:18:21 -0800624 main.log.report( "Check host connectivity" )
625 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800626 if tag == "":
627 tag = 'CASE%d' % main.CurrentTestCaseNumber
628 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800629 main.log.debug( "Entry in ping chart: %s" % entry )
630 expect = entry[ 'expect' ]
631 if expect == "Unidirectional":
632 # Verify ping from each src host to each dst host
633 src = entry[ 'src' ]
634 dst = entry[ 'dst' ]
635 expect = main.TRUE
636 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
637 if basedOnIp:
638 if ("v4" in src[0]):
639 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
640 utilities.assert_equals( expect=expect, actual=pa,
641 onpass="IPv4 connectivity successfully tested",
642 onfail="IPv4 connectivity failed" )
643 if ("v6" in src[0]):
644 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
645 utilities.assert_equals( expect=expect, actual=pa,
646 onpass="IPv6 connectivity successfully tested",
647 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700648 elif main.physicalNet:
649 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
650 utilities.assert_equals( expect=expect, actual=pa,
651 onpass="IP connectivity successfully tested",
652 onfail="IP connectivity failed" )
653
You Wangba231e72018-03-01 13:18:21 -0800654 else:
655 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
656 utilities.assert_equals( expect=expect, actual=pa,
657 onpass="IP connectivity successfully tested",
658 onfail="IP connectivity failed" )
659 else:
660 # Verify ping between each host pair
661 hosts = entry[ 'hosts' ]
662 try:
663 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
664 except:
665 expect = main.FALSE
666 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
667 if basedOnIp:
668 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800669 pa = utilities.retry( main.Network.pingallHosts,
670 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700671 args=(hosts, ),
672 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800673 attempts=retryAttempts,
674 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800675 utilities.assert_equals( expect=expect, actual=pa,
676 onpass="IPv4 connectivity successfully tested",
677 onfail="IPv4 connectivity failed" )
678 if ("v6" in hosts[0]):
679 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
680 utilities.assert_equals( expect=expect, actual=pa,
681 onpass="IPv6 connectivity successfully tested",
682 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700683 elif main.physicalNet:
684 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
685 utilities.assert_equals( expect=expect, actual=pa,
686 onpass="IP connectivity successfully tested",
687 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800688 else:
You Wangf19d9f42018-02-23 16:34:19 -0800689 pa = main.Network.pingallHosts( hosts )
690 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800691 onpass="IP connectivity successfully tested",
692 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700693 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700694 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700695 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700696 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700697 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800698
699 if dumpflows:
700 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
701 "flows",
702 main.logdir,
703 tag + "_FlowsOn" )
704 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
705 "groups",
706 main.logdir,
707 tag + "_GroupsOn" )
708
709 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700710 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700711 """
712 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
713 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
714 Kill a link and verify ONOS can see the proper link change
715 """
Jon Halla604fd42018-05-04 14:27:27 -0700716 if sleep is None:
717 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
718 else:
719 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700720 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700721 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
722 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700723 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
724 onpass="Link down successful",
725 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700726 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700727 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700728 "Waiting %s seconds for link down to be discovered" % sleep )
729 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700730 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700731 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700732 main.FALSE,
733 kwargs={ 'numoswitch': switches,
734 'numolink': links },
735 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700736 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700737 utilities.assert_equals( expect=main.TRUE, actual=topology,
738 onpass="Topology after link down is correct",
739 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700740
741 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700742 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800743 """
744 links = list of links (src, dst) to bring down.
745 """
746
747 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700748 if sleep is None:
749 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
750 else:
751 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800752
753 for end1, end2 in links:
754 main.Network.link( END1=end1, END2=end2, OPTION="down")
755 main.Network.link( END1=end2, END2=end1, OPTION="down")
756
Jon Halla604fd42018-05-04 14:27:27 -0700757 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800758 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700759 "Waiting %s seconds for links down to be discovered" % sleep )
760 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800761
762 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
763 main.FALSE,
764 kwargs={ 'numoswitch': switches,
765 'numolink': linksAfter },
766 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700767 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800768
You Wang2854bce2018-03-30 10:15:32 -0700769 utilities.assert_equals( expect=main.TRUE, actual=topology,
770 onpass="Link batch down successful",
771 onfail="Link batch down failed" )
772
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800773 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700774 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800775 """
776 links = list of link (src, dst) to bring up again.
777 """
778
779 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700780 if sleep is None:
781 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
782 else:
783 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800784
785 for end1, end2 in links:
786 main.Network.link( END1=end1, END2=end2, OPTION="up")
787 main.Network.link( END1=end2, END2=end1, OPTION="up")
788
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800789 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700790 "Waiting %s seconds for links up to be discovered" % sleep )
791 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800792
793 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
794 main.FALSE,
795 kwargs={ 'numoswitch': switches,
796 'numolink': linksAfter },
797 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700798 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800799
You Wang2854bce2018-03-30 10:15:32 -0700800 utilities.assert_equals( expect=main.TRUE, actual=topology,
801 onpass="Link batch up successful",
802 onfail="Link batch up failed" )
803
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800804 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700805 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
806 """
807 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
808 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
809 switches, links: number of expected switches and links after link change, ex.: '4', '6'
810 """
811 if sleep is None:
812 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
813 else:
814 sleep = float( sleep )
815 main.step( "Disable a batch of ports" )
816 for dpid, port in ports:
817 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
818 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
819 time.sleep( sleep )
820 if switches and links:
821 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
822 numolink=links )
823 utilities.assert_equals( expect=main.TRUE, actual=result,
824 onpass="Port down successful",
825 onfail="Port down failed" )
826
827 @staticmethod
828 def enablePortBatch( main, ports, switches, links, sleep=None ):
829 """
830 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
831 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
832 switches, links: number of expected switches and links after link change, ex.: '4', '6'
833 """
834 if sleep is None:
835 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
836 else:
837 sleep = float( sleep )
838 main.step( "Enable a batch of ports" )
839 for dpid, port in ports:
840 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
841 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
842 time.sleep( sleep )
843 if switches and links:
844 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
845 numolink=links )
846 utilities.assert_equals( expect=main.TRUE, actual=result,
847 onpass="Port up successful",
848 onfail="Port up failed" )
849
850 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700851 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700852 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700853 """
854 Params:
855 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700856 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700857 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
858 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
859 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
860 Kill a link and verify ONOS can see the proper link change
861 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700862 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700863 if sleep is None:
864 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
865 else:
866 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700867 result = False
868 count = 0
869 while True:
870 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700871 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800872 main.Network.link( END1=end1, END2=end2, OPTION="up" )
873 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700874 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700875 "Waiting %s seconds for link up to be discovered" % sleep )
876 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700877
You Wangc02d8352018-04-17 16:42:10 -0700878 if portUp:
879 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
880 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700881 main.log.info(
882 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700883 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700884
Jon Halla604fd42018-05-04 14:27:27 -0700885 result = ctrl.CLI.checkStatus( numoswitch=switches,
886 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700887 if count > 5 or result:
888 break
889 utilities.assert_equals( expect=main.TRUE, actual=result,
890 onpass="Link up successful",
891 onfail="Failed to bring link up" )
892
893 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700894 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700895 """
896 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
897 Completely kill a switch and verify ONOS can see the proper change
898 """
Jon Halla604fd42018-05-04 14:27:27 -0700899 if sleep is None:
900 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
901 else:
902 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700903 switch = switch if isinstance( switch, list ) else [ switch ]
904 main.step( "Kill " + str( switch ) )
905 for s in switch:
906 main.log.info( "Stopping " + s )
907 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700908 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700909
910 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700911 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700912 sleep ) )
913 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700914 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700915 main.FALSE,
916 kwargs={ 'numoswitch': switches,
917 'numolink': links },
918 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700919 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700920 utilities.assert_equals( expect=main.TRUE, actual=topology,
921 onpass="Kill switch successful",
922 onfail="Failed to kill switch?" )
923
924 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700925 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700926 """
927 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
928 Recover a switch and verify ONOS can see the proper change
929 """
Jon Halla604fd42018-05-04 14:27:27 -0700930 if sleep is None:
931 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
932 else:
933 sleep = float( sleep )
934 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700935 switch = switch if isinstance( switch, list ) else [ switch ]
936 main.step( "Recovering " + str( switch ) )
937 for s in switch:
938 main.log.info( "Starting " + s )
939 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700940 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700941 sleep ) )
942 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700943 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700944 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700945 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700946 sleep ) )
947 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700948
Devin Lim142b5342017-07-20 15:22:39 -0700949 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700950 main.FALSE,
951 kwargs={ 'numoswitch': switches,
952 'numolink': links },
953 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700954 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700955 utilities.assert_equals( expect=main.TRUE, actual=topology,
956 onpass="Switch recovery successful",
957 onfail="Failed to recover switch?" )
958
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700959 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700960 def killRouter( main, router, sleep=None ):
961 """
962 Kill bgpd process on a quagga router
963 router: name of the router to be killed. E.g. "bgp1"
964 """
965 sleep = float( sleep )
966 main.step( "Kill " + str( router ) )
967 if hasattr( main, 'Mininet1' ):
968 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
969 main.Mininet1.handle.expect( "mininet>" )
970 else:
971 # TODO: support killing router in physical network
972 pass
973 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
974 time.sleep( sleep )
975
976 @staticmethod
977 def recoverRouter( main, router, sleep=None ):
978 """
979 Restart bgpd process on a quagga router
980 router: name of the router to be recovered. E.g. "bgp1"
981 """
982 sleep = float( sleep )
983 main.step( "Recovering " + str( router ) )
984 if hasattr( main, 'Mininet1' ):
985 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
986 main.Mininet1.handle.expect( "mininet>" )
987 else:
988 # TODO: support recovering router in physical network
989 pass
990 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
991 time.sleep( sleep )
992
993 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700994 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700995 """
996 Stop Onos-cluster.
997 Stops Mininet
998 Copies ONOS log
999 """
You Wang4cc61912018-08-28 10:10:58 -07001000 from tests.dependencies.utils import Utils
1001 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -07001002 for ctrl in main.Cluster.active():
1003 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001004 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001005 if hasattr( main, "scapyHosts" ):
1006 scapyResult = main.TRUE
1007 for host in main.scapyHosts:
1008 scapyResult = host.stopScapy() and scapyResult
1009 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1010 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001011 if hasattr( main, 'Mininet1' ):
1012 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1013 else:
1014 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001015 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1016 main.scapyHosts = []
1017
You Wang5da39c82018-04-26 22:55:08 -07001018 if removeHostComponent:
1019 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1020 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001021 if hasattr( main, 'Mininet1' ):
1022 pass
1023 else:
1024 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001025 main.Network.removeHostComponent( host )
1026
You Wang5df1c6d2018-04-06 18:02:02 -07001027 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001028 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001029 else:
1030 main.Network.disconnectInbandHosts()
1031 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001032
You Wang5df1c6d2018-04-06 18:02:02 -07001033 if copyKarafLog:
1034 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001035
Devin Lim142b5342017-07-20 15:22:39 -07001036 for ctrl in main.Cluster.active():
1037 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001038 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001039
1040 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001041 def verifyNodes( main ):
1042 """
1043 Verifies Each active node in the cluster has an accurate view of other node's and their status
1044
1045 Params:
1046 nodes, integer array with position of the ONOS nodes in the CLIs array
1047 """
1048 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1049 False,
1050 attempts=10,
1051 sleep=10 )
1052 utilities.assert_equals( expect=True, actual=nodeResults,
1053 onpass="Nodes check successful",
1054 onfail="Nodes check NOT successful" )
1055
1056 if not nodeResults:
1057 for ctrl in main.Cluster.runningNodes:
1058 main.log.debug( "{} components not ACTIVE: \n{}".format(
1059 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001060 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001061 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001062 main.cleanAndExit()
1063
1064 @staticmethod
1065 def verifyTopology( main, switches, links, expNodes ):
1066 """
1067 Verifies that the ONOS cluster has an acuurate view of the topology
1068
1069 Params:
1070 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1071 """
1072 main.step( "Check number of topology elements" )
1073 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1074 main.FALSE,
1075 kwargs={ 'numoswitch': switches,
1076 'numolink': links,
1077 'numoctrl': expNodes },
1078 attempts=10,
1079 sleep=12 )
1080 utilities.assert_equals( expect=main.TRUE, actual=topology,
1081 onpass="Number of topology elements are correct",
1082 onfail="Unexpected number of links, switches, and/or controllers" )
1083
1084 @staticmethod
1085 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001086 """
1087 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1088 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1089 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1090 """
Jon Halla604fd42018-05-04 14:27:27 -07001091 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001092 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001093 if sleep is None:
1094 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1095 else:
1096 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001097
Jon Hall214f88b2020-09-21 10:21:42 -07001098 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001099 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001100 node = main.Cluster.runningNodes[ i ]
1101 if node.inDocker:
1102 killResult = node.server.dockerStop( node.name )
1103 else:
1104 killResult = main.ONOSbench.onosDie( node.ipAddress )
1105 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001106 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001107 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1108 onpass="ONOS instance Killed",
1109 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001110 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001111 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001112 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001113
Devin Lim142b5342017-07-20 15:22:39 -07001114 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001115 Testcaselib.verifyNodes( main )
1116 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001117
1118 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001119 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001120 """
1121 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1122 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1123 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1124 """
Jon Hall3c910162018-03-07 14:42:16 -08001125 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001126 if sleep is None:
1127 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1128 else:
1129 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001130 for i in nodes:
1131 node = main.Cluster.runningNodes[ i ]
1132 if node.inDocker:
1133 main.Cluster.startONOSDockerNode( i )
1134 else:
1135 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001136 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001137 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001138 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001139 node = main.Cluster.runningNodes[ i ]
1140 if node.inDocker:
1141 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1142 isUp = isUp and node.CLI.prepareForCLI()
1143 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1144 else:
1145 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001146 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1147 onpass="ONOS service is ready",
1148 onfail="ONOS service did not start properly" )
1149 for i in nodes:
1150 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001151 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001152 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001153 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1154 commandlineTimeout=60,
1155 onosStartTimeout=100 )
1156 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001157 utilities.assert_equals( expect=main.TRUE,
1158 actual=cliResult,
1159 onpass="ONOS CLI is ready",
1160 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001161
Jon Halla604fd42018-05-04 14:27:27 -07001162 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001163 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001164 Testcaselib.verifyNodes( main )
1165 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001166
Devin Lim142b5342017-07-20 15:22:39 -07001167 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001168 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001169 attempts=10,
1170 sleep=12 )
1171 if ready:
1172 ready = main.TRUE
1173 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001174 onpass="ONOS summary command succeded",
1175 onfail="ONOS summary command failed" )
1176 if not ready:
1177 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001178 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001179
1180 @staticmethod
1181 def addHostCfg( main ):
1182 """
1183 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001184 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001185 """
1186 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001187 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001188 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001189 hostCfg = json.load( template )
1190 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1191 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001192 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001193 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1194 subjectClass="hosts",
1195 subjectKey=urllib.quote( mac,
1196 safe='' ),
1197 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001198 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1199 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001200 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001201 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1202 subjectClass="hosts",
1203 subjectKey=urllib.quote( mac,
1204 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001205 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001206 main.pingChart.update( { 'vlan1': { "expect": "True",
1207 "hosts": [ "olt1", "vsg1" ] } } )
1208 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1209 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001210 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1211 vlanId=1,
1212 port1=5,
1213 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001214
1215 @staticmethod
1216 def delHostCfg( main ):
1217 """
1218 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001219 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001220 """
1221 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001222 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001223 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001224 hostCfg = json.load( template )
1225 main.step( "Removing host configuration" )
1226 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001227 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001228 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1229 subjectKey=urllib.quote(
1230 mac,
1231 safe='' ),
1232 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001233 main.step( "Removing configuration" )
1234 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001235 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001236 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1237 subjectKey=urllib.quote(
1238 mac,
1239 safe='' ),
1240 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001241 main.step( "Removing vlan configuration" )
1242 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001243 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1244 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001245
1246 @staticmethod
1247 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1248 """
1249 Verifies IP address assignment from the hosts
1250 """
1251 main.step( "Verify IP address assignment from hosts" )
1252 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001253 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001254 # Find out names of disconnected hosts
1255 disconnectedHosts = []
1256 if hasattr( main, "disconnectedIpv4Hosts" ):
1257 for host in main.disconnectedIpv4Hosts:
1258 disconnectedHosts.append( host )
1259 if hasattr( main, "disconnectedIpv6Hosts" ):
1260 for host in main.disconnectedIpv6Hosts:
1261 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001262 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001263 # Exclude disconnected hosts
1264 if hostName in disconnectedHosts:
1265 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1266 continue
You Wang53dba1e2018-02-02 17:45:44 -08001267 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1268 main.FALSE,
1269 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001270 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001271 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001272 attempts=attempts,
1273 sleep=sleep )
1274 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1275 onpass="Verify network host IP succeded",
1276 onfail="Verify network host IP failed" )
1277
1278 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001279 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001280 """
1281 Verifies host IP address assignment from ONOS
1282 """
1283 main.step( "Verify host IP address assignment in ONOS" )
1284 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001285 # Find out IPs of disconnected hosts
1286 disconnectedIps = []
1287 if hasattr( main, "disconnectedIpv4Hosts" ):
1288 for host in main.disconnectedIpv4Hosts:
1289 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1290 if hasattr( main, "disconnectedIpv6Hosts" ):
1291 for host in main.disconnectedIpv6Hosts:
1292 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001293 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001294 # Exclude disconnected hosts
1295 if ip in disconnectedIps:
1296 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1297 continue
You Wang53dba1e2018-02-02 17:45:44 -08001298 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1299 main.FALSE,
1300 kwargs={ 'hostList': [ hostName ],
1301 'prefix': ip },
1302 attempts=attempts,
1303 sleep=sleep )
1304 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1305 onpass="Verify ONOS host IP succeded",
1306 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001307 if not ipResult and skipOnFail:
1308 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001309 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001310 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001311
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001312 @staticmethod
1313 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1314 """
1315 Description:
1316 Updates interface configuration in ONOS, with given IP and vlan parameters
1317 Required:
1318 * connectPoint: connect point to update configuration
1319 Optional:
1320 * ips: list of IP addresses, combined with '/xx' subnet representation,
1321 corresponding to 'ips' field in the configuration
1322 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1323 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1324 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1325 """
1326 cfg = dict()
1327 cfg[ "ports" ] = dict()
1328 cfg[ "ports" ][ connectPoint ] = dict()
1329 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1330 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1331 if untagged > 0:
1332 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1333 else:
1334 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1335 if native > 0:
1336 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1337
1338 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001339
1340 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001341 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001342 """
1343 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001344 scapyNames: list of names that will be used as component names for scapy hosts
1345 mininetNames: used when scapy host names are different from the host names
1346 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1347 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001348 """
1349 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001350 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1351 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001352 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001353 if hasattr( main, 'Mininet1' ):
1354 main.Scapy.createHostComponent( scapyName )
1355 scapyHandle = getattr( main, scapyName )
1356 if mininetNames:
1357 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1358 else:
1359 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001360 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1361 scapyHandle.mExecDir = "/tmp"
1362 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1363 main.log.debug( "start mn host component in docker" )
1364 scapyHandle.startHostCli( mininetName,
1365 execDir="/tmp",
1366 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1367 else:
1368 main.log.debug( "start mn host component" )
1369 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001370 else:
You Wang0fc21702018-11-02 17:49:18 -07001371 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001372 scapyHandle = getattr( main, scapyName )
1373 scapyHandle.connectInband()
1374 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001375 scapyHandle.startScapy()
1376 scapyHandle.updateSelf()
1377 main.log.debug( scapyHandle.name )
1378 main.log.debug( scapyHandle.hostIp )
1379 main.log.debug( scapyHandle.hostMac )
1380
1381 @staticmethod
1382 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1383 """
1384 Verify unicast traffic by pinging from source hosts to the destination IP
1385 and capturing the packets at the destination host using Scapy.
1386 srcHosts: List of host names to send the ping packets
1387 dstIp: destination IP of the ping packets
1388 dstHost: host that runs Scapy to capture the packets
1389 dstIntf: name of the interface on the destination host
1390 expect: use True if the ping is expected to be captured at destination;
1391 Otherwise False
1392 skipOnFail: skip the rest of this test case if result is not expected
1393 maxRetry: number of retries allowed
1394 """
1395 from tests.dependencies.topology import Topology
1396 try:
1397 main.topo
1398 except ( NameError, AttributeError ):
1399 main.topo = Topology()
1400 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1401 result = main.TRUE
1402 for srcHost in srcHosts:
1403 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1404 expect, maxRetry, True )
1405 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001406 result = main.FALSE
1407 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1408 utilities.assert_equals( expect=main.TRUE,
1409 actual=result,
1410 onpass="Verify traffic to {}: Pass".format( dstIp ),
1411 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1412 if skipOnFail and result != main.TRUE:
1413 Testcaselib.saveOnosDiagnostics( main )
1414 Testcaselib.cleanup( main, copyKarafLog=False )
1415 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001416
1417 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001418 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001419 """
1420 Verify multicast traffic using scapy
1421 """
You Wangc564c6f2018-05-01 15:24:57 -07001422 from tests.dependencies.topology import Topology
1423 try:
1424 main.topo
1425 except ( NameError, AttributeError ):
1426 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001427 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001428 routeData = main.multicastConfig[ routeName ]
1429 srcs = main.mcastRoutes[ routeName ][ "src" ]
1430 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1431 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1432 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001433 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001434 for src in srcs:
1435 srcEntry = routeData[ "src" ][ src ]
1436 for dst in dsts:
1437 dstEntry = routeData[ "dst" ][ dst ]
1438 sender = getattr( main, srcEntry[ "host" ] )
1439 receiver = getattr( main, dstEntry[ "host" ] )
1440 main.Network.addRoute( str( srcEntry[ "host" ] ),
1441 str( routeData[ "group" ] ),
1442 str( srcEntry[ "interface" ] ),
1443 True if routeData[ "ipVersion" ] == 6 else False )
1444 # Build the packet
1445 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1446 if routeData[ "ipVersion" ] == 4:
1447 sender.buildIP( dst=str( routeData[ "group" ] ) )
1448 elif routeData[ "ipVersion" ] == 6:
1449 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1450 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1451 sIface = srcEntry[ "interface" ]
1452 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1453 pktFilter = srcEntry[ "filter" ]
1454 pkt = srcEntry[ "packet" ]
1455 # Send packet and check received packet
1456 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001457 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001458 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001459 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1460 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001461 if not trafficResult:
1462 result = main.FALSE
1463 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1464 dstEntry[ "host" ] ) )
1465 utilities.assert_equals( expect=main.TRUE,
1466 actual=result,
1467 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1468 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001469 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001470 Testcaselib.saveOnosDiagnostics( main )
1471 Testcaselib.cleanup( main, copyKarafLog=False )
1472 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001473
1474 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001475 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001476 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1477 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001478 """
1479 Verify reachability from each host in srcList to each host in dstList
1480 """
1481 from tests.dependencies.topology import Topology
1482 try:
1483 main.topo
1484 except ( NameError, AttributeError ):
1485 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001486 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001487 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001488 utilities.assert_equals( expect=main.TRUE,
1489 actual=pingResult,
1490 onpass="{}: Pass".format( stepMsg ),
1491 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001492 if not pingResult and skipOnFail:
1493 Testcaselib.saveOnosDiagnostics( main )
1494 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1495 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001496
1497 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001498 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001499 """
1500 Verify if the specified host is discovered by ONOS on the given locations
1501 Required:
You Wang85747762018-05-11 15:51:50 -07001502 locationDict: a dictionary that maps host names to expected locations.
1503 locations could be a string or a list.
1504 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001505 Returns:
1506 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1507 """
You Wang85747762018-05-11 15:51:50 -07001508 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1509 result = main.TRUE
1510 for hostName, locations in locationDict.items():
1511 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1512 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1513 if not hostIp:
1514 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1515 if not hostIp:
1516 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1517 result = main.FALSE
1518 continue
1519 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1520 main.FALSE,
1521 args=( hostIp, locations ),
1522 attempts=retry + 1,
1523 sleep=10 )
1524 if not locationResult:
1525 result = main.FALSE
1526 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001527 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001528 onpass="Location verification passed",
1529 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001530
1531 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001532 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001533 """
1534 Move specified host from srcSw to dstSw.
1535 If srcSw and dstSw are same, the host will be moved from current port to
1536 next available port.
1537 Required:
1538 hostName: name of the host. e.g., "h1"
1539 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1540 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1541 gw: ip address of the gateway of the new location
1542 Optional:
1543 macAddr: if specified, change MAC address of the host to the specified MAC address.
1544 prefixLen: prefix length
1545 cfg: port configuration as JSON string
1546 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001547 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001548 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001549 if not hasattr( main, 'Mininet1' ):
1550 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1551 return
1552
You Wang6e5b48e2018-07-23 16:17:38 -07001553 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1554 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1555 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001556 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001557 if cfg:
1558 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1559 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001560 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001561 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001562 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001563
1564 main.Mininet1.discoverHosts( [ hostName, ] )
1565
1566 # Update expectedHost when MAC address is changed.
1567 if macAddr is not None:
1568 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1569 if ipAddr is not None:
1570 for hostName, ip in main.expectedHosts[ "onos" ].items():
1571 if ip == ipAddr:
1572 vlan = hostName.split( "/" )[ -1 ]
1573 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001574 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001575 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001576
1577 @staticmethod
1578 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001579 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001580 """
1581 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1582 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1583 to next available port.
1584 Required:
1585 hostName: name of the host. e.g., "h1"
1586 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1587 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1588 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1589 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1590 gw: ip address of the gateway of the new location
1591 Optional:
1592 macAddr: if specified, change MAC address of the host to the specified MAC address.
1593 prefixLen: prefix length
1594 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001595 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001596 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001597 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001598 if not hasattr( main, 'Mininet1' ):
1599 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1600 return
1601
You Wang6e5b48e2018-07-23 16:17:38 -07001602 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1603 srcSw, srcPairSw, dstSw, dstPairSw ) )
1604 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1605 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1606 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001607 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001608 if cfg:
1609 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1610 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001611 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001612 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001613 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001614
1615 main.Mininet1.discoverHosts( [ hostName, ] )
1616
1617 # Update expectedHost when MAC address is changed.
1618 if macAddr is not None:
1619 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1620 if ipAddr is not None:
1621 for hostName, ip in main.expectedHosts[ "onos" ].items():
1622 if ip == ipAddr:
1623 vlan = hostName.split( "/" )[ -1 ]
1624 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001625 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001626
1627 @staticmethod
1628 def mnDockerSetup( main ):
1629 """
1630 Optionally start and setup docker image for mininet
1631 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001632 try:
1633 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001634
Jon Hall9b0de1f2020-08-24 15:38:04 -07001635 main.log.info( "Creating Mininet Docker" )
1636 handle = main.Mininet1.handle
1637 # build docker image
1638 dockerFilePath = "%s/../dependencies/" % main.testDir
1639 dockerName = "trellis_mininet"
1640 # Stop any leftover container
1641 main.Mininet1.dockerStop( dockerName )
1642 # TODO: assert on these docker calls
1643 main.Mininet1.dockerBuild( dockerFilePath, dockerName )
Jon Hallf6aeda22020-07-28 09:12:56 -07001644
Jon Hall9b0de1f2020-08-24 15:38:04 -07001645 confDir = "/tmp/mn_conf/"
1646 # Try to ensure the destination exists
1647 main.log.info( "Create folder for network config files" )
1648 handle.sendline( "rm -rf %s" % confDir )
1649 handle.expect( main.Mininet1.Prompt() )
1650 main.log.debug( handle.before + handle.after )
1651 handle.sendline( "mkdir -p %s" % confDir )
1652 handle.expect( main.Mininet1.Prompt() )
1653 main.log.debug( handle.before + handle.after )
1654 # Make sure permissions are correct
1655 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1656 handle.expect( main.Mininet1.Prompt() )
1657 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1658 handle.expect( main.Mininet1.Prompt() )
1659 main.log.debug( handle.before + handle.after )
1660 # Start docker container
1661 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1662 dockerName,
1663 main.params[ 'MN_DOCKER' ][ 'args' ] )
1664 if runResponse == main.FALSE:
1665 main.log.error( "Docker container already running, aborting test" )
1666 main.cleanup()
1667 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001668
Jon Hall9b0de1f2020-08-24 15:38:04 -07001669 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1670 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001671
Jon Hall9b0de1f2020-08-24 15:38:04 -07001672 # Fow when we create component handles
1673 main.Mininet1.mExecDir = "/tmp"
1674 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1675 main.Mininet1.hostPrompt = "/home/root#"
1676
1677 # For some reason docker isn't doing this
1678 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1679 main.Mininet1.handle.expect( "etc/hosts" )
1680 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1681 except Exception as e:
1682 main.log.exception( "Error seting up mininet" )
1683 man.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001684
1685 @staticmethod
1686 def mnDockerTeardown( main ):
1687 """
1688 Optionally stop and cleanup docker image for mininet
1689 """
1690
1691 if hasattr( main, 'Mininet1' ):
1692 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001693 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001694
1695 # Detach from container
1696 handle = main.Mininet1.handle
1697 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001698 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001699 main.Mininet1.sudoRequired = True
1700 except Exception as e:
1701 main.log.error( e )
1702
1703 @staticmethod
1704 def setOnosConfig( main ):
1705 """
1706 Read and Set onos configurations from the params file
1707 """
1708 main.step( "Set ONOS configurations" )
1709 config = main.params.get( 'ONOS_Configuration' )
1710 if config:
1711 main.log.debug( config )
1712 checkResult = main.TRUE
1713 for component in config:
1714 for setting in config[ component ]:
1715 value = config[ component ][ setting ]
1716 check = main.Cluster.next().setCfg( component, setting, value )
1717 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1718 checkResult = check and checkResult
1719 utilities.assert_equals( expect=main.TRUE,
1720 actual=checkResult,
1721 onpass="Successfully set config",
1722 onfail="Failed to set config" )
1723 else:
1724 main.log.warn( "No configurations were specified to be changed after startup" )
1725
1726 @staticmethod
1727 def setOnosLogLevels( main ):
1728 """
1729 Read and Set onos log levels from the params file
1730 """
1731 main.step( 'Set logging levels' )
1732 logging = True
1733 try:
1734 logs = main.params.get( 'ONOS_Logging', False )
1735 if logs:
1736 for namespace, level in logs.items():
1737 for ctrl in main.Cluster.active():
1738 ctrl.CLI.logSet( level, namespace )
1739 except AttributeError:
1740 logging = False
1741 utilities.assert_equals( expect=True, actual=logging,
1742 onpass="Set log levels",
1743 onfail="Failed to set log levels" )