blob: 68072a7cb226d333626bfee5dd889d53e77d8f68 [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" )
723 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700724 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700725 "Waiting %s seconds for link down to be discovered" % sleep )
726 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700727 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700728 main.FALSE,
729 kwargs={ 'numoswitch': switches,
730 'numolink': links },
731 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700732 sleep=sleep )
733 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700734 utilities.assert_equals( expect=main.TRUE, actual=result,
735 onpass="Link down successful",
736 onfail="Failed to turn off link?" )
737
738 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700739 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800740 """
741 links = list of links (src, dst) to bring down.
742 """
743
744 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700745 if sleep is None:
746 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
747 else:
748 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800749
750 for end1, end2 in links:
751 main.Network.link( END1=end1, END2=end2, OPTION="down")
752 main.Network.link( END1=end2, END2=end1, OPTION="down")
753
Jon Halla604fd42018-05-04 14:27:27 -0700754 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800755 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700756 "Waiting %s seconds for links down to be discovered" % sleep )
757 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800758
759 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
760 main.FALSE,
761 kwargs={ 'numoswitch': switches,
762 'numolink': linksAfter },
763 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700764 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800765
You Wang2854bce2018-03-30 10:15:32 -0700766 utilities.assert_equals( expect=main.TRUE, actual=topology,
767 onpass="Link batch down successful",
768 onfail="Link batch down failed" )
769
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800770 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700771 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800772 """
773 links = list of link (src, dst) to bring up again.
774 """
775
776 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700777 if sleep is None:
778 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
779 else:
780 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800781
782 for end1, end2 in links:
783 main.Network.link( END1=end1, END2=end2, OPTION="up")
784 main.Network.link( END1=end2, END2=end1, OPTION="up")
785
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800786 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700787 "Waiting %s seconds for links up to be discovered" % sleep )
788 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800789
790 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
791 main.FALSE,
792 kwargs={ 'numoswitch': switches,
793 'numolink': linksAfter },
794 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700795 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800796
You Wang2854bce2018-03-30 10:15:32 -0700797 utilities.assert_equals( expect=main.TRUE, actual=topology,
798 onpass="Link batch up successful",
799 onfail="Link batch up failed" )
800
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800801 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700802 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
803 """
804 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
805 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
806 switches, links: number of expected switches and links after link change, ex.: '4', '6'
807 """
808 if sleep is None:
809 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
810 else:
811 sleep = float( sleep )
812 main.step( "Disable a batch of ports" )
813 for dpid, port in ports:
814 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
815 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
816 time.sleep( sleep )
817 if switches and links:
818 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
819 numolink=links )
820 utilities.assert_equals( expect=main.TRUE, actual=result,
821 onpass="Port down successful",
822 onfail="Port down failed" )
823
824 @staticmethod
825 def enablePortBatch( main, ports, switches, links, sleep=None ):
826 """
827 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
828 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
829 switches, links: number of expected switches and links after link change, ex.: '4', '6'
830 """
831 if sleep is None:
832 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
833 else:
834 sleep = float( sleep )
835 main.step( "Enable a batch of ports" )
836 for dpid, port in ports:
837 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
838 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
839 time.sleep( sleep )
840 if switches and links:
841 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
842 numolink=links )
843 utilities.assert_equals( expect=main.TRUE, actual=result,
844 onpass="Port up successful",
845 onfail="Port up failed" )
846
847 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700848 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700849 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700850 """
851 Params:
852 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700853 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700854 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
855 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
856 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
857 Kill a link and verify ONOS can see the proper link change
858 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700859 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700860 if sleep is None:
861 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
862 else:
863 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700864 result = False
865 count = 0
866 while True:
867 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700868 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800869 main.Network.link( END1=end1, END2=end2, OPTION="up" )
870 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700871 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700872 "Waiting %s seconds for link up to be discovered" % sleep )
873 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700874
You Wangc02d8352018-04-17 16:42:10 -0700875 if portUp:
876 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
877 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700878 main.log.info(
879 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700880 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700881
Jon Halla604fd42018-05-04 14:27:27 -0700882 result = ctrl.CLI.checkStatus( numoswitch=switches,
883 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700884 if count > 5 or result:
885 break
886 utilities.assert_equals( expect=main.TRUE, actual=result,
887 onpass="Link up successful",
888 onfail="Failed to bring link up" )
889
890 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700891 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700892 """
893 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
894 Completely kill a switch and verify ONOS can see the proper change
895 """
Jon Halla604fd42018-05-04 14:27:27 -0700896 if sleep is None:
897 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
898 else:
899 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700900 switch = switch if isinstance( switch, list ) else [ switch ]
901 main.step( "Kill " + str( switch ) )
902 for s in switch:
903 main.log.info( "Stopping " + s )
904 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700905 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700906
907 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700908 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700909 sleep ) )
910 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700911 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700912 main.FALSE,
913 kwargs={ 'numoswitch': switches,
914 'numolink': links },
915 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700916 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700917 utilities.assert_equals( expect=main.TRUE, actual=topology,
918 onpass="Kill switch successful",
919 onfail="Failed to kill switch?" )
920
921 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700922 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700923 """
924 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
925 Recover a switch and verify ONOS can see the proper change
926 """
Jon Halla604fd42018-05-04 14:27:27 -0700927 if sleep is None:
928 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
929 else:
930 sleep = float( sleep )
931 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700932 switch = switch if isinstance( switch, list ) else [ switch ]
933 main.step( "Recovering " + str( switch ) )
934 for s in switch:
935 main.log.info( "Starting " + s )
936 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700937 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700938 sleep ) )
939 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700940 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700941 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700942 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700943 sleep ) )
944 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700945
Devin Lim142b5342017-07-20 15:22:39 -0700946 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700947 main.FALSE,
948 kwargs={ 'numoswitch': switches,
949 'numolink': links },
950 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700951 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700952 utilities.assert_equals( expect=main.TRUE, actual=topology,
953 onpass="Switch recovery successful",
954 onfail="Failed to recover switch?" )
955
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700956 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700957 def killRouter( main, router, sleep=None ):
958 """
959 Kill bgpd process on a quagga router
960 router: name of the router to be killed. E.g. "bgp1"
961 """
962 sleep = float( sleep )
963 main.step( "Kill " + str( router ) )
964 if hasattr( main, 'Mininet1' ):
965 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
966 main.Mininet1.handle.expect( "mininet>" )
967 else:
968 # TODO: support killing router in physical network
969 pass
970 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
971 time.sleep( sleep )
972
973 @staticmethod
974 def recoverRouter( main, router, sleep=None ):
975 """
976 Restart bgpd process on a quagga router
977 router: name of the router to be recovered. E.g. "bgp1"
978 """
979 sleep = float( sleep )
980 main.step( "Recovering " + str( router ) )
981 if hasattr( main, 'Mininet1' ):
982 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
983 main.Mininet1.handle.expect( "mininet>" )
984 else:
985 # TODO: support recovering router in physical network
986 pass
987 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
988 time.sleep( sleep )
989
990 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700991 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700992 """
993 Stop Onos-cluster.
994 Stops Mininet
995 Copies ONOS log
996 """
You Wang4cc61912018-08-28 10:10:58 -0700997 from tests.dependencies.utils import Utils
998 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -0700999 for ctrl in main.Cluster.active():
1000 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001001 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001002 if hasattr( main, "scapyHosts" ):
1003 scapyResult = main.TRUE
1004 for host in main.scapyHosts:
1005 scapyResult = host.stopScapy() and scapyResult
1006 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1007 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001008 if hasattr( main, 'Mininet1' ):
1009 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1010 else:
1011 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001012 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1013 main.scapyHosts = []
1014
You Wang5da39c82018-04-26 22:55:08 -07001015 if removeHostComponent:
1016 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1017 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001018 if hasattr( main, 'Mininet1' ):
1019 pass
1020 else:
1021 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001022 main.Network.removeHostComponent( host )
1023
You Wang5df1c6d2018-04-06 18:02:02 -07001024 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001025 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001026 else:
1027 main.Network.disconnectInbandHosts()
1028 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001029
You Wang5df1c6d2018-04-06 18:02:02 -07001030 if copyKarafLog:
1031 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001032
Devin Lim142b5342017-07-20 15:22:39 -07001033 for ctrl in main.Cluster.active():
1034 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001035 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001036
1037 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001038 def verifyNodes( main ):
1039 """
1040 Verifies Each active node in the cluster has an accurate view of other node's and their status
1041
1042 Params:
1043 nodes, integer array with position of the ONOS nodes in the CLIs array
1044 """
1045 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1046 False,
1047 attempts=10,
1048 sleep=10 )
1049 utilities.assert_equals( expect=True, actual=nodeResults,
1050 onpass="Nodes check successful",
1051 onfail="Nodes check NOT successful" )
1052
1053 if not nodeResults:
1054 for ctrl in main.Cluster.runningNodes:
1055 main.log.debug( "{} components not ACTIVE: \n{}".format(
1056 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001057 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001058 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001059 main.cleanAndExit()
1060
1061 @staticmethod
1062 def verifyTopology( main, switches, links, expNodes ):
1063 """
1064 Verifies that the ONOS cluster has an acuurate view of the topology
1065
1066 Params:
1067 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1068 """
1069 main.step( "Check number of topology elements" )
1070 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1071 main.FALSE,
1072 kwargs={ 'numoswitch': switches,
1073 'numolink': links,
1074 'numoctrl': expNodes },
1075 attempts=10,
1076 sleep=12 )
1077 utilities.assert_equals( expect=main.TRUE, actual=topology,
1078 onpass="Number of topology elements are correct",
1079 onfail="Unexpected number of links, switches, and/or controllers" )
1080
1081 @staticmethod
1082 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001083 """
1084 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1085 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1086 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1087 """
Jon Halla604fd42018-05-04 14:27:27 -07001088 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001089 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001090 if sleep is None:
1091 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1092 else:
1093 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001094
Jon Hall1efcb3f2016-08-23 13:42:15 -07001095 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001096 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001097 utilities.assert_equals( expect=main.TRUE, actual=killResult,
1098 onpass="ONOS instance Killed",
1099 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -07001100 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -07001101 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001102 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001103 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001104
Devin Lim142b5342017-07-20 15:22:39 -07001105 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001106 Testcaselib.verifyNodes( main )
1107 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001108
1109 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001110 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001111 """
1112 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1113 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1114 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1115 """
Jon Hall3c910162018-03-07 14:42:16 -08001116 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001117 if sleep is None:
1118 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1119 else:
1120 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001121 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Hall43060f62020-06-23 13:13:33 -07001122 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001123 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001124 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001125 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001126 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1127 onpass="ONOS service is ready",
1128 onfail="ONOS service did not start properly" )
1129 for i in nodes:
1130 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001131 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001132 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001133 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1134 commandlineTimeout=60,
1135 onosStartTimeout=100 )
1136 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001137 utilities.assert_equals( expect=main.TRUE,
1138 actual=cliResult,
1139 onpass="ONOS CLI is ready",
1140 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001141
Jon Halla604fd42018-05-04 14:27:27 -07001142 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001143 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001144 Testcaselib.verifyNodes( main )
1145 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001146
Devin Lim142b5342017-07-20 15:22:39 -07001147 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001148 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001149 attempts=10,
1150 sleep=12 )
1151 if ready:
1152 ready = main.TRUE
1153 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001154 onpass="ONOS summary command succeded",
1155 onfail="ONOS summary command failed" )
1156 if not ready:
1157 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001158 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001159
1160 @staticmethod
1161 def addHostCfg( main ):
1162 """
1163 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001164 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001165 """
1166 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001167 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001168 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001169 hostCfg = json.load( template )
1170 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1171 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001172 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001173 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1174 subjectClass="hosts",
1175 subjectKey=urllib.quote( mac,
1176 safe='' ),
1177 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001178 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1179 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001180 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001181 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1182 subjectClass="hosts",
1183 subjectKey=urllib.quote( mac,
1184 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001185 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001186 main.pingChart.update( { 'vlan1': { "expect": "True",
1187 "hosts": [ "olt1", "vsg1" ] } } )
1188 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1189 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001190 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1191 vlanId=1,
1192 port1=5,
1193 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001194
1195 @staticmethod
1196 def delHostCfg( main ):
1197 """
1198 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001199 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001200 """
1201 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001202 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001203 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001204 hostCfg = json.load( template )
1205 main.step( "Removing host configuration" )
1206 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001207 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001208 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1209 subjectKey=urllib.quote(
1210 mac,
1211 safe='' ),
1212 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001213 main.step( "Removing configuration" )
1214 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001215 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001216 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1217 subjectKey=urllib.quote(
1218 mac,
1219 safe='' ),
1220 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001221 main.step( "Removing vlan configuration" )
1222 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001223 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1224 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001225
1226 @staticmethod
1227 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1228 """
1229 Verifies IP address assignment from the hosts
1230 """
1231 main.step( "Verify IP address assignment from hosts" )
1232 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001233 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001234 # Find out names of disconnected hosts
1235 disconnectedHosts = []
1236 if hasattr( main, "disconnectedIpv4Hosts" ):
1237 for host in main.disconnectedIpv4Hosts:
1238 disconnectedHosts.append( host )
1239 if hasattr( main, "disconnectedIpv6Hosts" ):
1240 for host in main.disconnectedIpv6Hosts:
1241 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001242 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001243 # Exclude disconnected hosts
1244 if hostName in disconnectedHosts:
1245 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1246 continue
You Wang53dba1e2018-02-02 17:45:44 -08001247 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1248 main.FALSE,
1249 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001250 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001251 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001252 attempts=attempts,
1253 sleep=sleep )
1254 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1255 onpass="Verify network host IP succeded",
1256 onfail="Verify network host IP failed" )
1257
1258 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001259 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001260 """
1261 Verifies host IP address assignment from ONOS
1262 """
1263 main.step( "Verify host IP address assignment in ONOS" )
1264 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001265 # Find out IPs of disconnected hosts
1266 disconnectedIps = []
1267 if hasattr( main, "disconnectedIpv4Hosts" ):
1268 for host in main.disconnectedIpv4Hosts:
1269 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1270 if hasattr( main, "disconnectedIpv6Hosts" ):
1271 for host in main.disconnectedIpv6Hosts:
1272 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001273 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001274 # Exclude disconnected hosts
1275 if ip in disconnectedIps:
1276 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1277 continue
You Wang53dba1e2018-02-02 17:45:44 -08001278 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1279 main.FALSE,
1280 kwargs={ 'hostList': [ hostName ],
1281 'prefix': ip },
1282 attempts=attempts,
1283 sleep=sleep )
1284 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1285 onpass="Verify ONOS host IP succeded",
1286 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001287 if not ipResult and skipOnFail:
1288 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001289 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001290 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001291
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001292 @staticmethod
1293 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1294 """
1295 Description:
1296 Updates interface configuration in ONOS, with given IP and vlan parameters
1297 Required:
1298 * connectPoint: connect point to update configuration
1299 Optional:
1300 * ips: list of IP addresses, combined with '/xx' subnet representation,
1301 corresponding to 'ips' field in the configuration
1302 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1303 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1304 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1305 """
1306 cfg = dict()
1307 cfg[ "ports" ] = dict()
1308 cfg[ "ports" ][ connectPoint ] = dict()
1309 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1310 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1311 if untagged > 0:
1312 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1313 else:
1314 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1315 if native > 0:
1316 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1317
1318 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001319
1320 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001321 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001322 """
1323 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001324 scapyNames: list of names that will be used as component names for scapy hosts
1325 mininetNames: used when scapy host names are different from the host names
1326 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1327 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001328 """
1329 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001330 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1331 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001332 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001333 if hasattr( main, 'Mininet1' ):
1334 main.Scapy.createHostComponent( scapyName )
1335 scapyHandle = getattr( main, scapyName )
1336 if mininetNames:
1337 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1338 else:
1339 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001340 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1341 scapyHandle.mExecDir = "/tmp"
1342 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1343 main.log.debug( "start mn host component in docker" )
1344 scapyHandle.startHostCli( mininetName,
1345 execDir="/tmp",
1346 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1347 else:
1348 main.log.debug( "start mn host component" )
1349 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001350 else:
You Wang0fc21702018-11-02 17:49:18 -07001351 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001352 scapyHandle = getattr( main, scapyName )
1353 scapyHandle.connectInband()
1354 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001355 scapyHandle.startScapy()
1356 scapyHandle.updateSelf()
1357 main.log.debug( scapyHandle.name )
1358 main.log.debug( scapyHandle.hostIp )
1359 main.log.debug( scapyHandle.hostMac )
1360
1361 @staticmethod
1362 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1363 """
1364 Verify unicast traffic by pinging from source hosts to the destination IP
1365 and capturing the packets at the destination host using Scapy.
1366 srcHosts: List of host names to send the ping packets
1367 dstIp: destination IP of the ping packets
1368 dstHost: host that runs Scapy to capture the packets
1369 dstIntf: name of the interface on the destination host
1370 expect: use True if the ping is expected to be captured at destination;
1371 Otherwise False
1372 skipOnFail: skip the rest of this test case if result is not expected
1373 maxRetry: number of retries allowed
1374 """
1375 from tests.dependencies.topology import Topology
1376 try:
1377 main.topo
1378 except ( NameError, AttributeError ):
1379 main.topo = Topology()
1380 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1381 result = main.TRUE
1382 for srcHost in srcHosts:
1383 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1384 expect, maxRetry, True )
1385 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001386 result = main.FALSE
1387 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1388 utilities.assert_equals( expect=main.TRUE,
1389 actual=result,
1390 onpass="Verify traffic to {}: Pass".format( dstIp ),
1391 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1392 if skipOnFail and result != main.TRUE:
1393 Testcaselib.saveOnosDiagnostics( main )
1394 Testcaselib.cleanup( main, copyKarafLog=False )
1395 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001396
1397 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001398 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001399 """
1400 Verify multicast traffic using scapy
1401 """
You Wangc564c6f2018-05-01 15:24:57 -07001402 from tests.dependencies.topology import Topology
1403 try:
1404 main.topo
1405 except ( NameError, AttributeError ):
1406 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001407 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001408 routeData = main.multicastConfig[ routeName ]
1409 srcs = main.mcastRoutes[ routeName ][ "src" ]
1410 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1411 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1412 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001413 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001414 for src in srcs:
1415 srcEntry = routeData[ "src" ][ src ]
1416 for dst in dsts:
1417 dstEntry = routeData[ "dst" ][ dst ]
1418 sender = getattr( main, srcEntry[ "host" ] )
1419 receiver = getattr( main, dstEntry[ "host" ] )
1420 main.Network.addRoute( str( srcEntry[ "host" ] ),
1421 str( routeData[ "group" ] ),
1422 str( srcEntry[ "interface" ] ),
1423 True if routeData[ "ipVersion" ] == 6 else False )
1424 # Build the packet
1425 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1426 if routeData[ "ipVersion" ] == 4:
1427 sender.buildIP( dst=str( routeData[ "group" ] ) )
1428 elif routeData[ "ipVersion" ] == 6:
1429 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1430 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1431 sIface = srcEntry[ "interface" ]
1432 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1433 pktFilter = srcEntry[ "filter" ]
1434 pkt = srcEntry[ "packet" ]
1435 # Send packet and check received packet
1436 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001437 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001438 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001439 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1440 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001441 if not trafficResult:
1442 result = main.FALSE
1443 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1444 dstEntry[ "host" ] ) )
1445 utilities.assert_equals( expect=main.TRUE,
1446 actual=result,
1447 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1448 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001449 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001450 Testcaselib.saveOnosDiagnostics( main )
1451 Testcaselib.cleanup( main, copyKarafLog=False )
1452 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001453
1454 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001455 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001456 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1457 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001458 """
1459 Verify reachability from each host in srcList to each host in dstList
1460 """
1461 from tests.dependencies.topology import Topology
1462 try:
1463 main.topo
1464 except ( NameError, AttributeError ):
1465 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001466 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001467 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001468 utilities.assert_equals( expect=main.TRUE,
1469 actual=pingResult,
1470 onpass="{}: Pass".format( stepMsg ),
1471 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001472 if not pingResult and skipOnFail:
1473 Testcaselib.saveOnosDiagnostics( main )
1474 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1475 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001476
1477 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001478 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001479 """
1480 Verify if the specified host is discovered by ONOS on the given locations
1481 Required:
You Wang85747762018-05-11 15:51:50 -07001482 locationDict: a dictionary that maps host names to expected locations.
1483 locations could be a string or a list.
1484 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001485 Returns:
1486 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1487 """
You Wang85747762018-05-11 15:51:50 -07001488 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1489 result = main.TRUE
1490 for hostName, locations in locationDict.items():
1491 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1492 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1493 if not hostIp:
1494 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1495 if not hostIp:
1496 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1497 result = main.FALSE
1498 continue
1499 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1500 main.FALSE,
1501 args=( hostIp, locations ),
1502 attempts=retry + 1,
1503 sleep=10 )
1504 if not locationResult:
1505 result = main.FALSE
1506 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001507 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001508 onpass="Location verification passed",
1509 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001510
1511 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001512 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001513 """
1514 Move specified host from srcSw to dstSw.
1515 If srcSw and dstSw are same, the host will be moved from current port to
1516 next available port.
1517 Required:
1518 hostName: name of the host. e.g., "h1"
1519 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1520 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1521 gw: ip address of the gateway of the new location
1522 Optional:
1523 macAddr: if specified, change MAC address of the host to the specified MAC address.
1524 prefixLen: prefix length
1525 cfg: port configuration as JSON string
1526 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001527 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001528 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001529 if not hasattr( main, 'Mininet1' ):
1530 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1531 return
1532
You Wang6e5b48e2018-07-23 16:17:38 -07001533 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1534 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1535 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001536 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001537 if cfg:
1538 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1539 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001540 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001541 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001542 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001543
1544 main.Mininet1.discoverHosts( [ hostName, ] )
1545
1546 # Update expectedHost when MAC address is changed.
1547 if macAddr is not None:
1548 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1549 if ipAddr is not None:
1550 for hostName, ip in main.expectedHosts[ "onos" ].items():
1551 if ip == ipAddr:
1552 vlan = hostName.split( "/" )[ -1 ]
1553 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001554 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001555 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001556
1557 @staticmethod
1558 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001559 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001560 """
1561 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1562 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1563 to next available port.
1564 Required:
1565 hostName: name of the host. e.g., "h1"
1566 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1567 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1568 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1569 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1570 gw: ip address of the gateway of the new location
1571 Optional:
1572 macAddr: if specified, change MAC address of the host to the specified MAC address.
1573 prefixLen: prefix length
1574 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001575 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001576 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001577 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001578 if not hasattr( main, 'Mininet1' ):
1579 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1580 return
1581
You Wang6e5b48e2018-07-23 16:17:38 -07001582 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1583 srcSw, srcPairSw, dstSw, dstPairSw ) )
1584 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1585 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1586 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001587 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001588 if cfg:
1589 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1590 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001591 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001592 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001593 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001594
1595 main.Mininet1.discoverHosts( [ hostName, ] )
1596
1597 # Update expectedHost when MAC address is changed.
1598 if macAddr is not None:
1599 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1600 if ipAddr is not None:
1601 for hostName, ip in main.expectedHosts[ "onos" ].items():
1602 if ip == ipAddr:
1603 vlan = hostName.split( "/" )[ -1 ]
1604 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001605 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001606
1607 @staticmethod
1608 def mnDockerSetup( main ):
1609 """
1610 Optionally start and setup docker image for mininet
1611 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001612 try:
1613 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001614
Jon Hall9b0de1f2020-08-24 15:38:04 -07001615 main.log.info( "Creating Mininet Docker" )
1616 handle = main.Mininet1.handle
1617 # build docker image
1618 dockerFilePath = "%s/../dependencies/" % main.testDir
1619 dockerName = "trellis_mininet"
1620 # Stop any leftover container
1621 main.Mininet1.dockerStop( dockerName )
1622 # TODO: assert on these docker calls
1623 main.Mininet1.dockerBuild( dockerFilePath, dockerName )
Jon Hallf6aeda22020-07-28 09:12:56 -07001624
Jon Hall9b0de1f2020-08-24 15:38:04 -07001625 confDir = "/tmp/mn_conf/"
1626 # Try to ensure the destination exists
1627 main.log.info( "Create folder for network config files" )
1628 handle.sendline( "rm -rf %s" % confDir )
1629 handle.expect( main.Mininet1.Prompt() )
1630 main.log.debug( handle.before + handle.after )
1631 handle.sendline( "mkdir -p %s" % confDir )
1632 handle.expect( main.Mininet1.Prompt() )
1633 main.log.debug( handle.before + handle.after )
1634 # Make sure permissions are correct
1635 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1636 handle.expect( main.Mininet1.Prompt() )
1637 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1638 handle.expect( main.Mininet1.Prompt() )
1639 main.log.debug( handle.before + handle.after )
1640 # Start docker container
1641 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1642 dockerName,
1643 main.params[ 'MN_DOCKER' ][ 'args' ] )
1644 if runResponse == main.FALSE:
1645 main.log.error( "Docker container already running, aborting test" )
1646 main.cleanup()
1647 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001648
Jon Hall9b0de1f2020-08-24 15:38:04 -07001649 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1650 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001651
Jon Hall9b0de1f2020-08-24 15:38:04 -07001652 # Fow when we create component handles
1653 main.Mininet1.mExecDir = "/tmp"
1654 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1655 main.Mininet1.hostPrompt = "/home/root#"
1656
1657 # For some reason docker isn't doing this
1658 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1659 main.Mininet1.handle.expect( "etc/hosts" )
1660 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1661 except Exception as e:
1662 main.log.exception( "Error seting up mininet" )
1663 man.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001664
1665 @staticmethod
1666 def mnDockerTeardown( main ):
1667 """
1668 Optionally stop and cleanup docker image for mininet
1669 """
1670
1671 if hasattr( main, 'Mininet1' ):
1672 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001673 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001674
1675 # Detach from container
1676 handle = main.Mininet1.handle
1677 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001678 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001679 main.Mininet1.sudoRequired = True
1680 except Exception as e:
1681 main.log.error( e )
1682
1683 @staticmethod
1684 def setOnosConfig( main ):
1685 """
1686 Read and Set onos configurations from the params file
1687 """
1688 main.step( "Set ONOS configurations" )
1689 config = main.params.get( 'ONOS_Configuration' )
1690 if config:
1691 main.log.debug( config )
1692 checkResult = main.TRUE
1693 for component in config:
1694 for setting in config[ component ]:
1695 value = config[ component ][ setting ]
1696 check = main.Cluster.next().setCfg( component, setting, value )
1697 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1698 checkResult = check and checkResult
1699 utilities.assert_equals( expect=main.TRUE,
1700 actual=checkResult,
1701 onpass="Successfully set config",
1702 onfail="Failed to set config" )
1703 else:
1704 main.log.warn( "No configurations were specified to be changed after startup" )
1705
1706 @staticmethod
1707 def setOnosLogLevels( main ):
1708 """
1709 Read and Set onos log levels from the params file
1710 """
1711 main.step( 'Set logging levels' )
1712 logging = True
1713 try:
1714 logs = main.params.get( 'ONOS_Logging', False )
1715 if logs:
1716 for namespace, level in logs.items():
1717 for ctrl in main.Cluster.active():
1718 ctrl.CLI.logSet( level, namespace )
1719 except AttributeError:
1720 logging = False
1721 utilities.assert_equals( expect=True, actual=logging,
1722 onpass="Set log levels",
1723 onfail="Failed to set log levels" )