blob: fe6a7fcec2cc0e854173ed12487918b2881df03c [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 Hall1efcb3f2016-08-23 13:42:15 -070026from core import utilities
27
28
29class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070030
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070031 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070032
Jon Hall1efcb3f2016-08-23 13:42:15 -070033 @staticmethod
34 def initTest( main ):
35 """
36 - Construct tests variables
37 - GIT ( optional )
38 - Checkout ONOS master branch
39 - Pull latest ONOS code
40 - Building ONOS ( optional )
41 - Install ONOS package
42 - Build ONOS package
43 """
Devin Lim58046fa2017-07-05 16:55:00 -070044 try:
45 from tests.dependencies.ONOSSetup import ONOSSetup
46 main.testSetUp = ONOSSetup()
47 except ImportError:
48 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070049 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080050 from tests.dependencies.Network import Network
51 main.Network = Network()
Jon Hall76408472020-06-23 13:13:33 -070052 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080053 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070054 stepResult = main.FALSE
55 try:
Devin Lim58046fa2017-07-05 16:55:00 -070056 # Test variables
57 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
58 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070059 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080060 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
61 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
62 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080063 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
64 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
65 else:
66 main.useBmv2 = False
Jon Hall76408472020-06-23 13:13:33 -070067 if main.useBmv2:
68 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
69 else:
70 main.switchType = "ovs"
71
Devin Lim57221b02018-02-14 15:45:36 -080072 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallc7d3bc12020-05-27 09:29:30 -070073 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080074 main.forJson = "json/"
75 main.forChart = "chart/"
76 main.forConfig = "conf/"
77 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080078 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080079 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070080 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070081 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080082 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
83 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080084 main.bmv2 = "bmv2.py"
Jon Halla2e24d32020-06-05 12:04:06 -070085 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070086 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070087 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070088
Devin Lim0c972b72018-02-08 14:53:59 -080089 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070090 except Exception as e:
91 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070092
Devin Lim58046fa2017-07-05 16:55:00 -070093 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070094
Jon Hall1efcb3f2016-08-23 13:42:15 -070095 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080096 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
97 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070098 """
99 - Set up cell
100 - Create cell file
101 - Set cell file
102 - Verify cell file
103 - Kill ONOS process
104 - Uninstall ONOS cluster
105 - Verify ONOS start up
106 - Install ONOS cluster
107 - Connect to cli
108 """
109 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall76408472020-06-23 13:13:33 -0700110 try:
111 if main.params.get( 'EXTERNAL_APPS' ):
112 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
113 main.log.info( "Downloading %s app from %s" )
114 main.ONOSbench.onosFetchApp( url )
115 if not main.apps:
116 main.log.error( "App list is empty" )
117 except Exception as e:
118 main.log.debug( e )
119 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800120 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
121 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700122 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800123 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800124 skipPack=skipPackage,
125 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800126 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700127 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
128 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800129 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700130 attempts=10 )
131 if ready:
132 ready = main.TRUE
133 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700134 onpass="ONOS summary command succeded",
135 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700136 if not ready:
137 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700138 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700139
Jon Hall76408472020-06-23 13:13:33 -0700140 # FIXME: move to somewhere else?
141 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
142 # TODO: Support other pipeconfs/making this configurable
143 if switchPrefix == "tofino":
144 # It seems to take some time for the pipeconfs to be loaded
145 ctrl = main.Cluster.next()
146 for i in range( 120 ):
147 try:
148 main.log.debug( "Checking to see if pipeconfs are loaded" )
149 output = ctrl.CLI.sendline( "pipeconfs" )
150 if "tofino" in output:
151 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
152 break
153 time.sleep( 1 )
154 except Exception as e:
155 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700156
Jon Hall76408472020-06-23 13:13:33 -0700157 Testcaselib.setOnosLogLevels( main )
158 Testcaselib.setOnosConfig( main )
Jon Halla2e24d32020-06-05 12:04:06 -0700159
Jon Hall1efcb3f2016-08-23 13:42:15 -0700160 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800161 def loadCount( main ):
Jon Hall76408472020-06-23 13:13:33 -0700162 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
163 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800164
165 @staticmethod
Jon Hall76408472020-06-23 13:13:33 -0700166 def loadJson( main, suffix='' ):
167 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
168 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800169 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
170
171 @staticmethod
172 def loadChart( main ):
173 try:
174 with open( "%s%s.chart" % ( main.configPath + main.forChart,
175 main.cfgName ) ) as chart:
Jon Hall76408472020-06-23 13:13:33 -0700176 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800177 except IOError:
178 main.log.warn( "No chart file found." )
179
180 @staticmethod
181 def loadHost( main ):
182 with open( "%s%s.host" % ( main.configPath + main.forHost,
183 main.cfgName ) ) as host:
184 main.expectedHosts = json.load( host )
185
186 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800187 def loadSwitchFailureChart( main ):
188 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
189 main.cfgName ) ) as sfc:
190 main.switchFailureChart = json.load( sfc )
191
192 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800193 def loadLinkFailureChart( main ):
194 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700195 main.cfgName ) ) as lfc:
196 main.linkFailureChart = json.load( lfc )
197
198 @staticmethod
199 def loadMulticastConfig( main ):
200 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
201 main.cfgName ) ) as cfg:
202 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800203
204 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700205 def startMininet( main, topology, args="" ):
Jon Hall76408472020-06-23 13:13:33 -0700206 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800207 copyResult = main.ONOSbench.scp( main.Mininet1,
208 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700209 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800210 direction="to" )
211 if main.topologyLib:
212 for lib in main.topologyLib.split(","):
213 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
214 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700215 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800216 direction="to" )
217 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700218 import re
219 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
220 index = 0
Jon Hall76408472020-06-23 13:13:33 -0700221 destDir = "~/"
222 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
223 destDir = "/tmp/mn_conf/"
224 # Try to ensure the destination exists
225 main.log.info( "Create folder for network config files" )
226 handle = main.Mininet1.handle
227 handle.sendline( "mkdir -p %s" % destDir )
228 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
229 main.log.debug( handle.before + handle.after )
230 # Make sure permissions are correct
231 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, destDir ) )
232 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
233 main.log.debug( handle.before + handle.after )
234 handle.sendline( "sudo chmod -R a+rwx %s" % ( destDir ) )
235 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
236 main.log.debug( handle.before + handle.after )
You Wangd87b2312018-01-30 12:47:17 -0800237 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700238 # Update zebra configurations with correct ONOS instance IP
239 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
240 ip = controllerIPs[ index ]
241 index = ( index + 1 ) % len( controllerIPs )
242 with open( main.configPath + main.forConfig + conf ) as f:
243 s = f.read()
244 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
245 with open( main.configPath + main.forConfig + conf, "w" ) as f:
246 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800247 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800248 main.configPath + main.forConfig + conf,
Jon Hall76408472020-06-23 13:13:33 -0700249 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800250 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800251 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallc7d3bc12020-05-27 09:29:30 -0700252 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800253 main.Mininet1.home + "custom",
254 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800255 stepResult = copyResult
256 utilities.assert_equals( expect=main.TRUE,
257 actual=stepResult,
258 onpass="Successfully copied topo files",
259 onfail="Failed to copy topo files" )
Jon Halla2e24d32020-06-05 12:04:06 -0700260 if main.stratumRoot:
261 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
262 main.Mininet1.handle.expect( main.Mininet1.prompt )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700263 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700264 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700265 main.topology = topology
266 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700267 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700268 stepResult = topoResult
269 utilities.assert_equals( expect=main.TRUE,
270 actual=stepResult,
271 onpass="Successfully loaded topology",
272 onfail="Failed to load topology" )
273 # Exit if topology did not load properly
274 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700275 main.cleanAndExit()
Jon Hall76408472020-06-23 13:13:33 -0700276 if main.useBmv2:
277 # Upload the net-cfg file created for each switch
278 filename = "onos-netcfg.json"
279 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
280 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
281 path = "/tmp/mn-stratum/%s/" % switch
282 dstPath = "/tmp/"
283 dstFileName = "%s-onos-netcfg.json" % switch
284 main.ONOSbench1.scp( main.Mininet1,
285 "%s%s" % ( path, filename ),
286 "%s%s" % ( dstPath, dstFileName ),
287 "from" )
288 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
289 # Configure managementAddress
290 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
291 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
292 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
293 # Configure device id
294 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
295 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
296 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
297 # Configure device name
298 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s\",' %s%s" % ( switch, dstPath, dstFileName ) )
299 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
300 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
301 main.ONOSbench1.onosNetCfg( main.ONOSserver1.ip_address, dstPath, dstFileName )
302 # Make sure hosts make some noise
303 Testcaselib.discoverHosts( main )
304
305 @staticmethod
306 def discoverHosts( main ):
307 # TODO add option to only select specific hosts
308 if hasattr( main, "Mininet1" ):
309 network = main.Mininet1
310 elif hasattr( main, "NetworkBench" ):
311 network = main.NetworkBench
312 else:
313 main.log.warn( "Could not find component for test network, skipping host discovery" )
314 return
315 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700316
317 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700318 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800319 main.step( "Connecting to physical netowrk" )
Jon Hall76408472020-06-23 13:13:33 -0700320 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800321 topoResult = main.NetworkBench.connectToNet()
322 stepResult = topoResult
323 utilities.assert_equals( expect=main.TRUE,
324 actual=stepResult,
Jon Hall76408472020-06-23 13:13:33 -0700325 onpass="Successfully connected to topology",
326 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800327 # Exit if topology did not load properly
328 if not topoResult:
329 main.cleanAndExit()
330
Jon Hall76408472020-06-23 13:13:33 -0700331 # Perform any optional setup
332 for switch in main.NetworkBench.switches:
333 if hasattr( switch, "setup" ):
334 switch.setup() # We might not need this
335
You Wang84f981d2018-01-12 16:11:50 -0800336 main.step( "Assign switches to controllers." )
Jon Hall76408472020-06-23 13:13:33 -0700337 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700338 switches = main.NetworkBench.getSwitches()
339 pool = []
340 for name in switches.keys():
Jon Hall76408472020-06-23 13:13:33 -0700341 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
342 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700343 thread = main.Thread( target=main.NetworkBench.assignSwController,
344 name="assignSwitchToController",
345 args=[ name, main.Cluster.getIps(), '6653' ] )
346 pool.append( thread )
347 thread.start()
348 for thread in pool:
349 thread.join( 300 )
350 if not thread.result:
351 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800352 utilities.assert_equals( expect=main.TRUE,
353 actual=stepResult,
354 onpass="Successfully assign switches to controllers",
355 onfail="Failed to assign switches to controllers" )
356
You Wang4cc61912018-08-28 10:10:58 -0700357 # Check devices
358 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700359 # Connecting to hosts that only have data plane connectivity
360 main.step( "Connecting inband hosts" )
361 stepResult = main.Network.connectInbandHosts()
362 utilities.assert_equals( expect=main.TRUE,
363 actual=stepResult,
364 onpass="Successfully connected inband hosts",
365 onfail="Failed to connect inband hosts" )
Jon Hall76408472020-06-23 13:13:33 -0700366 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700367
You Wang84f981d2018-01-12 16:11:50 -0800368 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700369 def saveOnosDiagnostics( main ):
370 """
371 Get onos-diags.tar.gz and save it to the log directory.
372 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
373 """
374 main.log.info( "Collecting onos-diags..." )
375 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
376 main.logdir,
377 "-CASE%d" % main.CurrentTestCaseNumber )
378
379 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700380 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700381 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700382
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700383 main.failures = int( main.params[ 'failures' ] )
384 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700385
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700386 if main.cfgName == '2x2':
387 spine = {}
388 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
389 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
390 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700391
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700392 spine = {}
393 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
394 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
395 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700396
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700397 elif main.cfgName == '4x4':
398 spine = {}
399 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
400 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
401 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700402
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700403 spine = {}
404 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
405 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
406 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700407
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700408 spine = {}
409 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
410 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
411 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700412
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700413 spine = {}
414 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
415 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
416 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700417
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700418 else:
Piera2a7e1b2016-10-04 11:51:43 -0700419 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700420 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800421
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800422 @staticmethod
423 def addStaticOnosRoute( main, subnet, intf):
424 """
425 Adds an ONOS static route with the use route-add command.
426 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800427 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
428
Piera2a7e1b2016-10-04 11:51:43 -0700429 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700430 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700431 """
432 Check number of groups for each subnet on device deviceId and matches
433 it with an expected value. subnetDict is a dictionarty containing values
434 of the type "10.0.1.0/24" : 5.
435 """
You Wangc02f3be2018-05-18 12:14:23 -0700436 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
437 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
438 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700439
You Wangc02f3be2018-05-18 12:14:23 -0700440 result = main.TRUE
441 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700442 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700443 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700444 # this will match the group id that this flow entry points to, for example :
445 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700446 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700447 count = 0
448 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700449 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700450 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700451 if count - 1 != numberInSelect:
452 result = main.FALSE
453 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 ) )
454 utilities.assert_equals( expect=main.TRUE, actual=result,
455 onpass="All bucket numbers are as expected",
456 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700457
458 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900459 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700460 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800461 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900462 if tag == "":
463 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700464 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700465 main.FALSE,
466 kwargs={ 'min': minFlowCount },
467 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800468 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800469 if count == main.FALSE:
470 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700471 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700472 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800473 actual=( count > minFlowCount ),
Jon Hall76408472020-06-23 13:13:33 -0700474 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
475 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700476
477 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700478 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700479 main.FALSE,
480 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800481 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800482 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700483 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700484 expect=main.TRUE,
485 actual=flowCheck,
486 onpass="Flow status is correct!",
487 onfail="Flow status is wrong!" )
488 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700489 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700490 "flows",
491 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900492 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700493 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700494 "groups",
495 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900496 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700497
498 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700499 def checkDevices( main, switches, tag="", sleep=10 ):
500 main.step(
501 "Check whether the switches count is equal to %s" % switches )
502 if tag == "":
503 tag = 'CASE%d' % main.CurrentTestCaseNumber
504 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
505 main.FALSE,
506 kwargs={ 'numoswitch': switches},
507 attempts=10,
508 sleep=sleep )
509 utilities.assert_equals( expect=main.TRUE, actual=result,
510 onpass="Device up successful",
511 onfail="Failed to boot up devices?" )
512
513 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800514 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
515 main.step(
Jon Hall76408472020-06-23 13:13:33 -0700516 "Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800517 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
518 main.FALSE,
519 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800520 attempts=5,
521 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800522 if count == main.FALSE:
523 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800524 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800525 expect=True,
526 actual=( count > minFlowCount ),
527 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800528 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800529
530 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700531 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800532 main.step(
Jon Hall76408472020-06-23 13:13:33 -0700533 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800534 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
535 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700536 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800537 attempts=5,
538 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800539 if count == main.FALSE:
540 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800541 utilities.assertEquals(
542 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800543 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700544 onpass="Flow count looks correct: " + str( count ) ,
545 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800546
547 @staticmethod
548 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
549 main.step(
Jon Hall76408472020-06-23 13:13:33 -0700550 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800551 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
552 main.FALSE,
553 args=( dpid, groupCount, False, 1),
554 attempts=5,
555 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800556 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800557 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800558 utilities.assertEquals(
559 expect=True,
560 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700561 onpass="Group count looks correct: " + str( count ) ,
562 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800563
564 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700565 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800566
567 for dpid, values in main.count.items():
568 flowCount = values["flows"]
569 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700570 main.log.report( "Check flow count for dpid " + str( dpid ) +
571 ", should be " + str( flowCount ) )
572 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800573
Jon Hall9677ed32018-04-24 11:16:23 -0700574 main.log.report( "Check group count for dpid " + str( dpid ) +
575 ", should be " + str( groupCount ) )
576 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800577
578 return
579
580 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700581 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
582 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800583 '''
You Wangba231e72018-03-01 13:18:21 -0800584 Verify connectivity between hosts according to the ping chart
585 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800586 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800587 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800588 '''
You Wangba231e72018-03-01 13:18:21 -0800589 main.log.report( "Check host connectivity" )
590 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800591 if tag == "":
592 tag = 'CASE%d' % main.CurrentTestCaseNumber
593 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800594 main.log.debug( "Entry in ping chart: %s" % entry )
595 expect = entry[ 'expect' ]
596 if expect == "Unidirectional":
597 # Verify ping from each src host to each dst host
598 src = entry[ 'src' ]
599 dst = entry[ 'dst' ]
600 expect = main.TRUE
601 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
602 if basedOnIp:
603 if ("v4" in src[0]):
604 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
605 utilities.assert_equals( expect=expect, actual=pa,
606 onpass="IPv4 connectivity successfully tested",
607 onfail="IPv4 connectivity failed" )
608 if ("v6" in src[0]):
609 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
610 utilities.assert_equals( expect=expect, actual=pa,
611 onpass="IPv6 connectivity successfully tested",
612 onfail="IPv6 connectivity failed" )
Jon Hall76408472020-06-23 13:13:33 -0700613 elif main.physicalNet:
614 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
615 utilities.assert_equals( expect=expect, actual=pa,
616 onpass="IP connectivity successfully tested",
617 onfail="IP connectivity failed" )
618
You Wangba231e72018-03-01 13:18:21 -0800619 else:
620 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
621 utilities.assert_equals( expect=expect, actual=pa,
622 onpass="IP connectivity successfully tested",
623 onfail="IP connectivity failed" )
624 else:
625 # Verify ping between each host pair
626 hosts = entry[ 'hosts' ]
627 try:
628 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
629 except:
630 expect = main.FALSE
631 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
632 if basedOnIp:
633 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800634 pa = utilities.retry( main.Network.pingallHosts,
635 main.FALSE if expect else main.TRUE,
Jon Hall76408472020-06-23 13:13:33 -0700636 args=(hosts, ),
637 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800638 attempts=retryAttempts,
639 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800640 utilities.assert_equals( expect=expect, actual=pa,
641 onpass="IPv4 connectivity successfully tested",
642 onfail="IPv4 connectivity failed" )
643 if ("v6" in hosts[0]):
644 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
645 utilities.assert_equals( expect=expect, actual=pa,
646 onpass="IPv6 connectivity successfully tested",
647 onfail="IPv6 connectivity failed" )
Jon Hall76408472020-06-23 13:13:33 -0700648 elif main.physicalNet:
649 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
650 utilities.assert_equals( expect=expect, actual=pa,
651 onpass="IP connectivity successfully tested",
652 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800653 else:
You Wangf19d9f42018-02-23 16:34:19 -0800654 pa = main.Network.pingallHosts( hosts )
655 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800656 onpass="IP connectivity successfully tested",
657 onfail="IP connectivity failed" )
Jon Hall76408472020-06-23 13:13:33 -0700658 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700659 Testcaselib.saveOnosDiagnostics( main )
Jon Hall76408472020-06-23 13:13:33 -0700660 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700661 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700662 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800663
664 if dumpflows:
665 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
666 "flows",
667 main.logdir,
668 tag + "_FlowsOn" )
669 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
670 "groups",
671 main.logdir,
672 tag + "_GroupsOn" )
673
674 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700675 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700676 """
677 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
678 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
679 Kill a link and verify ONOS can see the proper link change
680 """
Jon Halla604fd42018-05-04 14:27:27 -0700681 if sleep is None:
682 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
683 else:
684 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700685 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700686 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
687 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
688 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700689 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700690 "Waiting %s seconds for link down to be discovered" % sleep )
691 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700692 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700693 main.FALSE,
694 kwargs={ 'numoswitch': switches,
695 'numolink': links },
696 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700697 sleep=sleep )
698 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700699 utilities.assert_equals( expect=main.TRUE, actual=result,
700 onpass="Link down successful",
701 onfail="Failed to turn off link?" )
702
703 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700704 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800705 """
706 links = list of links (src, dst) to bring down.
707 """
708
709 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700710 if sleep is None:
711 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
712 else:
713 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800714
715 for end1, end2 in links:
716 main.Network.link( END1=end1, END2=end2, OPTION="down")
717 main.Network.link( END1=end2, END2=end1, OPTION="down")
718
Jon Halla604fd42018-05-04 14:27:27 -0700719 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800720 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700721 "Waiting %s seconds for links down to be discovered" % sleep )
722 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800723
724 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
725 main.FALSE,
726 kwargs={ 'numoswitch': switches,
727 'numolink': linksAfter },
728 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700729 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800730
You Wang2854bce2018-03-30 10:15:32 -0700731 utilities.assert_equals( expect=main.TRUE, actual=topology,
732 onpass="Link batch down successful",
733 onfail="Link batch down failed" )
734
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800735 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700736 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800737 """
738 links = list of link (src, dst) to bring up again.
739 """
740
741 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700742 if sleep is None:
743 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
744 else:
745 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800746
747 for end1, end2 in links:
748 main.Network.link( END1=end1, END2=end2, OPTION="up")
749 main.Network.link( END1=end2, END2=end1, OPTION="up")
750
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800751 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700752 "Waiting %s seconds for links up to be discovered" % sleep )
753 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800754
755 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
756 main.FALSE,
757 kwargs={ 'numoswitch': switches,
758 'numolink': linksAfter },
759 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700760 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800761
You Wang2854bce2018-03-30 10:15:32 -0700762 utilities.assert_equals( expect=main.TRUE, actual=topology,
763 onpass="Link batch up successful",
764 onfail="Link batch up failed" )
765
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800766 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700767 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
768 """
769 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
770 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
771 switches, links: number of expected switches and links after link change, ex.: '4', '6'
772 """
773 if sleep is None:
774 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
775 else:
776 sleep = float( sleep )
777 main.step( "Disable a batch of ports" )
778 for dpid, port in ports:
779 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
780 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
781 time.sleep( sleep )
782 if switches and links:
783 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
784 numolink=links )
785 utilities.assert_equals( expect=main.TRUE, actual=result,
786 onpass="Port down successful",
787 onfail="Port down failed" )
788
789 @staticmethod
790 def enablePortBatch( main, ports, switches, links, sleep=None ):
791 """
792 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
793 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
794 switches, links: number of expected switches and links after link change, ex.: '4', '6'
795 """
796 if sleep is None:
797 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
798 else:
799 sleep = float( sleep )
800 main.step( "Enable a batch of ports" )
801 for dpid, port in ports:
802 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
803 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
804 time.sleep( sleep )
805 if switches and links:
806 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
807 numolink=links )
808 utilities.assert_equals( expect=main.TRUE, actual=result,
809 onpass="Port up successful",
810 onfail="Port up failed" )
811
812 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700813 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700814 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700815 """
816 Params:
817 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700818 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700819 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
820 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
821 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
822 Kill a link and verify ONOS can see the proper link change
823 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700824 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700825 if sleep is None:
826 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
827 else:
828 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700829 result = False
830 count = 0
831 while True:
832 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700833 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800834 main.Network.link( END1=end1, END2=end2, OPTION="up" )
835 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700836 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700837 "Waiting %s seconds for link up to be discovered" % sleep )
838 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700839
You Wangc02d8352018-04-17 16:42:10 -0700840 if portUp:
841 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
842 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall76408472020-06-23 13:13:33 -0700843 main.log.info(
844 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700845 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700846
Jon Halla604fd42018-05-04 14:27:27 -0700847 result = ctrl.CLI.checkStatus( numoswitch=switches,
848 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700849 if count > 5 or result:
850 break
851 utilities.assert_equals( expect=main.TRUE, actual=result,
852 onpass="Link up successful",
853 onfail="Failed to bring link up" )
854
855 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700856 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700857 """
858 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
859 Completely kill a switch and verify ONOS can see the proper change
860 """
Jon Halla604fd42018-05-04 14:27:27 -0700861 if sleep is None:
862 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
863 else:
864 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700865 switch = switch if isinstance( switch, list ) else [ switch ]
866 main.step( "Kill " + str( switch ) )
867 for s in switch:
868 main.log.info( "Stopping " + s )
869 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700870 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700871
872 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700873 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700874 sleep ) )
875 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700876 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700877 main.FALSE,
878 kwargs={ 'numoswitch': switches,
879 'numolink': links },
880 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700881 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700882 utilities.assert_equals( expect=main.TRUE, actual=topology,
883 onpass="Kill switch successful",
884 onfail="Failed to kill switch?" )
885
886 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700887 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700888 """
889 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
890 Recover a switch and verify ONOS can see the proper change
891 """
Jon Halla604fd42018-05-04 14:27:27 -0700892 if sleep is None:
893 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
894 else:
895 sleep = float( sleep )
896 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700897 switch = switch if isinstance( switch, list ) else [ switch ]
898 main.step( "Recovering " + str( switch ) )
899 for s in switch:
900 main.log.info( "Starting " + s )
901 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700902 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700903 sleep ) )
904 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700905 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700906 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700907 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700908 sleep ) )
909 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700910
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="Switch recovery successful",
919 onfail="Failed to recover switch?" )
920
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700921 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700922 def killRouter( main, router, sleep=None ):
923 """
924 Kill bgpd process on a quagga router
925 router: name of the router to be killed. E.g. "bgp1"
926 """
927 sleep = float( sleep )
928 main.step( "Kill " + str( router ) )
929 if hasattr( main, 'Mininet1' ):
930 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
931 main.Mininet1.handle.expect( "mininet>" )
932 else:
933 # TODO: support killing router in physical network
934 pass
935 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
936 time.sleep( sleep )
937
938 @staticmethod
939 def recoverRouter( main, router, sleep=None ):
940 """
941 Restart bgpd process on a quagga router
942 router: name of the router to be recovered. E.g. "bgp1"
943 """
944 sleep = float( sleep )
945 main.step( "Recovering " + str( router ) )
946 if hasattr( main, 'Mininet1' ):
947 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
948 main.Mininet1.handle.expect( "mininet>" )
949 else:
950 # TODO: support recovering router in physical network
951 pass
952 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
953 time.sleep( sleep )
954
955 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700956 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700957 """
958 Stop Onos-cluster.
959 Stops Mininet
960 Copies ONOS log
961 """
You Wang4cc61912018-08-28 10:10:58 -0700962 from tests.dependencies.utils import Utils
963 main.utils = Utils()
Jon Halla2e24d32020-06-05 12:04:06 -0700964 for ctrl in main.Cluster.active():
965 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -0700966 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700967 if hasattr( main, "scapyHosts" ):
968 scapyResult = main.TRUE
969 for host in main.scapyHosts:
970 scapyResult = host.stopScapy() and scapyResult
971 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
972 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700973 if hasattr( main, 'Mininet1' ):
974 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
975 else:
976 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700977 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
978 main.scapyHosts = []
979
You Wang5da39c82018-04-26 22:55:08 -0700980 if removeHostComponent:
981 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
982 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700983 if hasattr( main, 'Mininet1' ):
984 pass
985 else:
986 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700987 main.Network.removeHostComponent( host )
988
You Wang5df1c6d2018-04-06 18:02:02 -0700989 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700990 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700991 else:
992 main.Network.disconnectInbandHosts()
993 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700994
You Wang5df1c6d2018-04-06 18:02:02 -0700995 if copyKarafLog:
996 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700997
Devin Lim142b5342017-07-20 15:22:39 -0700998 for ctrl in main.Cluster.active():
999 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall76408472020-06-23 13:13:33 -07001000 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001001
1002 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001003 def verifyNodes( main ):
1004 """
1005 Verifies Each active node in the cluster has an accurate view of other node's and their status
1006
1007 Params:
1008 nodes, integer array with position of the ONOS nodes in the CLIs array
1009 """
1010 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1011 False,
1012 attempts=10,
1013 sleep=10 )
1014 utilities.assert_equals( expect=True, actual=nodeResults,
1015 onpass="Nodes check successful",
1016 onfail="Nodes check NOT successful" )
1017
1018 if not nodeResults:
1019 for ctrl in main.Cluster.runningNodes:
1020 main.log.debug( "{} components not ACTIVE: \n{}".format(
1021 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001022 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001023 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001024 main.cleanAndExit()
1025
1026 @staticmethod
1027 def verifyTopology( main, switches, links, expNodes ):
1028 """
1029 Verifies that the ONOS cluster has an acuurate view of the topology
1030
1031 Params:
1032 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1033 """
1034 main.step( "Check number of topology elements" )
1035 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1036 main.FALSE,
1037 kwargs={ 'numoswitch': switches,
1038 'numolink': links,
1039 'numoctrl': expNodes },
1040 attempts=10,
1041 sleep=12 )
1042 utilities.assert_equals( expect=main.TRUE, actual=topology,
1043 onpass="Number of topology elements are correct",
1044 onfail="Unexpected number of links, switches, and/or controllers" )
1045
1046 @staticmethod
1047 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001048 """
1049 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1050 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1051 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1052 """
Jon Halla604fd42018-05-04 14:27:27 -07001053 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001054 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001055 if sleep is None:
1056 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1057 else:
1058 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001059
Jon Hall1efcb3f2016-08-23 13:42:15 -07001060 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001061 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001062 utilities.assert_equals( expect=main.TRUE, actual=killResult,
1063 onpass="ONOS instance Killed",
1064 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -07001065 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -07001066 main.Cluster.reset()
Jon Hall76408472020-06-23 13:13:33 -07001067 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001068 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001069
Devin Lim142b5342017-07-20 15:22:39 -07001070 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001071 Testcaselib.verifyNodes( main )
1072 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001073
1074 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001075 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001076 """
1077 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1078 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1079 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1080 """
Jon Hall3c910162018-03-07 14:42:16 -08001081 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001082 if sleep is None:
1083 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1084 else:
1085 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001086 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Hall76408472020-06-23 13:13:33 -07001087 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001088 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001089 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001090 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001091 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1092 onpass="ONOS service is ready",
1093 onfail="ONOS service did not start properly" )
1094 for i in nodes:
1095 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001096 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001097 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001098 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1099 commandlineTimeout=60,
1100 onosStartTimeout=100 )
1101 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001102 utilities.assert_equals( expect=main.TRUE,
1103 actual=cliResult,
1104 onpass="ONOS CLI is ready",
1105 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001106
Jon Halla604fd42018-05-04 14:27:27 -07001107 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001108 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001109 Testcaselib.verifyNodes( main )
1110 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001111
Devin Lim142b5342017-07-20 15:22:39 -07001112 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
1113 main.FALSE,
1114 attempts=10,
1115 sleep=12 )
1116 if ready:
1117 ready = main.TRUE
1118 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001119 onpass="ONOS summary command succeded",
1120 onfail="ONOS summary command failed" )
1121 if not ready:
1122 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001123 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001124
1125 @staticmethod
1126 def addHostCfg( main ):
1127 """
1128 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001129 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001130 """
1131 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001132 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001133 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001134 hostCfg = json.load( template )
1135 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1136 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001137 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001138 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1139 subjectClass="hosts",
1140 subjectKey=urllib.quote( mac,
1141 safe='' ),
1142 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001143 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1144 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001145 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001146 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1147 subjectClass="hosts",
1148 subjectKey=urllib.quote( mac,
1149 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001150 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001151 main.pingChart.update( { 'vlan1': { "expect": "True",
1152 "hosts": [ "olt1", "vsg1" ] } } )
1153 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1154 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001155 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001156 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001157 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1158 subjectClass="apps",
1159 subjectKey="org.onosproject.segmentrouting",
1160 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001161
1162 @staticmethod
1163 def delHostCfg( main ):
1164 """
1165 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001166 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001167 """
1168 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001169 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001170 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001171 hostCfg = json.load( template )
1172 main.step( "Removing host configuration" )
1173 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001174 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001175 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1176 subjectKey=urllib.quote(
1177 mac,
1178 safe='' ),
1179 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001180 main.step( "Removing configuration" )
1181 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001182 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001183 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1184 subjectKey=urllib.quote(
1185 mac,
1186 safe='' ),
1187 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001188 main.step( "Removing vlan configuration" )
1189 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001190 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1191 subjectKey="org.onosproject.segmentrouting",
1192 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001193
1194 @staticmethod
1195 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1196 """
1197 Verifies IP address assignment from the hosts
1198 """
1199 main.step( "Verify IP address assignment from hosts" )
1200 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001201 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001202 # Find out names of disconnected hosts
1203 disconnectedHosts = []
1204 if hasattr( main, "disconnectedIpv4Hosts" ):
1205 for host in main.disconnectedIpv4Hosts:
1206 disconnectedHosts.append( host )
1207 if hasattr( main, "disconnectedIpv6Hosts" ):
1208 for host in main.disconnectedIpv6Hosts:
1209 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001210 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001211 # Exclude disconnected hosts
1212 if hostName in disconnectedHosts:
1213 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1214 continue
You Wang53dba1e2018-02-02 17:45:44 -08001215 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1216 main.FALSE,
1217 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001218 'prefix': ip,
Jon Hall76408472020-06-23 13:13:33 -07001219 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001220 attempts=attempts,
1221 sleep=sleep )
1222 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1223 onpass="Verify network host IP succeded",
1224 onfail="Verify network host IP failed" )
1225
1226 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001227 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001228 """
1229 Verifies host IP address assignment from ONOS
1230 """
1231 main.step( "Verify host IP address assignment in ONOS" )
1232 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001233 # Find out IPs of disconnected hosts
1234 disconnectedIps = []
1235 if hasattr( main, "disconnectedIpv4Hosts" ):
1236 for host in main.disconnectedIpv4Hosts:
1237 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1238 if hasattr( main, "disconnectedIpv6Hosts" ):
1239 for host in main.disconnectedIpv6Hosts:
1240 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001241 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001242 # Exclude disconnected hosts
1243 if ip in disconnectedIps:
1244 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1245 continue
You Wang53dba1e2018-02-02 17:45:44 -08001246 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1247 main.FALSE,
1248 kwargs={ 'hostList': [ hostName ],
1249 'prefix': ip },
1250 attempts=attempts,
1251 sleep=sleep )
1252 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1253 onpass="Verify ONOS host IP succeded",
1254 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001255 if not ipResult and skipOnFail:
1256 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001257 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001258 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001259
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001260 @staticmethod
1261 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1262 """
1263 Description:
1264 Updates interface configuration in ONOS, with given IP and vlan parameters
1265 Required:
1266 * connectPoint: connect point to update configuration
1267 Optional:
1268 * ips: list of IP addresses, combined with '/xx' subnet representation,
1269 corresponding to 'ips' field in the configuration
1270 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1271 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1272 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1273 """
1274 cfg = dict()
1275 cfg[ "ports" ] = dict()
1276 cfg[ "ports" ][ connectPoint ] = dict()
1277 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1278 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1279 if untagged > 0:
1280 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1281 else:
1282 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1283 if native > 0:
1284 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1285
1286 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001287
1288 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001289 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001290 """
1291 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001292 scapyNames: list of names that will be used as component names for scapy hosts
1293 mininetNames: used when scapy host names are different from the host names
1294 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1295 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001296 """
1297 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001298 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1299 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001300 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001301 if hasattr( main, 'Mininet1' ):
1302 main.Scapy.createHostComponent( scapyName )
1303 scapyHandle = getattr( main, scapyName )
1304 if mininetNames:
1305 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1306 else:
1307 mininetName = None
Jon Hall76408472020-06-23 13:13:33 -07001308 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1309 scapyHandle.mExecDir = "/tmp"
1310 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1311 main.log.debug( "start mn host component in docker" )
1312 scapyHandle.startHostCli( mininetName,
1313 execDir="/tmp",
1314 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1315 else:
1316 main.log.debug( "start mn host component" )
1317 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001318 else:
You Wang0fc21702018-11-02 17:49:18 -07001319 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001320 scapyHandle = getattr( main, scapyName )
1321 scapyHandle.connectInband()
1322 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001323 scapyHandle.startScapy()
1324 scapyHandle.updateSelf()
1325 main.log.debug( scapyHandle.name )
1326 main.log.debug( scapyHandle.hostIp )
1327 main.log.debug( scapyHandle.hostMac )
1328
1329 @staticmethod
1330 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1331 """
1332 Verify unicast traffic by pinging from source hosts to the destination IP
1333 and capturing the packets at the destination host using Scapy.
1334 srcHosts: List of host names to send the ping packets
1335 dstIp: destination IP of the ping packets
1336 dstHost: host that runs Scapy to capture the packets
1337 dstIntf: name of the interface on the destination host
1338 expect: use True if the ping is expected to be captured at destination;
1339 Otherwise False
1340 skipOnFail: skip the rest of this test case if result is not expected
1341 maxRetry: number of retries allowed
1342 """
1343 from tests.dependencies.topology import Topology
1344 try:
1345 main.topo
1346 except ( NameError, AttributeError ):
1347 main.topo = Topology()
1348 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1349 result = main.TRUE
1350 for srcHost in srcHosts:
1351 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1352 expect, maxRetry, True )
1353 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001354 result = main.FALSE
1355 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1356 utilities.assert_equals( expect=main.TRUE,
1357 actual=result,
1358 onpass="Verify traffic to {}: Pass".format( dstIp ),
1359 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1360 if skipOnFail and result != main.TRUE:
1361 Testcaselib.saveOnosDiagnostics( main )
1362 Testcaselib.cleanup( main, copyKarafLog=False )
1363 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001364
1365 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001366 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001367 """
1368 Verify multicast traffic using scapy
1369 """
You Wangc564c6f2018-05-01 15:24:57 -07001370 from tests.dependencies.topology import Topology
1371 try:
1372 main.topo
1373 except ( NameError, AttributeError ):
1374 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001375 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001376 routeData = main.multicastConfig[ routeName ]
1377 srcs = main.mcastRoutes[ routeName ][ "src" ]
1378 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1379 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1380 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001381 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001382 for src in srcs:
1383 srcEntry = routeData[ "src" ][ src ]
1384 for dst in dsts:
1385 dstEntry = routeData[ "dst" ][ dst ]
1386 sender = getattr( main, srcEntry[ "host" ] )
1387 receiver = getattr( main, dstEntry[ "host" ] )
1388 main.Network.addRoute( str( srcEntry[ "host" ] ),
1389 str( routeData[ "group" ] ),
1390 str( srcEntry[ "interface" ] ),
1391 True if routeData[ "ipVersion" ] == 6 else False )
1392 # Build the packet
1393 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1394 if routeData[ "ipVersion" ] == 4:
1395 sender.buildIP( dst=str( routeData[ "group" ] ) )
1396 elif routeData[ "ipVersion" ] == 6:
1397 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1398 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1399 sIface = srcEntry[ "interface" ]
1400 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1401 pktFilter = srcEntry[ "filter" ]
1402 pkt = srcEntry[ "packet" ]
1403 # Send packet and check received packet
1404 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001405 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001406 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001407 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1408 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001409 if not trafficResult:
1410 result = main.FALSE
1411 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1412 dstEntry[ "host" ] ) )
1413 utilities.assert_equals( expect=main.TRUE,
1414 actual=result,
1415 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1416 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001417 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001418 Testcaselib.saveOnosDiagnostics( main )
1419 Testcaselib.cleanup( main, copyKarafLog=False )
1420 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001421
1422 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001423 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001424 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1425 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001426 """
1427 Verify reachability from each host in srcList to each host in dstList
1428 """
1429 from tests.dependencies.topology import Topology
1430 try:
1431 main.topo
1432 except ( NameError, AttributeError ):
1433 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001434 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001435 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001436 utilities.assert_equals( expect=main.TRUE,
1437 actual=pingResult,
1438 onpass="{}: Pass".format( stepMsg ),
1439 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001440 if not pingResult and skipOnFail:
1441 Testcaselib.saveOnosDiagnostics( main )
1442 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1443 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001444
1445 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001446 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001447 """
1448 Verify if the specified host is discovered by ONOS on the given locations
1449 Required:
You Wang85747762018-05-11 15:51:50 -07001450 locationDict: a dictionary that maps host names to expected locations.
1451 locations could be a string or a list.
1452 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001453 Returns:
1454 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1455 """
You Wang85747762018-05-11 15:51:50 -07001456 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1457 result = main.TRUE
1458 for hostName, locations in locationDict.items():
1459 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1460 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1461 if not hostIp:
1462 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1463 if not hostIp:
1464 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1465 result = main.FALSE
1466 continue
1467 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1468 main.FALSE,
1469 args=( hostIp, locations ),
1470 attempts=retry + 1,
1471 sleep=10 )
1472 if not locationResult:
1473 result = main.FALSE
1474 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001475 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001476 onpass="Location verification passed",
1477 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001478
1479 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001480 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001481 """
1482 Move specified host from srcSw to dstSw.
1483 If srcSw and dstSw are same, the host will be moved from current port to
1484 next available port.
1485 Required:
1486 hostName: name of the host. e.g., "h1"
1487 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1488 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1489 gw: ip address of the gateway of the new location
1490 Optional:
1491 macAddr: if specified, change MAC address of the host to the specified MAC address.
1492 prefixLen: prefix length
1493 cfg: port configuration as JSON string
1494 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001495 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001496 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001497 if not hasattr( main, 'Mininet1' ):
1498 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1499 return
1500
You Wang6e5b48e2018-07-23 16:17:38 -07001501 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1502 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1503 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001504 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001505 if cfg:
1506 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1507 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001508 # Wait for the host to get RA for setting up default gateway
Jon Hall76408472020-06-23 13:13:33 -07001509 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001510 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001511
1512 main.Mininet1.discoverHosts( [ hostName, ] )
1513
1514 # Update expectedHost when MAC address is changed.
1515 if macAddr is not None:
1516 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1517 if ipAddr is not None:
1518 for hostName, ip in main.expectedHosts[ "onos" ].items():
1519 if ip == ipAddr:
1520 vlan = hostName.split( "/" )[ -1 ]
1521 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001522 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001523 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001524
1525 @staticmethod
1526 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001527 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001528 """
1529 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1530 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1531 to next available port.
1532 Required:
1533 hostName: name of the host. e.g., "h1"
1534 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1535 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1536 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1537 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1538 gw: ip address of the gateway of the new location
1539 Optional:
1540 macAddr: if specified, change MAC address of the host to the specified MAC address.
1541 prefixLen: prefix length
1542 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001543 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001544 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001545 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001546 if not hasattr( main, 'Mininet1' ):
1547 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1548 return
1549
You Wang6e5b48e2018-07-23 16:17:38 -07001550 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1551 srcSw, srcPairSw, dstSw, dstPairSw ) )
1552 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1553 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1554 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001555 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001556 if cfg:
1557 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1558 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001559 # Wait for the host to get RA for setting up default gateway
Jon Hall76408472020-06-23 13:13:33 -07001560 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001561 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001562
1563 main.Mininet1.discoverHosts( [ hostName, ] )
1564
1565 # Update expectedHost when MAC address is changed.
1566 if macAddr is not None:
1567 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1568 if ipAddr is not None:
1569 for hostName, ip in main.expectedHosts[ "onos" ].items():
1570 if ip == ipAddr:
1571 vlan = hostName.split( "/" )[ -1 ]
1572 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001573 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall76408472020-06-23 13:13:33 -07001574
1575 @staticmethod
1576 def mnDockerSetup( main ):
1577 """
1578 Optionally start and setup docker image for mininet
1579 """
1580 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1581
1582 main.log.info( "Creating Mininet Docker" )
1583 handle = main.Mininet1.handle
1584 main.Mininet1.dockerPrompt = '#'
1585
1586 confDir = "/tmp/mn_conf/"
1587 # Try to ensure the destination exists
1588 main.log.info( "Create folder for network config files" )
1589 handle.sendline( "mkdir -p %s" % confDir )
1590 handle.expect( main.Mininet1.prompt )
1591 main.log.debug( handle.before + handle.after )
1592 # Make sure permissions are correct
1593 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1594 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1595 handle.expect( main.Mininet1.prompt )
1596 main.log.debug( handle.before + handle.after )
1597 # Start docker container
1598 handle.sendline( "docker run --name trellis_mininet %s %s" % ( main.params[ 'MN_DOCKER' ][ 'args' ], main.params[ 'MN_DOCKER' ][ 'name' ] ) )
1599 handle.expect( main.Mininet1.bashPrompt )
1600 output = handle.before + handle.after
1601 main.log.debug( repr(output) )
1602
1603 handle.sendline( "docker attach trellis_mininet" )
1604 handle.expect( main.Mininet1.dockerPrompt )
1605 main.log.debug( handle.before + handle.after )
1606 handle.sendline( "sysctl -w net.ipv4.ip_forward=0" )
1607 handle.sendline( "sysctl -w net.ipv4.conf.all.forwarding=0" )
1608 handle.expect( main.Mininet1.dockerPrompt )
1609 main.log.debug( handle.before + handle.after )
1610 # We should be good to go
1611 main.Mininet1.prompt = main.Mininet1.dockerPrompt
1612 main.Mininet1.sudoRequired = False
1613
1614 # Fow when we create component handles
1615 main.Mininet1.mExecDir = "/tmp"
1616 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1617 main.Mininet1.hostPrompt = "/home/root#"
1618
1619 @staticmethod
1620 def mnDockerTeardown( main ):
1621 """
1622 Optionally stop and cleanup docker image for mininet
1623 """
1624
1625 if hasattr( main, 'Mininet1' ):
1626 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1627 main.log.info( "Deleting Mininet Docker" )
1628
1629 # Detach from container
1630 handle = main.Mininet1.handle
1631 try:
1632 handle.sendline( "exit" ) # ctrl-p ctrk-q to detach from container
1633 main.log.debug( "sleeping %i seconds" % ( 5 ) )
1634 time.sleep(5)
1635 handle.expect( main.Mininet1.dockerPrompt )
1636 main.log.debug( handle.before + handle.after )
1637 main.Mininet1.prompt = main.Mininet1.bashPrompt
1638 handle.expect( main.Mininet1.prompt )
1639 main.log.debug( handle.before + handle.after )
1640 main.Mininet1.sudoRequired = True
1641 except Exception as e:
1642 main.log.error( e )
1643
1644 @staticmethod
1645 def setOnosConfig( main ):
1646 """
1647 Read and Set onos configurations from the params file
1648 """
1649 main.step( "Set ONOS configurations" )
1650 config = main.params.get( 'ONOS_Configuration' )
1651 if config:
1652 main.log.debug( config )
1653 checkResult = main.TRUE
1654 for component in config:
1655 for setting in config[ component ]:
1656 value = config[ component ][ setting ]
1657 check = main.Cluster.next().setCfg( component, setting, value )
1658 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1659 checkResult = check and checkResult
1660 utilities.assert_equals( expect=main.TRUE,
1661 actual=checkResult,
1662 onpass="Successfully set config",
1663 onfail="Failed to set config" )
1664 else:
1665 main.log.warn( "No configurations were specified to be changed after startup" )
1666
1667 @staticmethod
1668 def setOnosLogLevels( main ):
1669 """
1670 Read and Set onos log levels from the params file
1671 """
1672 main.step( 'Set logging levels' )
1673 logging = True
1674 try:
1675 logs = main.params.get( 'ONOS_Logging', False )
1676 if logs:
1677 for namespace, level in logs.items():
1678 for ctrl in main.Cluster.active():
1679 ctrl.CLI.logSet( level, namespace )
1680 except AttributeError:
1681 logging = False
1682 utilities.assert_equals( expect=True, actual=logging,
1683 onpass="Set log levels",
1684 onfail="Failed to set log levels" )