blob: 8fa0b96024b913b4813e45d24f02e79b3aa8b76b [file] [log] [blame]
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jon Hall1efcb3f2016-08-23 13:42:15 -070021import os
Jon Hall1efcb3f2016-08-23 13:42:15 -070022import time
23import json
24import urllib
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -070025import re
Jon Hallf6aeda22020-07-28 09:12:56 -070026import pexpect
Jon Hall1efcb3f2016-08-23 13:42:15 -070027from core import utilities
28
29
30class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070031
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070032 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070033
Jon Hall1efcb3f2016-08-23 13:42:15 -070034 @staticmethod
35 def initTest( main ):
36 """
37 - Construct tests variables
38 - GIT ( optional )
39 - Checkout ONOS master branch
40 - Pull latest ONOS code
41 - Building ONOS ( optional )
42 - Install ONOS package
43 - Build ONOS package
44 """
Devin Lim58046fa2017-07-05 16:55:00 -070045 try:
46 from tests.dependencies.ONOSSetup import ONOSSetup
47 main.testSetUp = ONOSSetup()
48 except ImportError:
49 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070050 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080051 from tests.dependencies.Network import Network
52 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070053 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080054 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070055 stepResult = main.FALSE
56 try:
Devin Lim58046fa2017-07-05 16:55:00 -070057 # Test variables
58 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
59 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070060 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080061 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
62 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
63 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080064 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
65 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
66 else:
67 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070068 if main.useBmv2:
69 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
70 else:
71 main.switchType = "ovs"
72
Devin Lim57221b02018-02-14 15:45:36 -080073 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070074 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080075 main.forJson = "json/"
76 main.forChart = "chart/"
77 main.forConfig = "conf/"
78 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080079 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080080 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070081 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070082 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080083 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
84 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080085 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070086 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070087 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070088 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070089 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070090 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070091
Devin Lim0c972b72018-02-08 14:53:59 -080092 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070093 except Exception as e:
94 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070095
Jon Hallaa1d9b82020-07-30 13:49:42 -070096 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070097
Jon Hall1efcb3f2016-08-23 13:42:15 -070098 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080099 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
100 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700101 """
102 - Set up cell
103 - Create cell file
104 - Set cell file
105 - Verify cell file
106 - Kill ONOS process
107 - Uninstall ONOS cluster
108 - Verify ONOS start up
109 - Install ONOS cluster
110 - Connect to cli
111 """
112 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700113 try:
114 if main.params.get( 'EXTERNAL_APPS' ):
115 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
116 main.log.info( "Downloading %s app from %s" )
117 main.ONOSbench.onosFetchApp( url )
118 if not main.apps:
119 main.log.error( "App list is empty" )
120 except Exception as e:
121 main.log.debug( e )
122 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800123 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
124 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700125 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800126 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800127 skipPack=skipPackage,
128 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800129 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700130 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700131 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800132 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700133 attempts=10 )
134 if ready:
135 ready = main.TRUE
136 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700137 onpass="ONOS summary command succeded",
138 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700139 if not ready:
140 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700141 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700142
You Wang5bf49592020-07-08 18:47:46 -0700143 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700144 appInstallResult = main.TRUE
145 if main.trellisOar:
146 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700147 if main.t3Oar:
148 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
149 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
150 onpass="SR app installation succeded",
151 onfail="SR app installation failed" )
152 if not appInstallResult:
153 main.cleanAndExit()
154
Jon Hall43060f62020-06-23 13:13:33 -0700155 # FIXME: move to somewhere else?
156 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
157 # TODO: Support other pipeconfs/making this configurable
158 if switchPrefix == "tofino":
159 # It seems to take some time for the pipeconfs to be loaded
160 ctrl = main.Cluster.next()
161 for i in range( 120 ):
162 try:
163 main.log.debug( "Checking to see if pipeconfs are loaded" )
164 output = ctrl.CLI.sendline( "pipeconfs" )
165 if "tofino" in output:
166 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
167 break
168 time.sleep( 1 )
169 except Exception as e:
170 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700171
Jon Hall43060f62020-06-23 13:13:33 -0700172 Testcaselib.setOnosLogLevels( main )
173 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700174
Jon Hall1efcb3f2016-08-23 13:42:15 -0700175 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800176 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700177 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
178 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800179
180 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700181 def loadJson( main, suffix='' ):
182 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
183 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800184 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
185
186 @staticmethod
187 def loadChart( main ):
188 try:
189 with open( "%s%s.chart" % ( main.configPath + main.forChart,
190 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700191 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800192 except IOError:
193 main.log.warn( "No chart file found." )
194
195 @staticmethod
196 def loadHost( main ):
197 with open( "%s%s.host" % ( main.configPath + main.forHost,
198 main.cfgName ) ) as host:
199 main.expectedHosts = json.load( host )
200
201 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800202 def loadSwitchFailureChart( main ):
203 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
204 main.cfgName ) ) as sfc:
205 main.switchFailureChart = json.load( sfc )
206
207 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800208 def loadLinkFailureChart( main ):
209 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700210 main.cfgName ) ) as lfc:
211 main.linkFailureChart = json.load( lfc )
212
213 @staticmethod
214 def loadMulticastConfig( main ):
215 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
216 main.cfgName ) ) as cfg:
217 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800218
219 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700220 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700221 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800222 copyResult = main.ONOSbench.scp( main.Mininet1,
223 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700224 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800225 direction="to" )
226 if main.topologyLib:
227 for lib in main.topologyLib.split(","):
228 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
229 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700230 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800231 direction="to" )
232 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700233 import re
234 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
235 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700236 destDir = "~/"
237 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
238 destDir = "/tmp/mn_conf/"
239 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800240 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700241 # Update zebra configurations with correct ONOS instance IP
242 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
243 ip = controllerIPs[ index ]
244 index = ( index + 1 ) % len( controllerIPs )
245 with open( main.configPath + main.forConfig + conf ) as f:
246 s = f.read()
247 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
248 with open( main.configPath + main.forConfig + conf, "w" ) as f:
249 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800250 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800251 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700252 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800253 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800254 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700255 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800256 main.Mininet1.home + "custom",
257 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800258 stepResult = copyResult
259 utilities.assert_equals( expect=main.TRUE,
260 actual=stepResult,
261 onpass="Successfully copied topo files",
262 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700263 if main.stratumRoot:
264 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700265 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700266 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700267 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700268 main.topology = topology
269 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700270 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700271 stepResult = topoResult
272 utilities.assert_equals( expect=main.TRUE,
273 actual=stepResult,
274 onpass="Successfully loaded topology",
275 onfail="Failed to load topology" )
276 # Exit if topology did not load properly
277 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700278 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700279 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700280 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700281 # Upload the net-cfg file created for each switch
282 filename = "onos-netcfg.json"
283 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700284 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700285 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
286 path = "/tmp/mn-stratum/%s/" % switch
287 dstPath = "/tmp/"
288 dstFileName = "%s-onos-netcfg.json" % switch
289 main.ONOSbench1.scp( main.Mininet1,
290 "%s%s" % ( path, filename ),
291 "%s%s" % ( dstPath, dstFileName ),
292 "from" )
293 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 -0700294 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700295 # Configure managementAddress
296 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
297 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
298 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
299 # Configure device id
300 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
301 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
302 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
303 # Configure device name
304 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s\",' %s%s" % ( switch, dstPath, dstFileName ) )
305 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
306 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700307 node = main.Cluster.active(0)
308 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
309 dstPath,
310 dstFileName,
311 user=node.REST.user_name,
312 password=node.REST.pwd )
313 # Stop test if we fail to push switch netcfg
314 utilities.assert_equals( expect=main.TRUE,
315 actual=switchNetCfg,
316 onpass="Successfully pushed switch netcfg",
317 onfail="Failed to configure switches in onos" )
318 if not switchNetCfg:
319 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700320 # Make sure hosts make some noise
321 Testcaselib.discoverHosts( main )
322
323 @staticmethod
324 def discoverHosts( main ):
325 # TODO add option to only select specific hosts
326 if hasattr( main, "Mininet1" ):
327 network = main.Mininet1
328 elif hasattr( main, "NetworkBench" ):
329 network = main.NetworkBench
330 else:
331 main.log.warn( "Could not find component for test network, skipping host discovery" )
332 return
333 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700334
335 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700336 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800337 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700338 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800339 topoResult = main.NetworkBench.connectToNet()
340 stepResult = topoResult
341 utilities.assert_equals( expect=main.TRUE,
342 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700343 onpass="Successfully connected to topology",
344 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800345 # Exit if topology did not load properly
346 if not topoResult:
347 main.cleanAndExit()
348
Jon Hall43060f62020-06-23 13:13:33 -0700349 # Perform any optional setup
350 for switch in main.NetworkBench.switches:
351 if hasattr( switch, "setup" ):
352 switch.setup() # We might not need this
353
You Wang84f981d2018-01-12 16:11:50 -0800354 main.step( "Assign switches to controllers." )
Jon Hall43060f62020-06-23 13:13:33 -0700355 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700356 switches = main.NetworkBench.getSwitches()
357 pool = []
358 for name in switches.keys():
Jon Hall43060f62020-06-23 13:13:33 -0700359 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
360 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700361 thread = main.Thread( target=main.NetworkBench.assignSwController,
362 name="assignSwitchToController",
363 args=[ name, main.Cluster.getIps(), '6653' ] )
364 pool.append( thread )
365 thread.start()
366 for thread in pool:
367 thread.join( 300 )
368 if not thread.result:
369 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800370 utilities.assert_equals( expect=main.TRUE,
371 actual=stepResult,
372 onpass="Successfully assign switches to controllers",
373 onfail="Failed to assign switches to controllers" )
374
You Wang4cc61912018-08-28 10:10:58 -0700375 # Check devices
376 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700377 # Connecting to hosts that only have data plane connectivity
378 main.step( "Connecting inband hosts" )
379 stepResult = main.Network.connectInbandHosts()
380 utilities.assert_equals( expect=main.TRUE,
381 actual=stepResult,
382 onpass="Successfully connected inband hosts",
383 onfail="Failed to connect inband hosts" )
Jon Hall43060f62020-06-23 13:13:33 -0700384 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700385
You Wang84f981d2018-01-12 16:11:50 -0800386 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700387 def saveOnosDiagnostics( main ):
388 """
389 Get onos-diags.tar.gz and save it to the log directory.
390 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
391 """
392 main.log.info( "Collecting onos-diags..." )
393 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
394 main.logdir,
395 "-CASE%d" % main.CurrentTestCaseNumber )
396
397 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700398 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700399 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700400
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700401 main.failures = int( main.params[ 'failures' ] )
402 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700403
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700404 if main.cfgName == '2x2':
405 spine = {}
406 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
407 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
408 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700409
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700410 spine = {}
411 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
412 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
413 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700414
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700415 elif main.cfgName == '4x4':
416 spine = {}
417 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
418 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
419 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700420
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700421 spine = {}
422 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
423 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
424 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700425
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700426 spine = {}
427 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
428 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
429 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700430
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700431 spine = {}
432 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
433 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
434 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700435
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700436 else:
Piera2a7e1b2016-10-04 11:51:43 -0700437 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700438 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800439
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800440 @staticmethod
441 def addStaticOnosRoute( main, subnet, intf):
442 """
443 Adds an ONOS static route with the use route-add command.
444 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800445 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
446
Piera2a7e1b2016-10-04 11:51:43 -0700447 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700448 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700449 """
450 Check number of groups for each subnet on device deviceId and matches
451 it with an expected value. subnetDict is a dictionarty containing values
452 of the type "10.0.1.0/24" : 5.
453 """
You Wangc02f3be2018-05-18 12:14:23 -0700454 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
455 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
456 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700457
You Wangc02f3be2018-05-18 12:14:23 -0700458 result = main.TRUE
459 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700460 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700461 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700462 # this will match the group id that this flow entry points to, for example :
463 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700464 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700465 count = 0
466 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700467 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700468 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700469 if count - 1 != numberInSelect:
470 result = main.FALSE
471 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 ) )
472 utilities.assert_equals( expect=main.TRUE, actual=result,
473 onpass="All bucket numbers are as expected",
474 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700475
476 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900477 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700478 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800479 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900480 if tag == "":
481 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700482 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700483 main.FALSE,
484 kwargs={ 'min': minFlowCount },
485 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800486 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800487 if count == main.FALSE:
488 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700489 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700490 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800491 actual=( count > minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700492 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
493 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700494
495 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700496 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700497 main.FALSE,
498 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800499 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800500 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700501 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700502 expect=main.TRUE,
503 actual=flowCheck,
504 onpass="Flow status is correct!",
505 onfail="Flow status is wrong!" )
506 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700507 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700508 "flows",
509 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900510 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700511 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700512 "groups",
513 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900514 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700515
516 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700517 def checkDevices( main, switches, tag="", sleep=10 ):
518 main.step(
519 "Check whether the switches count is equal to %s" % switches )
520 if tag == "":
521 tag = 'CASE%d' % main.CurrentTestCaseNumber
522 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
523 main.FALSE,
524 kwargs={ 'numoswitch': switches},
525 attempts=10,
526 sleep=sleep )
527 utilities.assert_equals( expect=main.TRUE, actual=result,
528 onpass="Device up successful",
529 onfail="Failed to boot up devices?" )
530
531 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800532 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
533 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700534 "Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800535 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
536 main.FALSE,
537 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800538 attempts=5,
539 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800540 if count == main.FALSE:
541 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800542 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800543 expect=True,
544 actual=( count > minFlowCount ),
545 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800546 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800547
548 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700549 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800550 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700551 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800552 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
553 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700554 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -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 )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800559 utilities.assertEquals(
560 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800561 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700562 onpass="Flow count looks correct: " + str( count ) ,
563 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800564
565 @staticmethod
566 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
567 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700568 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800569 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
570 main.FALSE,
571 args=( dpid, groupCount, False, 1),
572 attempts=5,
573 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800574 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800575 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800576 utilities.assertEquals(
577 expect=True,
578 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700579 onpass="Group count looks correct: " + str( count ) ,
580 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800581
582 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700583 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800584
585 for dpid, values in main.count.items():
586 flowCount = values["flows"]
587 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700588 main.log.report( "Check flow count for dpid " + str( dpid ) +
589 ", should be " + str( flowCount ) )
590 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800591
Jon Hall9677ed32018-04-24 11:16:23 -0700592 main.log.report( "Check group count for dpid " + str( dpid ) +
593 ", should be " + str( groupCount ) )
594 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800595
596 return
597
598 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700599 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
600 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800601 '''
You Wangba231e72018-03-01 13:18:21 -0800602 Verify connectivity between hosts according to the ping chart
603 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800604 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800605 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800606 '''
You Wangba231e72018-03-01 13:18:21 -0800607 main.log.report( "Check host connectivity" )
608 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800609 if tag == "":
610 tag = 'CASE%d' % main.CurrentTestCaseNumber
611 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800612 main.log.debug( "Entry in ping chart: %s" % entry )
613 expect = entry[ 'expect' ]
614 if expect == "Unidirectional":
615 # Verify ping from each src host to each dst host
616 src = entry[ 'src' ]
617 dst = entry[ 'dst' ]
618 expect = main.TRUE
619 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
620 if basedOnIp:
621 if ("v4" in src[0]):
622 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
623 utilities.assert_equals( expect=expect, actual=pa,
624 onpass="IPv4 connectivity successfully tested",
625 onfail="IPv4 connectivity failed" )
626 if ("v6" in src[0]):
627 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
628 utilities.assert_equals( expect=expect, actual=pa,
629 onpass="IPv6 connectivity successfully tested",
630 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700631 elif main.physicalNet:
632 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
633 utilities.assert_equals( expect=expect, actual=pa,
634 onpass="IP connectivity successfully tested",
635 onfail="IP connectivity failed" )
636
You Wangba231e72018-03-01 13:18:21 -0800637 else:
638 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
639 utilities.assert_equals( expect=expect, actual=pa,
640 onpass="IP connectivity successfully tested",
641 onfail="IP connectivity failed" )
642 else:
643 # Verify ping between each host pair
644 hosts = entry[ 'hosts' ]
645 try:
646 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
647 except:
648 expect = main.FALSE
649 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
650 if basedOnIp:
651 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800652 pa = utilities.retry( main.Network.pingallHosts,
653 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700654 args=(hosts, ),
655 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800656 attempts=retryAttempts,
657 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800658 utilities.assert_equals( expect=expect, actual=pa,
659 onpass="IPv4 connectivity successfully tested",
660 onfail="IPv4 connectivity failed" )
661 if ("v6" in hosts[0]):
662 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
663 utilities.assert_equals( expect=expect, actual=pa,
664 onpass="IPv6 connectivity successfully tested",
665 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700666 elif main.physicalNet:
667 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
668 utilities.assert_equals( expect=expect, actual=pa,
669 onpass="IP connectivity successfully tested",
670 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800671 else:
You Wangf19d9f42018-02-23 16:34:19 -0800672 pa = main.Network.pingallHosts( hosts )
673 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800674 onpass="IP connectivity successfully tested",
675 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700676 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700677 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700678 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700679 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700680 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800681
682 if dumpflows:
683 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
684 "flows",
685 main.logdir,
686 tag + "_FlowsOn" )
687 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
688 "groups",
689 main.logdir,
690 tag + "_GroupsOn" )
691
692 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700693 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700694 """
695 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
696 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
697 Kill a link and verify ONOS can see the proper link change
698 """
Jon Halla604fd42018-05-04 14:27:27 -0700699 if sleep is None:
700 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
701 else:
702 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700703 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700704 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
705 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
706 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700707 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700708 "Waiting %s seconds for link down to be discovered" % sleep )
709 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700710 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700711 main.FALSE,
712 kwargs={ 'numoswitch': switches,
713 'numolink': links },
714 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700715 sleep=sleep )
716 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700717 utilities.assert_equals( expect=main.TRUE, actual=result,
718 onpass="Link down successful",
719 onfail="Failed to turn off link?" )
720
721 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700722 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800723 """
724 links = list of links (src, dst) to bring down.
725 """
726
727 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700728 if sleep is None:
729 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
730 else:
731 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800732
733 for end1, end2 in links:
734 main.Network.link( END1=end1, END2=end2, OPTION="down")
735 main.Network.link( END1=end2, END2=end1, OPTION="down")
736
Jon Halla604fd42018-05-04 14:27:27 -0700737 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800738 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700739 "Waiting %s seconds for links down to be discovered" % sleep )
740 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800741
742 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
743 main.FALSE,
744 kwargs={ 'numoswitch': switches,
745 'numolink': linksAfter },
746 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700747 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800748
You Wang2854bce2018-03-30 10:15:32 -0700749 utilities.assert_equals( expect=main.TRUE, actual=topology,
750 onpass="Link batch down successful",
751 onfail="Link batch down failed" )
752
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800753 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700754 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800755 """
756 links = list of link (src, dst) to bring up again.
757 """
758
759 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700760 if sleep is None:
761 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
762 else:
763 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800764
765 for end1, end2 in links:
766 main.Network.link( END1=end1, END2=end2, OPTION="up")
767 main.Network.link( END1=end2, END2=end1, OPTION="up")
768
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800769 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700770 "Waiting %s seconds for links up to be discovered" % sleep )
771 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800772
773 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
774 main.FALSE,
775 kwargs={ 'numoswitch': switches,
776 'numolink': linksAfter },
777 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700778 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800779
You Wang2854bce2018-03-30 10:15:32 -0700780 utilities.assert_equals( expect=main.TRUE, actual=topology,
781 onpass="Link batch up successful",
782 onfail="Link batch up failed" )
783
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800784 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700785 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
786 """
787 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
788 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
789 switches, links: number of expected switches and links after link change, ex.: '4', '6'
790 """
791 if sleep is None:
792 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
793 else:
794 sleep = float( sleep )
795 main.step( "Disable a batch of ports" )
796 for dpid, port in ports:
797 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
798 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
799 time.sleep( sleep )
800 if switches and links:
801 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
802 numolink=links )
803 utilities.assert_equals( expect=main.TRUE, actual=result,
804 onpass="Port down successful",
805 onfail="Port down failed" )
806
807 @staticmethod
808 def enablePortBatch( main, ports, switches, links, sleep=None ):
809 """
810 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
811 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
812 switches, links: number of expected switches and links after link change, ex.: '4', '6'
813 """
814 if sleep is None:
815 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
816 else:
817 sleep = float( sleep )
818 main.step( "Enable a batch of ports" )
819 for dpid, port in ports:
820 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
821 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
822 time.sleep( sleep )
823 if switches and links:
824 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
825 numolink=links )
826 utilities.assert_equals( expect=main.TRUE, actual=result,
827 onpass="Port up successful",
828 onfail="Port up failed" )
829
830 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700831 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700832 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700833 """
834 Params:
835 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700836 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700837 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
838 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
839 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
840 Kill a link and verify ONOS can see the proper link change
841 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700842 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700843 if sleep is None:
844 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
845 else:
846 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700847 result = False
848 count = 0
849 while True:
850 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700851 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800852 main.Network.link( END1=end1, END2=end2, OPTION="up" )
853 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700854 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700855 "Waiting %s seconds for link up to be discovered" % sleep )
856 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700857
You Wangc02d8352018-04-17 16:42:10 -0700858 if portUp:
859 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
860 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700861 main.log.info(
862 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700863 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700864
Jon Halla604fd42018-05-04 14:27:27 -0700865 result = ctrl.CLI.checkStatus( numoswitch=switches,
866 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700867 if count > 5 or result:
868 break
869 utilities.assert_equals( expect=main.TRUE, actual=result,
870 onpass="Link up successful",
871 onfail="Failed to bring link up" )
872
873 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700874 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700875 """
876 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
877 Completely kill a switch and verify ONOS can see the proper change
878 """
Jon Halla604fd42018-05-04 14:27:27 -0700879 if sleep is None:
880 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
881 else:
882 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700883 switch = switch if isinstance( switch, list ) else [ switch ]
884 main.step( "Kill " + str( switch ) )
885 for s in switch:
886 main.log.info( "Stopping " + s )
887 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700888 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700889
890 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700891 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700892 sleep ) )
893 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700894 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700895 main.FALSE,
896 kwargs={ 'numoswitch': switches,
897 'numolink': links },
898 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700899 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700900 utilities.assert_equals( expect=main.TRUE, actual=topology,
901 onpass="Kill switch successful",
902 onfail="Failed to kill switch?" )
903
904 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700905 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700906 """
907 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
908 Recover a switch and verify ONOS can see the proper change
909 """
Jon Halla604fd42018-05-04 14:27:27 -0700910 if sleep is None:
911 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
912 else:
913 sleep = float( sleep )
914 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700915 switch = switch if isinstance( switch, list ) else [ switch ]
916 main.step( "Recovering " + str( switch ) )
917 for s in switch:
918 main.log.info( "Starting " + s )
919 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700920 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700921 sleep ) )
922 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700923 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700924 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700925 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700926 sleep ) )
927 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700928
Devin Lim142b5342017-07-20 15:22:39 -0700929 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700930 main.FALSE,
931 kwargs={ 'numoswitch': switches,
932 'numolink': links },
933 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700934 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700935 utilities.assert_equals( expect=main.TRUE, actual=topology,
936 onpass="Switch recovery successful",
937 onfail="Failed to recover switch?" )
938
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700939 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700940 def killRouter( main, router, sleep=None ):
941 """
942 Kill bgpd process on a quagga router
943 router: name of the router to be killed. E.g. "bgp1"
944 """
945 sleep = float( sleep )
946 main.step( "Kill " + str( router ) )
947 if hasattr( main, 'Mininet1' ):
948 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
949 main.Mininet1.handle.expect( "mininet>" )
950 else:
951 # TODO: support killing router in physical network
952 pass
953 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
954 time.sleep( sleep )
955
956 @staticmethod
957 def recoverRouter( main, router, sleep=None ):
958 """
959 Restart bgpd process on a quagga router
960 router: name of the router to be recovered. E.g. "bgp1"
961 """
962 sleep = float( sleep )
963 main.step( "Recovering " + str( router ) )
964 if hasattr( main, 'Mininet1' ):
965 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
966 main.Mininet1.handle.expect( "mininet>" )
967 else:
968 # TODO: support recovering router in physical network
969 pass
970 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
971 time.sleep( sleep )
972
973 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700974 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700975 """
976 Stop Onos-cluster.
977 Stops Mininet
978 Copies ONOS log
979 """
You Wang4cc61912018-08-28 10:10:58 -0700980 from tests.dependencies.utils import Utils
981 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -0700982 for ctrl in main.Cluster.active():
983 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -0700984 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700985 if hasattr( main, "scapyHosts" ):
986 scapyResult = main.TRUE
987 for host in main.scapyHosts:
988 scapyResult = host.stopScapy() and scapyResult
989 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
990 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700991 if hasattr( main, 'Mininet1' ):
992 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
993 else:
994 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700995 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
996 main.scapyHosts = []
997
You Wang5da39c82018-04-26 22:55:08 -0700998 if removeHostComponent:
999 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1000 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001001 if hasattr( main, 'Mininet1' ):
1002 pass
1003 else:
1004 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001005 main.Network.removeHostComponent( host )
1006
You Wang5df1c6d2018-04-06 18:02:02 -07001007 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001008 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001009 else:
1010 main.Network.disconnectInbandHosts()
1011 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001012
You Wang5df1c6d2018-04-06 18:02:02 -07001013 if copyKarafLog:
1014 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001015
Devin Lim142b5342017-07-20 15:22:39 -07001016 for ctrl in main.Cluster.active():
1017 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001018 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001019
1020 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001021 def verifyNodes( main ):
1022 """
1023 Verifies Each active node in the cluster has an accurate view of other node's and their status
1024
1025 Params:
1026 nodes, integer array with position of the ONOS nodes in the CLIs array
1027 """
1028 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1029 False,
1030 attempts=10,
1031 sleep=10 )
1032 utilities.assert_equals( expect=True, actual=nodeResults,
1033 onpass="Nodes check successful",
1034 onfail="Nodes check NOT successful" )
1035
1036 if not nodeResults:
1037 for ctrl in main.Cluster.runningNodes:
1038 main.log.debug( "{} components not ACTIVE: \n{}".format(
1039 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001040 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001041 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001042 main.cleanAndExit()
1043
1044 @staticmethod
1045 def verifyTopology( main, switches, links, expNodes ):
1046 """
1047 Verifies that the ONOS cluster has an acuurate view of the topology
1048
1049 Params:
1050 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1051 """
1052 main.step( "Check number of topology elements" )
1053 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1054 main.FALSE,
1055 kwargs={ 'numoswitch': switches,
1056 'numolink': links,
1057 'numoctrl': expNodes },
1058 attempts=10,
1059 sleep=12 )
1060 utilities.assert_equals( expect=main.TRUE, actual=topology,
1061 onpass="Number of topology elements are correct",
1062 onfail="Unexpected number of links, switches, and/or controllers" )
1063
1064 @staticmethod
1065 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001066 """
1067 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1068 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1069 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1070 """
Jon Halla604fd42018-05-04 14:27:27 -07001071 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001072 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001073 if sleep is None:
1074 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1075 else:
1076 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001077
Jon Hall1efcb3f2016-08-23 13:42:15 -07001078 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001079 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001080 utilities.assert_equals( expect=main.TRUE, actual=killResult,
1081 onpass="ONOS instance Killed",
1082 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -07001083 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -07001084 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001085 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001086 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001087
Devin Lim142b5342017-07-20 15:22:39 -07001088 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001089 Testcaselib.verifyNodes( main )
1090 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001091
1092 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001093 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001094 """
1095 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1096 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1097 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1098 """
Jon Hall3c910162018-03-07 14:42:16 -08001099 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001100 if sleep is None:
1101 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1102 else:
1103 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001104 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Hall43060f62020-06-23 13:13:33 -07001105 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001106 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001107 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001108 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001109 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1110 onpass="ONOS service is ready",
1111 onfail="ONOS service did not start properly" )
1112 for i in nodes:
1113 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001114 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001115 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001116 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1117 commandlineTimeout=60,
1118 onosStartTimeout=100 )
1119 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001120 utilities.assert_equals( expect=main.TRUE,
1121 actual=cliResult,
1122 onpass="ONOS CLI is ready",
1123 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001124
Jon Halla604fd42018-05-04 14:27:27 -07001125 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001126 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001127 Testcaselib.verifyNodes( main )
1128 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001129
Devin Lim142b5342017-07-20 15:22:39 -07001130 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001131 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001132 attempts=10,
1133 sleep=12 )
1134 if ready:
1135 ready = main.TRUE
1136 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001137 onpass="ONOS summary command succeded",
1138 onfail="ONOS summary command failed" )
1139 if not ready:
1140 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001141 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001142
1143 @staticmethod
1144 def addHostCfg( main ):
1145 """
1146 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001147 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001148 """
1149 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001150 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001151 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001152 hostCfg = json.load( template )
1153 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1154 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001155 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001156 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1157 subjectClass="hosts",
1158 subjectKey=urllib.quote( mac,
1159 safe='' ),
1160 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001161 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1162 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001163 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001164 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1165 subjectClass="hosts",
1166 subjectKey=urllib.quote( mac,
1167 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001168 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001169 main.pingChart.update( { 'vlan1': { "expect": "True",
1170 "hosts": [ "olt1", "vsg1" ] } } )
1171 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1172 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001173 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001174 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001175 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1176 subjectClass="apps",
1177 subjectKey="org.onosproject.segmentrouting",
1178 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001179
1180 @staticmethod
1181 def delHostCfg( main ):
1182 """
1183 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001184 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001185 """
1186 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001187 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001188 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001189 hostCfg = json.load( template )
1190 main.step( "Removing host configuration" )
1191 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001192 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001193 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1194 subjectKey=urllib.quote(
1195 mac,
1196 safe='' ),
1197 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001198 main.step( "Removing configuration" )
1199 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001200 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001201 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1202 subjectKey=urllib.quote(
1203 mac,
1204 safe='' ),
1205 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001206 main.step( "Removing vlan configuration" )
1207 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001208 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1209 subjectKey="org.onosproject.segmentrouting",
1210 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001211
1212 @staticmethod
1213 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1214 """
1215 Verifies IP address assignment from the hosts
1216 """
1217 main.step( "Verify IP address assignment from hosts" )
1218 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001219 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001220 # Find out names of disconnected hosts
1221 disconnectedHosts = []
1222 if hasattr( main, "disconnectedIpv4Hosts" ):
1223 for host in main.disconnectedIpv4Hosts:
1224 disconnectedHosts.append( host )
1225 if hasattr( main, "disconnectedIpv6Hosts" ):
1226 for host in main.disconnectedIpv6Hosts:
1227 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001228 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001229 # Exclude disconnected hosts
1230 if hostName in disconnectedHosts:
1231 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1232 continue
You Wang53dba1e2018-02-02 17:45:44 -08001233 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1234 main.FALSE,
1235 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001236 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001237 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001238 attempts=attempts,
1239 sleep=sleep )
1240 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1241 onpass="Verify network host IP succeded",
1242 onfail="Verify network host IP failed" )
1243
1244 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001245 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001246 """
1247 Verifies host IP address assignment from ONOS
1248 """
1249 main.step( "Verify host IP address assignment in ONOS" )
1250 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001251 # Find out IPs of disconnected hosts
1252 disconnectedIps = []
1253 if hasattr( main, "disconnectedIpv4Hosts" ):
1254 for host in main.disconnectedIpv4Hosts:
1255 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1256 if hasattr( main, "disconnectedIpv6Hosts" ):
1257 for host in main.disconnectedIpv6Hosts:
1258 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001259 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001260 # Exclude disconnected hosts
1261 if ip in disconnectedIps:
1262 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1263 continue
You Wang53dba1e2018-02-02 17:45:44 -08001264 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1265 main.FALSE,
1266 kwargs={ 'hostList': [ hostName ],
1267 'prefix': ip },
1268 attempts=attempts,
1269 sleep=sleep )
1270 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1271 onpass="Verify ONOS host IP succeded",
1272 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001273 if not ipResult and skipOnFail:
1274 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001275 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001276 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001277
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001278 @staticmethod
1279 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1280 """
1281 Description:
1282 Updates interface configuration in ONOS, with given IP and vlan parameters
1283 Required:
1284 * connectPoint: connect point to update configuration
1285 Optional:
1286 * ips: list of IP addresses, combined with '/xx' subnet representation,
1287 corresponding to 'ips' field in the configuration
1288 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1289 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1290 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1291 """
1292 cfg = dict()
1293 cfg[ "ports" ] = dict()
1294 cfg[ "ports" ][ connectPoint ] = dict()
1295 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1296 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1297 if untagged > 0:
1298 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1299 else:
1300 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1301 if native > 0:
1302 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1303
1304 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001305
1306 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001307 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001308 """
1309 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001310 scapyNames: list of names that will be used as component names for scapy hosts
1311 mininetNames: used when scapy host names are different from the host names
1312 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1313 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001314 """
1315 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001316 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1317 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001318 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001319 if hasattr( main, 'Mininet1' ):
1320 main.Scapy.createHostComponent( scapyName )
1321 scapyHandle = getattr( main, scapyName )
1322 if mininetNames:
1323 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1324 else:
1325 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001326 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1327 scapyHandle.mExecDir = "/tmp"
1328 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1329 main.log.debug( "start mn host component in docker" )
1330 scapyHandle.startHostCli( mininetName,
1331 execDir="/tmp",
1332 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1333 else:
1334 main.log.debug( "start mn host component" )
1335 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001336 else:
You Wang0fc21702018-11-02 17:49:18 -07001337 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001338 scapyHandle = getattr( main, scapyName )
1339 scapyHandle.connectInband()
1340 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001341 scapyHandle.startScapy()
1342 scapyHandle.updateSelf()
1343 main.log.debug( scapyHandle.name )
1344 main.log.debug( scapyHandle.hostIp )
1345 main.log.debug( scapyHandle.hostMac )
1346
1347 @staticmethod
1348 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1349 """
1350 Verify unicast traffic by pinging from source hosts to the destination IP
1351 and capturing the packets at the destination host using Scapy.
1352 srcHosts: List of host names to send the ping packets
1353 dstIp: destination IP of the ping packets
1354 dstHost: host that runs Scapy to capture the packets
1355 dstIntf: name of the interface on the destination host
1356 expect: use True if the ping is expected to be captured at destination;
1357 Otherwise False
1358 skipOnFail: skip the rest of this test case if result is not expected
1359 maxRetry: number of retries allowed
1360 """
1361 from tests.dependencies.topology import Topology
1362 try:
1363 main.topo
1364 except ( NameError, AttributeError ):
1365 main.topo = Topology()
1366 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1367 result = main.TRUE
1368 for srcHost in srcHosts:
1369 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1370 expect, maxRetry, True )
1371 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001372 result = main.FALSE
1373 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1374 utilities.assert_equals( expect=main.TRUE,
1375 actual=result,
1376 onpass="Verify traffic to {}: Pass".format( dstIp ),
1377 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1378 if skipOnFail and result != main.TRUE:
1379 Testcaselib.saveOnosDiagnostics( main )
1380 Testcaselib.cleanup( main, copyKarafLog=False )
1381 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001382
1383 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001384 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001385 """
1386 Verify multicast traffic using scapy
1387 """
You Wangc564c6f2018-05-01 15:24:57 -07001388 from tests.dependencies.topology import Topology
1389 try:
1390 main.topo
1391 except ( NameError, AttributeError ):
1392 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001393 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001394 routeData = main.multicastConfig[ routeName ]
1395 srcs = main.mcastRoutes[ routeName ][ "src" ]
1396 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1397 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1398 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001399 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001400 for src in srcs:
1401 srcEntry = routeData[ "src" ][ src ]
1402 for dst in dsts:
1403 dstEntry = routeData[ "dst" ][ dst ]
1404 sender = getattr( main, srcEntry[ "host" ] )
1405 receiver = getattr( main, dstEntry[ "host" ] )
1406 main.Network.addRoute( str( srcEntry[ "host" ] ),
1407 str( routeData[ "group" ] ),
1408 str( srcEntry[ "interface" ] ),
1409 True if routeData[ "ipVersion" ] == 6 else False )
1410 # Build the packet
1411 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1412 if routeData[ "ipVersion" ] == 4:
1413 sender.buildIP( dst=str( routeData[ "group" ] ) )
1414 elif routeData[ "ipVersion" ] == 6:
1415 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1416 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1417 sIface = srcEntry[ "interface" ]
1418 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1419 pktFilter = srcEntry[ "filter" ]
1420 pkt = srcEntry[ "packet" ]
1421 # Send packet and check received packet
1422 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001423 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001424 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001425 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1426 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001427 if not trafficResult:
1428 result = main.FALSE
1429 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1430 dstEntry[ "host" ] ) )
1431 utilities.assert_equals( expect=main.TRUE,
1432 actual=result,
1433 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1434 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001435 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001436 Testcaselib.saveOnosDiagnostics( main )
1437 Testcaselib.cleanup( main, copyKarafLog=False )
1438 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001439
1440 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001441 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001442 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1443 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001444 """
1445 Verify reachability from each host in srcList to each host in dstList
1446 """
1447 from tests.dependencies.topology import Topology
1448 try:
1449 main.topo
1450 except ( NameError, AttributeError ):
1451 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001452 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001453 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001454 utilities.assert_equals( expect=main.TRUE,
1455 actual=pingResult,
1456 onpass="{}: Pass".format( stepMsg ),
1457 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001458 if not pingResult and skipOnFail:
1459 Testcaselib.saveOnosDiagnostics( main )
1460 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1461 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001462
1463 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001464 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001465 """
1466 Verify if the specified host is discovered by ONOS on the given locations
1467 Required:
You Wang85747762018-05-11 15:51:50 -07001468 locationDict: a dictionary that maps host names to expected locations.
1469 locations could be a string or a list.
1470 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001471 Returns:
1472 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1473 """
You Wang85747762018-05-11 15:51:50 -07001474 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1475 result = main.TRUE
1476 for hostName, locations in locationDict.items():
1477 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1478 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1479 if not hostIp:
1480 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1481 if not hostIp:
1482 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1483 result = main.FALSE
1484 continue
1485 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1486 main.FALSE,
1487 args=( hostIp, locations ),
1488 attempts=retry + 1,
1489 sleep=10 )
1490 if not locationResult:
1491 result = main.FALSE
1492 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001493 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001494 onpass="Location verification passed",
1495 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001496
1497 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001498 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001499 """
1500 Move specified host from srcSw to dstSw.
1501 If srcSw and dstSw are same, the host will be moved from current port to
1502 next available port.
1503 Required:
1504 hostName: name of the host. e.g., "h1"
1505 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1506 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1507 gw: ip address of the gateway of the new location
1508 Optional:
1509 macAddr: if specified, change MAC address of the host to the specified MAC address.
1510 prefixLen: prefix length
1511 cfg: port configuration as JSON string
1512 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001513 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001514 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001515 if not hasattr( main, 'Mininet1' ):
1516 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1517 return
1518
You Wang6e5b48e2018-07-23 16:17:38 -07001519 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1520 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1521 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001522 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001523 if cfg:
1524 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1525 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001526 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001527 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001528 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001529
1530 main.Mininet1.discoverHosts( [ hostName, ] )
1531
1532 # Update expectedHost when MAC address is changed.
1533 if macAddr is not None:
1534 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1535 if ipAddr is not None:
1536 for hostName, ip in main.expectedHosts[ "onos" ].items():
1537 if ip == ipAddr:
1538 vlan = hostName.split( "/" )[ -1 ]
1539 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001540 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001541 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001542
1543 @staticmethod
1544 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001545 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001546 """
1547 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1548 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1549 to next available port.
1550 Required:
1551 hostName: name of the host. e.g., "h1"
1552 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1553 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1554 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1555 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1556 gw: ip address of the gateway of the new location
1557 Optional:
1558 macAddr: if specified, change MAC address of the host to the specified MAC address.
1559 prefixLen: prefix length
1560 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001561 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001562 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001563 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001564 if not hasattr( main, 'Mininet1' ):
1565 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1566 return
1567
You Wang6e5b48e2018-07-23 16:17:38 -07001568 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1569 srcSw, srcPairSw, dstSw, dstPairSw ) )
1570 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1571 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1572 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001573 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001574 if cfg:
1575 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1576 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001577 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001578 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001579 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001580
1581 main.Mininet1.discoverHosts( [ hostName, ] )
1582
1583 # Update expectedHost when MAC address is changed.
1584 if macAddr is not None:
1585 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1586 if ipAddr is not None:
1587 for hostName, ip in main.expectedHosts[ "onos" ].items():
1588 if ip == ipAddr:
1589 vlan = hostName.split( "/" )[ -1 ]
1590 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001591 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001592
1593 @staticmethod
1594 def mnDockerSetup( main ):
1595 """
1596 Optionally start and setup docker image for mininet
1597 """
1598 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1599
1600 main.log.info( "Creating Mininet Docker" )
1601 handle = main.Mininet1.handle
Jon Hallf6aeda22020-07-28 09:12:56 -07001602 # build docker image
Jon Hall3c0114c2020-08-11 15:07:42 -07001603 dockerFilePath = "%s/../dependencies/" % main.testDir
1604 dockerName = "trellis_mininet"
1605 # TODO: assert on these docker calls
1606 main.Mininet1.dockerBuild( dockerFilePath, dockerName )
Jon Hallf6aeda22020-07-28 09:12:56 -07001607
Jon Hall43060f62020-06-23 13:13:33 -07001608 confDir = "/tmp/mn_conf/"
1609 # Try to ensure the destination exists
1610 main.log.info( "Create folder for network config files" )
1611 handle.sendline( "mkdir -p %s" % confDir )
Jon Hall3c0114c2020-08-11 15:07:42 -07001612 handle.expect( main.Mininet1.Prompt() )
Jon Hall43060f62020-06-23 13:13:33 -07001613 main.log.debug( handle.before + handle.after )
1614 # Make sure permissions are correct
1615 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
Jon Hall3c0114c2020-08-11 15:07:42 -07001616 handle.expect( main.Mininet1.Prompt() )
Jon Hall43060f62020-06-23 13:13:33 -07001617 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
Jon Hall3c0114c2020-08-11 15:07:42 -07001618 handle.expect( main.Mininet1.Prompt() )
Jon Hall43060f62020-06-23 13:13:33 -07001619 main.log.debug( handle.before + handle.after )
Jon Hallcc166702020-07-30 11:42:22 -07001620 # Stop any leftover container
Jon Hall3c0114c2020-08-11 15:07:42 -07001621 main.Mininet1.dockerStop( dockerName )
Jon Hall43060f62020-06-23 13:13:33 -07001622 # Start docker container
Jon Hall3c0114c2020-08-11 15:07:42 -07001623 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1624 dockerName,
1625 main.params[ 'MN_DOCKER' ][ 'args' ] )
1626 if runResponse == main.FALSE:
Jon Hallf6aeda22020-07-28 09:12:56 -07001627 main.log.error( "Docker container already running, aborting test" )
1628 main.cleanup()
1629 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001630
Jon Hall3c0114c2020-08-11 15:07:42 -07001631 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
Jon Hall43060f62020-06-23 13:13:33 -07001632 main.Mininet1.sudoRequired = False
1633
1634 # Fow when we create component handles
1635 main.Mininet1.mExecDir = "/tmp"
1636 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1637 main.Mininet1.hostPrompt = "/home/root#"
1638
1639 @staticmethod
1640 def mnDockerTeardown( main ):
1641 """
1642 Optionally stop and cleanup docker image for mininet
1643 """
1644
1645 if hasattr( main, 'Mininet1' ):
1646 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001647 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001648
1649 # Detach from container
1650 handle = main.Mininet1.handle
1651 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001652 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001653 main.Mininet1.sudoRequired = True
1654 except Exception as e:
1655 main.log.error( e )
1656
1657 @staticmethod
1658 def setOnosConfig( main ):
1659 """
1660 Read and Set onos configurations from the params file
1661 """
1662 main.step( "Set ONOS configurations" )
1663 config = main.params.get( 'ONOS_Configuration' )
1664 if config:
1665 main.log.debug( config )
1666 checkResult = main.TRUE
1667 for component in config:
1668 for setting in config[ component ]:
1669 value = config[ component ][ setting ]
1670 check = main.Cluster.next().setCfg( component, setting, value )
1671 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1672 checkResult = check and checkResult
1673 utilities.assert_equals( expect=main.TRUE,
1674 actual=checkResult,
1675 onpass="Successfully set config",
1676 onfail="Failed to set config" )
1677 else:
1678 main.log.warn( "No configurations were specified to be changed after startup" )
1679
1680 @staticmethod
1681 def setOnosLogLevels( main ):
1682 """
1683 Read and Set onos log levels from the params file
1684 """
1685 main.step( 'Set logging levels' )
1686 logging = True
1687 try:
1688 logs = main.params.get( 'ONOS_Logging', False )
1689 if logs:
1690 for namespace, level in logs.items():
1691 for ctrl in main.Cluster.active():
1692 ctrl.CLI.logSet( level, namespace )
1693 except AttributeError:
1694 logging = False
1695 utilities.assert_equals( expect=True, actual=logging,
1696 onpass="Set log levels",
1697 onfail="Failed to set log levels" )