blob: dd2b8709c37c7cff6316c9baafe1060fa1062fd4 [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 Hall43060f62020-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 Hall43060f62020-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 Hallbc1c1c92020-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 Halldac3eae2020-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' ] )
You Wang5bf49592020-07-08 18:47:46 -070088 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ]
89 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070090
Devin Lim0c972b72018-02-08 14:53:59 -080091 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070092 except Exception as e:
93 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070094
Devin Lim58046fa2017-07-05 16:55:00 -070095 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070096
Jon Hall1efcb3f2016-08-23 13:42:15 -070097 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080098 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
99 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700100 """
101 - Set up cell
102 - Create cell file
103 - Set cell file
104 - Verify cell file
105 - Kill ONOS process
106 - Uninstall ONOS cluster
107 - Verify ONOS start up
108 - Install ONOS cluster
109 - Connect to cli
110 """
111 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700112 try:
113 if main.params.get( 'EXTERNAL_APPS' ):
114 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
115 main.log.info( "Downloading %s app from %s" )
116 main.ONOSbench.onosFetchApp( url )
117 if not main.apps:
118 main.log.error( "App list is empty" )
119 except Exception as e:
120 main.log.debug( e )
121 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800122 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
123 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700124 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800125 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800126 skipPack=skipPackage,
127 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800128 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700129 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700130 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800131 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700132 attempts=10 )
133 if ready:
134 ready = main.TRUE
135 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700136 onpass="ONOS summary command succeded",
137 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700138 if not ready:
139 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700140 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700141
You Wang5bf49592020-07-08 18:47:46 -0700142 # Install segmentrouting and t3 app
143 appInstallResult = main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
144 if main.t3Oar:
145 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
146 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
147 onpass="SR app installation succeded",
148 onfail="SR app installation failed" )
149 if not appInstallResult:
150 main.cleanAndExit()
151
Jon Hall43060f62020-06-23 13:13:33 -0700152 # FIXME: move to somewhere else?
153 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
154 # TODO: Support other pipeconfs/making this configurable
155 if switchPrefix == "tofino":
156 # It seems to take some time for the pipeconfs to be loaded
157 ctrl = main.Cluster.next()
158 for i in range( 120 ):
159 try:
160 main.log.debug( "Checking to see if pipeconfs are loaded" )
161 output = ctrl.CLI.sendline( "pipeconfs" )
162 if "tofino" in output:
163 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
164 break
165 time.sleep( 1 )
166 except Exception as e:
167 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700168
Jon Hall43060f62020-06-23 13:13:33 -0700169 Testcaselib.setOnosLogLevels( main )
170 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700171
Jon Hall1efcb3f2016-08-23 13:42:15 -0700172 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800173 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700174 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
175 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800176
177 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700178 def loadJson( main, suffix='' ):
179 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
180 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800181 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
182
183 @staticmethod
184 def loadChart( main ):
185 try:
186 with open( "%s%s.chart" % ( main.configPath + main.forChart,
187 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700188 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800189 except IOError:
190 main.log.warn( "No chart file found." )
191
192 @staticmethod
193 def loadHost( main ):
194 with open( "%s%s.host" % ( main.configPath + main.forHost,
195 main.cfgName ) ) as host:
196 main.expectedHosts = json.load( host )
197
198 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800199 def loadSwitchFailureChart( main ):
200 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
201 main.cfgName ) ) as sfc:
202 main.switchFailureChart = json.load( sfc )
203
204 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800205 def loadLinkFailureChart( main ):
206 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700207 main.cfgName ) ) as lfc:
208 main.linkFailureChart = json.load( lfc )
209
210 @staticmethod
211 def loadMulticastConfig( main ):
212 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
213 main.cfgName ) ) as cfg:
214 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800215
216 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700217 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700218 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800219 copyResult = main.ONOSbench.scp( main.Mininet1,
220 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700221 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800222 direction="to" )
223 if main.topologyLib:
224 for lib in main.topologyLib.split(","):
225 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
226 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700227 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800228 direction="to" )
229 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700230 import re
231 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
232 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700233 destDir = "~/"
234 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
235 destDir = "/tmp/mn_conf/"
236 # Try to ensure the destination exists
237 main.log.info( "Create folder for network config files" )
238 handle = main.Mininet1.handle
239 handle.sendline( "mkdir -p %s" % destDir )
240 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
241 main.log.debug( handle.before + handle.after )
242 # Make sure permissions are correct
243 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, destDir ) )
244 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
245 main.log.debug( handle.before + handle.after )
246 handle.sendline( "sudo chmod -R a+rwx %s" % ( destDir ) )
247 handle.expect( [ main.Mininet1.prompt, main.Mininet1.dockerPrompt ] )
248 main.log.debug( handle.before + handle.after )
You Wangd87b2312018-01-30 12:47:17 -0800249 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700250 # Update zebra configurations with correct ONOS instance IP
251 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
252 ip = controllerIPs[ index ]
253 index = ( index + 1 ) % len( controllerIPs )
254 with open( main.configPath + main.forConfig + conf ) as f:
255 s = f.read()
256 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
257 with open( main.configPath + main.forConfig + conf, "w" ) as f:
258 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800259 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800260 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700261 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800262 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800263 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700264 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800265 main.Mininet1.home + "custom",
266 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800267 stepResult = copyResult
268 utilities.assert_equals( expect=main.TRUE,
269 actual=stepResult,
270 onpass="Successfully copied topo files",
271 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700272 if main.stratumRoot:
273 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
274 main.Mininet1.handle.expect( main.Mininet1.prompt )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700275 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700276 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700277 main.topology = topology
278 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700279 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700280 stepResult = topoResult
281 utilities.assert_equals( expect=main.TRUE,
282 actual=stepResult,
283 onpass="Successfully loaded topology",
284 onfail="Failed to load topology" )
285 # Exit if topology did not load properly
286 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700287 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700288 if main.useBmv2:
289 # Upload the net-cfg file created for each switch
290 filename = "onos-netcfg.json"
291 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
292 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
293 path = "/tmp/mn-stratum/%s/" % switch
294 dstPath = "/tmp/"
295 dstFileName = "%s-onos-netcfg.json" % switch
296 main.ONOSbench1.scp( main.Mininet1,
297 "%s%s" % ( path, filename ),
298 "%s%s" % ( dstPath, dstFileName ),
299 "from" )
300 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
301 # Configure managementAddress
302 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
303 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
304 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
305 # Configure device id
306 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
307 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
308 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
309 # Configure device name
310 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s\",' %s%s" % ( switch, dstPath, dstFileName ) )
311 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
312 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
313 main.ONOSbench1.onosNetCfg( main.ONOSserver1.ip_address, dstPath, dstFileName )
314 # Make sure hosts make some noise
315 Testcaselib.discoverHosts( main )
316
317 @staticmethod
318 def discoverHosts( main ):
319 # TODO add option to only select specific hosts
320 if hasattr( main, "Mininet1" ):
321 network = main.Mininet1
322 elif hasattr( main, "NetworkBench" ):
323 network = main.NetworkBench
324 else:
325 main.log.warn( "Could not find component for test network, skipping host discovery" )
326 return
327 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700328
329 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700330 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800331 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700332 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800333 topoResult = main.NetworkBench.connectToNet()
334 stepResult = topoResult
335 utilities.assert_equals( expect=main.TRUE,
336 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700337 onpass="Successfully connected to topology",
338 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800339 # Exit if topology did not load properly
340 if not topoResult:
341 main.cleanAndExit()
342
Jon Hall43060f62020-06-23 13:13:33 -0700343 # Perform any optional setup
344 for switch in main.NetworkBench.switches:
345 if hasattr( switch, "setup" ):
346 switch.setup() # We might not need this
347
You Wang84f981d2018-01-12 16:11:50 -0800348 main.step( "Assign switches to controllers." )
Jon Hall43060f62020-06-23 13:13:33 -0700349 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700350 switches = main.NetworkBench.getSwitches()
351 pool = []
352 for name in switches.keys():
Jon Hall43060f62020-06-23 13:13:33 -0700353 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
354 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700355 thread = main.Thread( target=main.NetworkBench.assignSwController,
356 name="assignSwitchToController",
357 args=[ name, main.Cluster.getIps(), '6653' ] )
358 pool.append( thread )
359 thread.start()
360 for thread in pool:
361 thread.join( 300 )
362 if not thread.result:
363 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800364 utilities.assert_equals( expect=main.TRUE,
365 actual=stepResult,
366 onpass="Successfully assign switches to controllers",
367 onfail="Failed to assign switches to controllers" )
368
You Wang4cc61912018-08-28 10:10:58 -0700369 # Check devices
370 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700371 # Connecting to hosts that only have data plane connectivity
372 main.step( "Connecting inband hosts" )
373 stepResult = main.Network.connectInbandHosts()
374 utilities.assert_equals( expect=main.TRUE,
375 actual=stepResult,
376 onpass="Successfully connected inband hosts",
377 onfail="Failed to connect inband hosts" )
Jon Hall43060f62020-06-23 13:13:33 -0700378 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700379
You Wang84f981d2018-01-12 16:11:50 -0800380 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700381 def saveOnosDiagnostics( main ):
382 """
383 Get onos-diags.tar.gz and save it to the log directory.
384 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
385 """
386 main.log.info( "Collecting onos-diags..." )
387 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
388 main.logdir,
389 "-CASE%d" % main.CurrentTestCaseNumber )
390
391 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700392 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700393 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700394
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700395 main.failures = int( main.params[ 'failures' ] )
396 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700397
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700398 if main.cfgName == '2x2':
399 spine = {}
400 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
401 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
402 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700403
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700404 spine = {}
405 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
406 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
407 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700408
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700409 elif main.cfgName == '4x4':
410 spine = {}
411 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
412 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
413 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700414
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700415 spine = {}
416 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
417 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
418 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700419
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700420 spine = {}
421 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
422 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
423 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700424
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700425 spine = {}
426 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
427 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
428 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700429
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700430 else:
Piera2a7e1b2016-10-04 11:51:43 -0700431 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700432 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800433
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800434 @staticmethod
435 def addStaticOnosRoute( main, subnet, intf):
436 """
437 Adds an ONOS static route with the use route-add command.
438 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800439 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
440
Piera2a7e1b2016-10-04 11:51:43 -0700441 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700442 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700443 """
444 Check number of groups for each subnet on device deviceId and matches
445 it with an expected value. subnetDict is a dictionarty containing values
446 of the type "10.0.1.0/24" : 5.
447 """
You Wangc02f3be2018-05-18 12:14:23 -0700448 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
449 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
450 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700451
You Wangc02f3be2018-05-18 12:14:23 -0700452 result = main.TRUE
453 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700454 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700455 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700456 # this will match the group id that this flow entry points to, for example :
457 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700458 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700459 count = 0
460 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700461 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700462 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700463 if count - 1 != numberInSelect:
464 result = main.FALSE
465 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 ) )
466 utilities.assert_equals( expect=main.TRUE, actual=result,
467 onpass="All bucket numbers are as expected",
468 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700469
470 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900471 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700472 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800473 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900474 if tag == "":
475 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700476 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700477 main.FALSE,
478 kwargs={ 'min': minFlowCount },
479 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800480 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800481 if count == main.FALSE:
482 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700483 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700484 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800485 actual=( count > minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700486 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
487 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700488
489 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700490 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700491 main.FALSE,
492 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800493 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800494 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700495 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700496 expect=main.TRUE,
497 actual=flowCheck,
498 onpass="Flow status is correct!",
499 onfail="Flow status is wrong!" )
500 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700501 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700502 "flows",
503 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900504 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700505 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700506 "groups",
507 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900508 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700509
510 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700511 def checkDevices( main, switches, tag="", sleep=10 ):
512 main.step(
513 "Check whether the switches count is equal to %s" % switches )
514 if tag == "":
515 tag = 'CASE%d' % main.CurrentTestCaseNumber
516 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
517 main.FALSE,
518 kwargs={ 'numoswitch': switches},
519 attempts=10,
520 sleep=sleep )
521 utilities.assert_equals( expect=main.TRUE, actual=result,
522 onpass="Device up successful",
523 onfail="Failed to boot up devices?" )
524
525 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800526 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
527 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700528 "Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800529 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
530 main.FALSE,
531 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800532 attempts=5,
533 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800534 if count == main.FALSE:
535 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800536 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800537 expect=True,
538 actual=( count > minFlowCount ),
539 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800540 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800541
542 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700543 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800544 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700545 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800546 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
547 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700548 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800549 attempts=5,
550 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800551 if count == main.FALSE:
552 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800553 utilities.assertEquals(
554 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800555 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700556 onpass="Flow count looks correct: " + str( count ) ,
557 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800558
559 @staticmethod
560 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
561 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700562 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800563 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
564 main.FALSE,
565 args=( dpid, groupCount, False, 1),
566 attempts=5,
567 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800568 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800569 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800570 utilities.assertEquals(
571 expect=True,
572 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700573 onpass="Group count looks correct: " + str( count ) ,
574 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800575
576 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700577 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800578
579 for dpid, values in main.count.items():
580 flowCount = values["flows"]
581 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700582 main.log.report( "Check flow count for dpid " + str( dpid ) +
583 ", should be " + str( flowCount ) )
584 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800585
Jon Hall9677ed32018-04-24 11:16:23 -0700586 main.log.report( "Check group count for dpid " + str( dpid ) +
587 ", should be " + str( groupCount ) )
588 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800589
590 return
591
592 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700593 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
594 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800595 '''
You Wangba231e72018-03-01 13:18:21 -0800596 Verify connectivity between hosts according to the ping chart
597 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800598 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800599 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800600 '''
You Wangba231e72018-03-01 13:18:21 -0800601 main.log.report( "Check host connectivity" )
602 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800603 if tag == "":
604 tag = 'CASE%d' % main.CurrentTestCaseNumber
605 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800606 main.log.debug( "Entry in ping chart: %s" % entry )
607 expect = entry[ 'expect' ]
608 if expect == "Unidirectional":
609 # Verify ping from each src host to each dst host
610 src = entry[ 'src' ]
611 dst = entry[ 'dst' ]
612 expect = main.TRUE
613 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
614 if basedOnIp:
615 if ("v4" in src[0]):
616 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
617 utilities.assert_equals( expect=expect, actual=pa,
618 onpass="IPv4 connectivity successfully tested",
619 onfail="IPv4 connectivity failed" )
620 if ("v6" in src[0]):
621 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
622 utilities.assert_equals( expect=expect, actual=pa,
623 onpass="IPv6 connectivity successfully tested",
624 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700625 elif main.physicalNet:
626 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
627 utilities.assert_equals( expect=expect, actual=pa,
628 onpass="IP connectivity successfully tested",
629 onfail="IP connectivity failed" )
630
You Wangba231e72018-03-01 13:18:21 -0800631 else:
632 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
633 utilities.assert_equals( expect=expect, actual=pa,
634 onpass="IP connectivity successfully tested",
635 onfail="IP connectivity failed" )
636 else:
637 # Verify ping between each host pair
638 hosts = entry[ 'hosts' ]
639 try:
640 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
641 except:
642 expect = main.FALSE
643 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
644 if basedOnIp:
645 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800646 pa = utilities.retry( main.Network.pingallHosts,
647 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700648 args=(hosts, ),
649 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800650 attempts=retryAttempts,
651 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800652 utilities.assert_equals( expect=expect, actual=pa,
653 onpass="IPv4 connectivity successfully tested",
654 onfail="IPv4 connectivity failed" )
655 if ("v6" in hosts[0]):
656 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
657 utilities.assert_equals( expect=expect, actual=pa,
658 onpass="IPv6 connectivity successfully tested",
659 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700660 elif main.physicalNet:
661 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
662 utilities.assert_equals( expect=expect, actual=pa,
663 onpass="IP connectivity successfully tested",
664 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800665 else:
You Wangf19d9f42018-02-23 16:34:19 -0800666 pa = main.Network.pingallHosts( hosts )
667 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800668 onpass="IP connectivity successfully tested",
669 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700670 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700671 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700672 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700673 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700674 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800675
676 if dumpflows:
677 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
678 "flows",
679 main.logdir,
680 tag + "_FlowsOn" )
681 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
682 "groups",
683 main.logdir,
684 tag + "_GroupsOn" )
685
686 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700687 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700688 """
689 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
690 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
691 Kill a link and verify ONOS can see the proper link change
692 """
Jon Halla604fd42018-05-04 14:27:27 -0700693 if sleep is None:
694 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
695 else:
696 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700697 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700698 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
699 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
700 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700701 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700702 "Waiting %s seconds for link down to be discovered" % sleep )
703 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700704 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700705 main.FALSE,
706 kwargs={ 'numoswitch': switches,
707 'numolink': links },
708 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700709 sleep=sleep )
710 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700711 utilities.assert_equals( expect=main.TRUE, actual=result,
712 onpass="Link down successful",
713 onfail="Failed to turn off link?" )
714
715 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700716 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800717 """
718 links = list of links (src, dst) to bring down.
719 """
720
721 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700722 if sleep is None:
723 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
724 else:
725 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800726
727 for end1, end2 in links:
728 main.Network.link( END1=end1, END2=end2, OPTION="down")
729 main.Network.link( END1=end2, END2=end1, OPTION="down")
730
Jon Halla604fd42018-05-04 14:27:27 -0700731 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800732 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700733 "Waiting %s seconds for links down to be discovered" % sleep )
734 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800735
736 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
737 main.FALSE,
738 kwargs={ 'numoswitch': switches,
739 'numolink': linksAfter },
740 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700741 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800742
You Wang2854bce2018-03-30 10:15:32 -0700743 utilities.assert_equals( expect=main.TRUE, actual=topology,
744 onpass="Link batch down successful",
745 onfail="Link batch down failed" )
746
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800747 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700748 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800749 """
750 links = list of link (src, dst) to bring up again.
751 """
752
753 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700754 if sleep is None:
755 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
756 else:
757 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800758
759 for end1, end2 in links:
760 main.Network.link( END1=end1, END2=end2, OPTION="up")
761 main.Network.link( END1=end2, END2=end1, OPTION="up")
762
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800763 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700764 "Waiting %s seconds for links up to be discovered" % sleep )
765 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800766
767 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
768 main.FALSE,
769 kwargs={ 'numoswitch': switches,
770 'numolink': linksAfter },
771 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700772 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800773
You Wang2854bce2018-03-30 10:15:32 -0700774 utilities.assert_equals( expect=main.TRUE, actual=topology,
775 onpass="Link batch up successful",
776 onfail="Link batch up failed" )
777
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800778 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700779 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
780 """
781 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
782 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
783 switches, links: number of expected switches and links after link change, ex.: '4', '6'
784 """
785 if sleep is None:
786 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
787 else:
788 sleep = float( sleep )
789 main.step( "Disable a batch of ports" )
790 for dpid, port in ports:
791 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
792 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
793 time.sleep( sleep )
794 if switches and links:
795 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
796 numolink=links )
797 utilities.assert_equals( expect=main.TRUE, actual=result,
798 onpass="Port down successful",
799 onfail="Port down failed" )
800
801 @staticmethod
802 def enablePortBatch( main, ports, switches, links, sleep=None ):
803 """
804 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
805 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
806 switches, links: number of expected switches and links after link change, ex.: '4', '6'
807 """
808 if sleep is None:
809 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
810 else:
811 sleep = float( sleep )
812 main.step( "Enable a batch of ports" )
813 for dpid, port in ports:
814 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
815 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
816 time.sleep( sleep )
817 if switches and links:
818 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
819 numolink=links )
820 utilities.assert_equals( expect=main.TRUE, actual=result,
821 onpass="Port up successful",
822 onfail="Port up failed" )
823
824 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700825 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700826 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700827 """
828 Params:
829 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700830 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700831 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
832 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
833 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
834 Kill a link and verify ONOS can see the proper link change
835 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700836 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700837 if sleep is None:
838 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
839 else:
840 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700841 result = False
842 count = 0
843 while True:
844 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700845 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800846 main.Network.link( END1=end1, END2=end2, OPTION="up" )
847 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700848 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700849 "Waiting %s seconds for link up to be discovered" % sleep )
850 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700851
You Wangc02d8352018-04-17 16:42:10 -0700852 if portUp:
853 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
854 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700855 main.log.info(
856 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700857 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700858
Jon Halla604fd42018-05-04 14:27:27 -0700859 result = ctrl.CLI.checkStatus( numoswitch=switches,
860 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700861 if count > 5 or result:
862 break
863 utilities.assert_equals( expect=main.TRUE, actual=result,
864 onpass="Link up successful",
865 onfail="Failed to bring link up" )
866
867 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700868 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700869 """
870 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
871 Completely kill a switch and verify ONOS can see the proper change
872 """
Jon Halla604fd42018-05-04 14:27:27 -0700873 if sleep is None:
874 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
875 else:
876 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700877 switch = switch if isinstance( switch, list ) else [ switch ]
878 main.step( "Kill " + str( switch ) )
879 for s in switch:
880 main.log.info( "Stopping " + s )
881 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700882 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700883
884 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700885 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700886 sleep ) )
887 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700888 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700889 main.FALSE,
890 kwargs={ 'numoswitch': switches,
891 'numolink': links },
892 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700893 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700894 utilities.assert_equals( expect=main.TRUE, actual=topology,
895 onpass="Kill switch successful",
896 onfail="Failed to kill switch?" )
897
898 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700899 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700900 """
901 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
902 Recover a switch and verify ONOS can see the proper change
903 """
Jon Halla604fd42018-05-04 14:27:27 -0700904 if sleep is None:
905 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
906 else:
907 sleep = float( sleep )
908 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700909 switch = switch if isinstance( switch, list ) else [ switch ]
910 main.step( "Recovering " + str( switch ) )
911 for s in switch:
912 main.log.info( "Starting " + s )
913 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700914 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700915 sleep ) )
916 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700917 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700918 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700919 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700920 sleep ) )
921 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700922
Devin Lim142b5342017-07-20 15:22:39 -0700923 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700924 main.FALSE,
925 kwargs={ 'numoswitch': switches,
926 'numolink': links },
927 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700928 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700929 utilities.assert_equals( expect=main.TRUE, actual=topology,
930 onpass="Switch recovery successful",
931 onfail="Failed to recover switch?" )
932
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700933 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700934 def killRouter( main, router, sleep=None ):
935 """
936 Kill bgpd process on a quagga router
937 router: name of the router to be killed. E.g. "bgp1"
938 """
939 sleep = float( sleep )
940 main.step( "Kill " + str( router ) )
941 if hasattr( main, 'Mininet1' ):
942 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
943 main.Mininet1.handle.expect( "mininet>" )
944 else:
945 # TODO: support killing router in physical network
946 pass
947 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
948 time.sleep( sleep )
949
950 @staticmethod
951 def recoverRouter( main, router, sleep=None ):
952 """
953 Restart bgpd process on a quagga router
954 router: name of the router to be recovered. E.g. "bgp1"
955 """
956 sleep = float( sleep )
957 main.step( "Recovering " + str( router ) )
958 if hasattr( main, 'Mininet1' ):
959 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
960 main.Mininet1.handle.expect( "mininet>" )
961 else:
962 # TODO: support recovering router in physical network
963 pass
964 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
965 time.sleep( sleep )
966
967 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700968 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700969 """
970 Stop Onos-cluster.
971 Stops Mininet
972 Copies ONOS log
973 """
You Wang4cc61912018-08-28 10:10:58 -0700974 from tests.dependencies.utils import Utils
975 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -0700976 for ctrl in main.Cluster.active():
977 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -0700978 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700979 if hasattr( main, "scapyHosts" ):
980 scapyResult = main.TRUE
981 for host in main.scapyHosts:
982 scapyResult = host.stopScapy() and scapyResult
983 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
984 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700985 if hasattr( main, 'Mininet1' ):
986 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
987 else:
988 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700989 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
990 main.scapyHosts = []
991
You Wang5da39c82018-04-26 22:55:08 -0700992 if removeHostComponent:
993 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
994 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700995 if hasattr( main, 'Mininet1' ):
996 pass
997 else:
998 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700999 main.Network.removeHostComponent( host )
1000
You Wang5df1c6d2018-04-06 18:02:02 -07001001 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001002 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001003 else:
1004 main.Network.disconnectInbandHosts()
1005 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001006
You Wang5df1c6d2018-04-06 18:02:02 -07001007 if copyKarafLog:
1008 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001009
Devin Lim142b5342017-07-20 15:22:39 -07001010 for ctrl in main.Cluster.active():
1011 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001012 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001013
1014 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001015 def verifyNodes( main ):
1016 """
1017 Verifies Each active node in the cluster has an accurate view of other node's and their status
1018
1019 Params:
1020 nodes, integer array with position of the ONOS nodes in the CLIs array
1021 """
1022 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1023 False,
1024 attempts=10,
1025 sleep=10 )
1026 utilities.assert_equals( expect=True, actual=nodeResults,
1027 onpass="Nodes check successful",
1028 onfail="Nodes check NOT successful" )
1029
1030 if not nodeResults:
1031 for ctrl in main.Cluster.runningNodes:
1032 main.log.debug( "{} components not ACTIVE: \n{}".format(
1033 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001034 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001035 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001036 main.cleanAndExit()
1037
1038 @staticmethod
1039 def verifyTopology( main, switches, links, expNodes ):
1040 """
1041 Verifies that the ONOS cluster has an acuurate view of the topology
1042
1043 Params:
1044 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
1045 """
1046 main.step( "Check number of topology elements" )
1047 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1048 main.FALSE,
1049 kwargs={ 'numoswitch': switches,
1050 'numolink': links,
1051 'numoctrl': expNodes },
1052 attempts=10,
1053 sleep=12 )
1054 utilities.assert_equals( expect=main.TRUE, actual=topology,
1055 onpass="Number of topology elements are correct",
1056 onfail="Unexpected number of links, switches, and/or controllers" )
1057
1058 @staticmethod
1059 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001060 """
1061 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1062 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1063 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1064 """
Jon Halla604fd42018-05-04 14:27:27 -07001065 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001066 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001067 if sleep is None:
1068 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1069 else:
1070 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001071
Jon Hall1efcb3f2016-08-23 13:42:15 -07001072 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001073 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001074 utilities.assert_equals( expect=main.TRUE, actual=killResult,
1075 onpass="ONOS instance Killed",
1076 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -07001077 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -07001078 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001079 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001080 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001081
Devin Lim142b5342017-07-20 15:22:39 -07001082 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001083 Testcaselib.verifyNodes( main )
1084 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001085
1086 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001087 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001088 """
1089 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1090 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1091 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1092 """
Jon Hall3c910162018-03-07 14:42:16 -08001093 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001094 if sleep is None:
1095 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1096 else:
1097 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001098 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Hall43060f62020-06-23 13:13:33 -07001099 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001100 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001101 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -07001102 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001103 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1104 onpass="ONOS service is ready",
1105 onfail="ONOS service did not start properly" )
1106 for i in nodes:
1107 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001108 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001109 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001110 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1111 commandlineTimeout=60,
1112 onosStartTimeout=100 )
1113 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001114 utilities.assert_equals( expect=main.TRUE,
1115 actual=cliResult,
1116 onpass="ONOS CLI is ready",
1117 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001118
Jon Halla604fd42018-05-04 14:27:27 -07001119 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001120 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001121 Testcaselib.verifyNodes( main )
1122 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001123
Devin Lim142b5342017-07-20 15:22:39 -07001124 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001125 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001126 attempts=10,
1127 sleep=12 )
1128 if ready:
1129 ready = main.TRUE
1130 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001131 onpass="ONOS summary command succeded",
1132 onfail="ONOS summary command failed" )
1133 if not ready:
1134 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001135 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001136
1137 @staticmethod
1138 def addHostCfg( main ):
1139 """
1140 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001141 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001142 """
1143 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001144 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001145 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001146 hostCfg = json.load( template )
1147 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1148 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001149 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001150 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1151 subjectClass="hosts",
1152 subjectKey=urllib.quote( mac,
1153 safe='' ),
1154 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001155 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1156 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001157 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001158 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1159 subjectClass="hosts",
1160 subjectKey=urllib.quote( mac,
1161 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001162 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001163 main.pingChart.update( { 'vlan1': { "expect": "True",
1164 "hosts": [ "olt1", "vsg1" ] } } )
1165 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1166 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001167 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001168 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001169 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1170 subjectClass="apps",
1171 subjectKey="org.onosproject.segmentrouting",
1172 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001173
1174 @staticmethod
1175 def delHostCfg( main ):
1176 """
1177 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001178 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001179 """
1180 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001181 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001182 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001183 hostCfg = json.load( template )
1184 main.step( "Removing host configuration" )
1185 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001186 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001187 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1188 subjectKey=urllib.quote(
1189 mac,
1190 safe='' ),
1191 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001192 main.step( "Removing configuration" )
1193 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001194 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001195 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1196 subjectKey=urllib.quote(
1197 mac,
1198 safe='' ),
1199 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001200 main.step( "Removing vlan configuration" )
1201 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001202 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1203 subjectKey="org.onosproject.segmentrouting",
1204 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001205
1206 @staticmethod
1207 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1208 """
1209 Verifies IP address assignment from the hosts
1210 """
1211 main.step( "Verify IP address assignment from hosts" )
1212 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001213 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001214 # Find out names of disconnected hosts
1215 disconnectedHosts = []
1216 if hasattr( main, "disconnectedIpv4Hosts" ):
1217 for host in main.disconnectedIpv4Hosts:
1218 disconnectedHosts.append( host )
1219 if hasattr( main, "disconnectedIpv6Hosts" ):
1220 for host in main.disconnectedIpv6Hosts:
1221 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001222 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001223 # Exclude disconnected hosts
1224 if hostName in disconnectedHosts:
1225 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1226 continue
You Wang53dba1e2018-02-02 17:45:44 -08001227 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1228 main.FALSE,
1229 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001230 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001231 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001232 attempts=attempts,
1233 sleep=sleep )
1234 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1235 onpass="Verify network host IP succeded",
1236 onfail="Verify network host IP failed" )
1237
1238 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001239 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001240 """
1241 Verifies host IP address assignment from ONOS
1242 """
1243 main.step( "Verify host IP address assignment in ONOS" )
1244 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001245 # Find out IPs of disconnected hosts
1246 disconnectedIps = []
1247 if hasattr( main, "disconnectedIpv4Hosts" ):
1248 for host in main.disconnectedIpv4Hosts:
1249 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1250 if hasattr( main, "disconnectedIpv6Hosts" ):
1251 for host in main.disconnectedIpv6Hosts:
1252 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001253 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001254 # Exclude disconnected hosts
1255 if ip in disconnectedIps:
1256 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1257 continue
You Wang53dba1e2018-02-02 17:45:44 -08001258 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1259 main.FALSE,
1260 kwargs={ 'hostList': [ hostName ],
1261 'prefix': ip },
1262 attempts=attempts,
1263 sleep=sleep )
1264 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1265 onpass="Verify ONOS host IP succeded",
1266 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001267 if not ipResult and skipOnFail:
1268 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001269 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001270 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001271
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001272 @staticmethod
1273 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1274 """
1275 Description:
1276 Updates interface configuration in ONOS, with given IP and vlan parameters
1277 Required:
1278 * connectPoint: connect point to update configuration
1279 Optional:
1280 * ips: list of IP addresses, combined with '/xx' subnet representation,
1281 corresponding to 'ips' field in the configuration
1282 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1283 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1284 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1285 """
1286 cfg = dict()
1287 cfg[ "ports" ] = dict()
1288 cfg[ "ports" ][ connectPoint ] = dict()
1289 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1290 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1291 if untagged > 0:
1292 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1293 else:
1294 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1295 if native > 0:
1296 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1297
1298 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001299
1300 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001301 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001302 """
1303 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001304 scapyNames: list of names that will be used as component names for scapy hosts
1305 mininetNames: used when scapy host names are different from the host names
1306 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1307 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001308 """
1309 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001310 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1311 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001312 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001313 if hasattr( main, 'Mininet1' ):
1314 main.Scapy.createHostComponent( scapyName )
1315 scapyHandle = getattr( main, scapyName )
1316 if mininetNames:
1317 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1318 else:
1319 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001320 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1321 scapyHandle.mExecDir = "/tmp"
1322 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1323 main.log.debug( "start mn host component in docker" )
1324 scapyHandle.startHostCli( mininetName,
1325 execDir="/tmp",
1326 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1327 else:
1328 main.log.debug( "start mn host component" )
1329 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001330 else:
You Wang0fc21702018-11-02 17:49:18 -07001331 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001332 scapyHandle = getattr( main, scapyName )
1333 scapyHandle.connectInband()
1334 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001335 scapyHandle.startScapy()
1336 scapyHandle.updateSelf()
1337 main.log.debug( scapyHandle.name )
1338 main.log.debug( scapyHandle.hostIp )
1339 main.log.debug( scapyHandle.hostMac )
1340
1341 @staticmethod
1342 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1343 """
1344 Verify unicast traffic by pinging from source hosts to the destination IP
1345 and capturing the packets at the destination host using Scapy.
1346 srcHosts: List of host names to send the ping packets
1347 dstIp: destination IP of the ping packets
1348 dstHost: host that runs Scapy to capture the packets
1349 dstIntf: name of the interface on the destination host
1350 expect: use True if the ping is expected to be captured at destination;
1351 Otherwise False
1352 skipOnFail: skip the rest of this test case if result is not expected
1353 maxRetry: number of retries allowed
1354 """
1355 from tests.dependencies.topology import Topology
1356 try:
1357 main.topo
1358 except ( NameError, AttributeError ):
1359 main.topo = Topology()
1360 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1361 result = main.TRUE
1362 for srcHost in srcHosts:
1363 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1364 expect, maxRetry, True )
1365 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001366 result = main.FALSE
1367 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1368 utilities.assert_equals( expect=main.TRUE,
1369 actual=result,
1370 onpass="Verify traffic to {}: Pass".format( dstIp ),
1371 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1372 if skipOnFail and result != main.TRUE:
1373 Testcaselib.saveOnosDiagnostics( main )
1374 Testcaselib.cleanup( main, copyKarafLog=False )
1375 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001376
1377 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001378 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001379 """
1380 Verify multicast traffic using scapy
1381 """
You Wangc564c6f2018-05-01 15:24:57 -07001382 from tests.dependencies.topology import Topology
1383 try:
1384 main.topo
1385 except ( NameError, AttributeError ):
1386 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001387 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001388 routeData = main.multicastConfig[ routeName ]
1389 srcs = main.mcastRoutes[ routeName ][ "src" ]
1390 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1391 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1392 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001393 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001394 for src in srcs:
1395 srcEntry = routeData[ "src" ][ src ]
1396 for dst in dsts:
1397 dstEntry = routeData[ "dst" ][ dst ]
1398 sender = getattr( main, srcEntry[ "host" ] )
1399 receiver = getattr( main, dstEntry[ "host" ] )
1400 main.Network.addRoute( str( srcEntry[ "host" ] ),
1401 str( routeData[ "group" ] ),
1402 str( srcEntry[ "interface" ] ),
1403 True if routeData[ "ipVersion" ] == 6 else False )
1404 # Build the packet
1405 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1406 if routeData[ "ipVersion" ] == 4:
1407 sender.buildIP( dst=str( routeData[ "group" ] ) )
1408 elif routeData[ "ipVersion" ] == 6:
1409 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1410 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1411 sIface = srcEntry[ "interface" ]
1412 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1413 pktFilter = srcEntry[ "filter" ]
1414 pkt = srcEntry[ "packet" ]
1415 # Send packet and check received packet
1416 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001417 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001418 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001419 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1420 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001421 if not trafficResult:
1422 result = main.FALSE
1423 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1424 dstEntry[ "host" ] ) )
1425 utilities.assert_equals( expect=main.TRUE,
1426 actual=result,
1427 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1428 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001429 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001430 Testcaselib.saveOnosDiagnostics( main )
1431 Testcaselib.cleanup( main, copyKarafLog=False )
1432 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001433
1434 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001435 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001436 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1437 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001438 """
1439 Verify reachability from each host in srcList to each host in dstList
1440 """
1441 from tests.dependencies.topology import Topology
1442 try:
1443 main.topo
1444 except ( NameError, AttributeError ):
1445 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001446 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001447 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001448 utilities.assert_equals( expect=main.TRUE,
1449 actual=pingResult,
1450 onpass="{}: Pass".format( stepMsg ),
1451 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001452 if not pingResult and skipOnFail:
1453 Testcaselib.saveOnosDiagnostics( main )
1454 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1455 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001456
1457 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001458 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001459 """
1460 Verify if the specified host is discovered by ONOS on the given locations
1461 Required:
You Wang85747762018-05-11 15:51:50 -07001462 locationDict: a dictionary that maps host names to expected locations.
1463 locations could be a string or a list.
1464 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001465 Returns:
1466 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1467 """
You Wang85747762018-05-11 15:51:50 -07001468 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1469 result = main.TRUE
1470 for hostName, locations in locationDict.items():
1471 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1472 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1473 if not hostIp:
1474 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1475 if not hostIp:
1476 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1477 result = main.FALSE
1478 continue
1479 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1480 main.FALSE,
1481 args=( hostIp, locations ),
1482 attempts=retry + 1,
1483 sleep=10 )
1484 if not locationResult:
1485 result = main.FALSE
1486 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001487 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001488 onpass="Location verification passed",
1489 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001490
1491 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001492 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001493 """
1494 Move specified host from srcSw to dstSw.
1495 If srcSw and dstSw are same, the host will be moved from current port to
1496 next available port.
1497 Required:
1498 hostName: name of the host. e.g., "h1"
1499 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1500 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1501 gw: ip address of the gateway of the new location
1502 Optional:
1503 macAddr: if specified, change MAC address of the host to the specified MAC address.
1504 prefixLen: prefix length
1505 cfg: port configuration as JSON string
1506 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001507 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001508 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001509 if not hasattr( main, 'Mininet1' ):
1510 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1511 return
1512
You Wang6e5b48e2018-07-23 16:17:38 -07001513 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1514 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1515 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001516 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001517 if cfg:
1518 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1519 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001520 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001521 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001522 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001523
1524 main.Mininet1.discoverHosts( [ hostName, ] )
1525
1526 # Update expectedHost when MAC address is changed.
1527 if macAddr is not None:
1528 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1529 if ipAddr is not None:
1530 for hostName, ip in main.expectedHosts[ "onos" ].items():
1531 if ip == ipAddr:
1532 vlan = hostName.split( "/" )[ -1 ]
1533 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001534 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001535 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001536
1537 @staticmethod
1538 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001539 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001540 """
1541 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1542 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1543 to next available port.
1544 Required:
1545 hostName: name of the host. e.g., "h1"
1546 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1547 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1548 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1549 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1550 gw: ip address of the gateway of the new location
1551 Optional:
1552 macAddr: if specified, change MAC address of the host to the specified MAC address.
1553 prefixLen: prefix length
1554 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001555 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001556 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001557 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001558 if not hasattr( main, 'Mininet1' ):
1559 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1560 return
1561
You Wang6e5b48e2018-07-23 16:17:38 -07001562 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1563 srcSw, srcPairSw, dstSw, dstPairSw ) )
1564 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1565 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1566 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001567 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001568 if cfg:
1569 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1570 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001571 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001572 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001573 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001574
1575 main.Mininet1.discoverHosts( [ hostName, ] )
1576
1577 # Update expectedHost when MAC address is changed.
1578 if macAddr is not None:
1579 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1580 if ipAddr is not None:
1581 for hostName, ip in main.expectedHosts[ "onos" ].items():
1582 if ip == ipAddr:
1583 vlan = hostName.split( "/" )[ -1 ]
1584 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001585 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001586
1587 @staticmethod
1588 def mnDockerSetup( main ):
1589 """
1590 Optionally start and setup docker image for mininet
1591 """
1592 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1593
1594 main.log.info( "Creating Mininet Docker" )
1595 handle = main.Mininet1.handle
1596 main.Mininet1.dockerPrompt = '#'
1597
1598 confDir = "/tmp/mn_conf/"
1599 # Try to ensure the destination exists
1600 main.log.info( "Create folder for network config files" )
1601 handle.sendline( "mkdir -p %s" % confDir )
1602 handle.expect( main.Mininet1.prompt )
1603 main.log.debug( handle.before + handle.after )
1604 # Make sure permissions are correct
1605 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1606 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1607 handle.expect( main.Mininet1.prompt )
1608 main.log.debug( handle.before + handle.after )
1609 # Start docker container
1610 handle.sendline( "docker run --name trellis_mininet %s %s" % ( main.params[ 'MN_DOCKER' ][ 'args' ], main.params[ 'MN_DOCKER' ][ 'name' ] ) )
1611 handle.expect( main.Mininet1.bashPrompt )
1612 output = handle.before + handle.after
1613 main.log.debug( repr(output) )
1614
1615 handle.sendline( "docker attach trellis_mininet" )
1616 handle.expect( main.Mininet1.dockerPrompt )
1617 main.log.debug( handle.before + handle.after )
1618 handle.sendline( "sysctl -w net.ipv4.ip_forward=0" )
1619 handle.sendline( "sysctl -w net.ipv4.conf.all.forwarding=0" )
1620 handle.expect( main.Mininet1.dockerPrompt )
1621 main.log.debug( handle.before + handle.after )
1622 # We should be good to go
1623 main.Mininet1.prompt = main.Mininet1.dockerPrompt
1624 main.Mininet1.sudoRequired = False
1625
1626 # Fow when we create component handles
1627 main.Mininet1.mExecDir = "/tmp"
1628 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1629 main.Mininet1.hostPrompt = "/home/root#"
1630
1631 @staticmethod
1632 def mnDockerTeardown( main ):
1633 """
1634 Optionally stop and cleanup docker image for mininet
1635 """
1636
1637 if hasattr( main, 'Mininet1' ):
1638 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1639 main.log.info( "Deleting Mininet Docker" )
1640
1641 # Detach from container
1642 handle = main.Mininet1.handle
1643 try:
1644 handle.sendline( "exit" ) # ctrl-p ctrk-q to detach from container
1645 main.log.debug( "sleeping %i seconds" % ( 5 ) )
1646 time.sleep(5)
1647 handle.expect( main.Mininet1.dockerPrompt )
1648 main.log.debug( handle.before + handle.after )
1649 main.Mininet1.prompt = main.Mininet1.bashPrompt
1650 handle.expect( main.Mininet1.prompt )
1651 main.log.debug( handle.before + handle.after )
1652 main.Mininet1.sudoRequired = True
1653 except Exception as e:
1654 main.log.error( e )
1655
1656 @staticmethod
1657 def setOnosConfig( main ):
1658 """
1659 Read and Set onos configurations from the params file
1660 """
1661 main.step( "Set ONOS configurations" )
1662 config = main.params.get( 'ONOS_Configuration' )
1663 if config:
1664 main.log.debug( config )
1665 checkResult = main.TRUE
1666 for component in config:
1667 for setting in config[ component ]:
1668 value = config[ component ][ setting ]
1669 check = main.Cluster.next().setCfg( component, setting, value )
1670 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1671 checkResult = check and checkResult
1672 utilities.assert_equals( expect=main.TRUE,
1673 actual=checkResult,
1674 onpass="Successfully set config",
1675 onfail="Failed to set config" )
1676 else:
1677 main.log.warn( "No configurations were specified to be changed after startup" )
1678
1679 @staticmethod
1680 def setOnosLogLevels( main ):
1681 """
1682 Read and Set onos log levels from the params file
1683 """
1684 main.step( 'Set logging levels' )
1685 logging = True
1686 try:
1687 logs = main.params.get( 'ONOS_Logging', False )
1688 if logs:
1689 for namespace, level in logs.items():
1690 for ctrl in main.Cluster.active():
1691 ctrl.CLI.logSet( level, namespace )
1692 except AttributeError:
1693 logging = False
1694 utilities.assert_equals( expect=True, actual=logging,
1695 onpass="Set log levels",
1696 onfail="Failed to set log levels" )