blob: 43d646bcc1f3f9eb6f60655412662052cfe75e08 [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()
Devin Lim0c972b72018-02-08 14:53:59 -080052 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070053 stepResult = main.FALSE
54 try:
Devin Lim58046fa2017-07-05 16:55:00 -070055 # Test variables
56 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
57 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070058 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080059 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
60 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
61 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
steven308016d41d9c2018-11-25 19:22:11 +080062 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
Devin Lim57221b02018-02-14 15:45:36 -080063 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
steven308016d41d9c2018-11-25 19:22:11 +080064 main.bmv2Path = main.path + "/../dependencies/"
Devin Lim57221b02018-02-14 15:45:36 -080065 main.forJson = "json/"
66 main.forChart = "chart/"
67 main.forConfig = "conf/"
68 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080069 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080070 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070071 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070072 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080073 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
74 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
steven308016d41d9c2018-11-25 19:22:11 +080075 main.bmv2 = "bmv2.py"
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070076 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070077 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070078
Devin Lim0c972b72018-02-08 14:53:59 -080079 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070080 except Exception as e:
81 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070082
Devin Lim58046fa2017-07-05 16:55:00 -070083 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070084
Jon Hall1efcb3f2016-08-23 13:42:15 -070085 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080086 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
87 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070088 """
89 - Set up cell
90 - Create cell file
91 - Set cell file
92 - Verify cell file
93 - Kill ONOS process
94 - Uninstall ONOS cluster
95 - Verify ONOS start up
96 - Install ONOS cluster
97 - Connect to cli
98 """
99 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -0800100 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700101 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -0800102 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
103 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700104 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800105 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800106 skipPack=skipPackage,
107 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800108 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700109 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
110 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800111 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700112 attempts=10 )
113 if ready:
114 ready = main.TRUE
115 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700116 onpass="ONOS summary command succeded",
117 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700118 if not ready:
119 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700120 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700121
Devin Lim142b5342017-07-20 15:22:39 -0700122 for ctrl in main.Cluster.active():
123 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700124 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700125 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700126 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
127 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
128 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700129 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
130 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700131
132 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800133 def loadCount( main ):
134 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700135 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800136
137 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800138 def loadJson( main ):
139 with open( "%s%s.json" % ( main.configPath + main.forJson,
140 main.cfgName ) ) as cfg:
141 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
142
143 @staticmethod
144 def loadChart( main ):
145 try:
146 with open( "%s%s.chart" % ( main.configPath + main.forChart,
147 main.cfgName ) ) as chart:
148 main.pingChart = json.load(chart)
149 except IOError:
150 main.log.warn( "No chart file found." )
151
152 @staticmethod
153 def loadHost( main ):
154 with open( "%s%s.host" % ( main.configPath + main.forHost,
155 main.cfgName ) ) as host:
156 main.expectedHosts = json.load( host )
157
158 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800159 def loadSwitchFailureChart( main ):
160 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
161 main.cfgName ) ) as sfc:
162 main.switchFailureChart = json.load( sfc )
163
164 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800165 def loadLinkFailureChart( main ):
166 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700167 main.cfgName ) ) as lfc:
168 main.linkFailureChart = json.load( lfc )
169
170 @staticmethod
171 def loadMulticastConfig( main ):
172 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
173 main.cfgName ) ) as cfg:
174 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800175
176 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700177 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800178 copyResult = main.ONOSbench.scp( main.Mininet1,
179 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700180 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800181 direction="to" )
182 if main.topologyLib:
183 for lib in main.topologyLib.split(","):
184 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
185 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700186 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800187 direction="to" )
188 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700189 import re
190 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
191 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800192 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700193 # Update zebra configurations with correct ONOS instance IP
194 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
195 ip = controllerIPs[ index ]
196 index = ( index + 1 ) % len( controllerIPs )
197 with open( main.configPath + main.forConfig + conf ) as f:
198 s = f.read()
199 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
200 with open( main.configPath + main.forConfig + conf, "w" ) as f:
201 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800202 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800203 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800204 "~/",
205 direction="to" )
steven308016d41d9c2018-11-25 19:22:11 +0800206 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
207 main.bmv2Path + main.bmv2,
208 main.Mininet1.home + "custom",
209 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800210 stepResult = copyResult
211 utilities.assert_equals( expect=main.TRUE,
212 actual=stepResult,
213 onpass="Successfully copied topo files",
214 onfail="Failed to copy topo files" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700215 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700216 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700217 main.topology = topology
218 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700219 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700220 stepResult = topoResult
221 utilities.assert_equals( expect=main.TRUE,
222 actual=stepResult,
223 onpass="Successfully loaded topology",
224 onfail="Failed to load topology" )
225 # Exit if topology did not load properly
226 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700227 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700228
229 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700230 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800231 main.step( "Connecting to physical netowrk" )
232 topoResult = main.NetworkBench.connectToNet()
233 stepResult = topoResult
234 utilities.assert_equals( expect=main.TRUE,
235 actual=stepResult,
236 onpass="Successfully loaded topology",
237 onfail="Failed to load topology" )
238 # Exit if topology did not load properly
239 if not topoResult:
240 main.cleanAndExit()
241
242 main.step( "Assign switches to controllers." )
243 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700244 switches = main.NetworkBench.getSwitches()
245 pool = []
246 for name in switches.keys():
247 thread = main.Thread( target=main.NetworkBench.assignSwController,
248 name="assignSwitchToController",
249 args=[ name, main.Cluster.getIps(), '6653' ] )
250 pool.append( thread )
251 thread.start()
252 for thread in pool:
253 thread.join( 300 )
254 if not thread.result:
255 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800256 utilities.assert_equals( expect=main.TRUE,
257 actual=stepResult,
258 onpass="Successfully assign switches to controllers",
259 onfail="Failed to assign switches to controllers" )
260
You Wang4cc61912018-08-28 10:10:58 -0700261 # Check devices
262 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
263 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
264 # Connecting to hosts that only have data plane connectivity
265 main.step( "Connecting inband hosts" )
266 stepResult = main.Network.connectInbandHosts()
267 utilities.assert_equals( expect=main.TRUE,
268 actual=stepResult,
269 onpass="Successfully connected inband hosts",
270 onfail="Failed to connect inband hosts" )
271
You Wang84f981d2018-01-12 16:11:50 -0800272 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700273 def saveOnosDiagnostics( main ):
274 """
275 Get onos-diags.tar.gz and save it to the log directory.
276 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
277 """
278 main.log.info( "Collecting onos-diags..." )
279 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
280 main.logdir,
281 "-CASE%d" % main.CurrentTestCaseNumber )
282
283 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700284 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700285 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700286
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700287 main.failures = int( main.params[ 'failures' ] )
288 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700289
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700290 if main.cfgName == '2x2':
291 spine = {}
292 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
293 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
294 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700295
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700296 spine = {}
297 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
298 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
299 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700300
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700301 elif main.cfgName == '4x4':
302 spine = {}
303 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
304 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
305 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700306
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700307 spine = {}
308 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
309 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
310 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700311
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700312 spine = {}
313 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
314 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
315 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700316
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700317 spine = {}
318 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
319 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
320 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700321
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700322 else:
Piera2a7e1b2016-10-04 11:51:43 -0700323 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700324 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800325
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800326 @staticmethod
327 def addStaticOnosRoute( main, subnet, intf):
328 """
329 Adds an ONOS static route with the use route-add command.
330 """
331 main.step("Add static route for subnet {0} towards router interface {1}".format(subnet, intf))
332 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
333
334 utilities.assert_equals( expect=True, actual=( not routeResult ),
335 onpass="route-add command succeeded",
336 onfail="route-add command failed")
Piera2a7e1b2016-10-04 11:51:43 -0700337
338 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700339 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700340 """
341 Check number of groups for each subnet on device deviceId and matches
342 it with an expected value. subnetDict is a dictionarty containing values
343 of the type "10.0.1.0/24" : 5.
344 """
You Wangc02f3be2018-05-18 12:14:23 -0700345 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
346 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
347 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700348
You Wangc02f3be2018-05-18 12:14:23 -0700349 result = main.TRUE
350 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700351 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700352 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700353 # this will match the group id that this flow entry points to, for example :
354 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700355 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700356 count = 0
357 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700358 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700359 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700360 if count - 1 != numberInSelect:
361 result = main.FALSE
362 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 ) )
363 utilities.assert_equals( expect=main.TRUE, actual=result,
364 onpass="All bucket numbers are as expected",
365 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700366
367 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900368 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700369 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800370 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900371 if tag == "":
372 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700373 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700374 main.FALSE,
375 kwargs={ 'min': minFlowCount },
376 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800377 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800378 if count == main.FALSE:
steven308016d41d9c2018-11-25 19:22:11 +0800379 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700380 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700381 expect=True,
steven30801a0cc1422019-01-26 10:06:51 +0800382 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700383 onpass="Flow count looks correct: " + str( count ),
384 onfail="Flow count looks wrong: " + str( count ) )
385
386 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700387 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700388 main.FALSE,
389 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800390 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800391 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700392 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700393 expect=main.TRUE,
394 actual=flowCheck,
395 onpass="Flow status is correct!",
396 onfail="Flow status is wrong!" )
397 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700398 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700399 "flows",
400 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900401 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700402 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700403 "groups",
404 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900405 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700406
407 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700408 def checkDevices( main, switches, tag="", sleep=10 ):
409 main.step(
410 "Check whether the switches count is equal to %s" % switches )
411 if tag == "":
412 tag = 'CASE%d' % main.CurrentTestCaseNumber
413 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
414 main.FALSE,
415 kwargs={ 'numoswitch': switches},
416 attempts=10,
417 sleep=sleep )
418 utilities.assert_equals( expect=main.TRUE, actual=result,
419 onpass="Device up successful",
420 onfail="Failed to boot up devices?" )
421
422 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800423 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
424 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800425 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
426 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
427 main.FALSE,
428 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800429 attempts=5,
430 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800431 if count == main.FALSE:
432 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800433 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800434 expect=True,
435 actual=( count > minFlowCount ),
436 onpass="Flow count looks correct: " + str( count ),
steven30801a0cc1422019-01-26 10:06:51 +0800437 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800438
439 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700440 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800441 main.step(
442 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
443 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
444 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700445 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800446 attempts=5,
447 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800448 if count == main.FALSE:
449 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800450 utilities.assertEquals(
451 expect=True,
steven30801a0cc1422019-01-26 10:06:51 +0800452 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700453 onpass="Flow count looks correct: " + str( count ) ,
454 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800455
456 @staticmethod
457 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
458 main.step(
459 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
460 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
461 main.FALSE,
462 args=( dpid, groupCount, False, 1),
463 attempts=5,
464 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800465 if count == main.FALSE:
steven308016d41d9c2018-11-25 19:22:11 +0800466 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800467 utilities.assertEquals(
468 expect=True,
469 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700470 onpass="Group count looks correct: " + str( count ) ,
471 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800472
473 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700474 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800475
476 for dpid, values in main.count.items():
477 flowCount = values["flows"]
478 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700479 main.log.report( "Check flow count for dpid " + str( dpid ) +
480 ", should be " + str( flowCount ) )
481 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800482
Jon Hall9677ed32018-04-24 11:16:23 -0700483 main.log.report( "Check group count for dpid " + str( dpid ) +
484 ", should be " + str( groupCount ) )
485 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800486
487 return
488
489 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700490 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
491 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800492 '''
You Wangba231e72018-03-01 13:18:21 -0800493 Verify connectivity between hosts according to the ping chart
494 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800495 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800496 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800497 '''
You Wangba231e72018-03-01 13:18:21 -0800498 main.log.report( "Check host connectivity" )
499 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800500 if tag == "":
501 tag = 'CASE%d' % main.CurrentTestCaseNumber
502 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800503 main.log.debug( "Entry in ping chart: %s" % entry )
504 expect = entry[ 'expect' ]
505 if expect == "Unidirectional":
506 # Verify ping from each src host to each dst host
507 src = entry[ 'src' ]
508 dst = entry[ 'dst' ]
509 expect = main.TRUE
510 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
511 if basedOnIp:
512 if ("v4" in src[0]):
513 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
514 utilities.assert_equals( expect=expect, actual=pa,
515 onpass="IPv4 connectivity successfully tested",
516 onfail="IPv4 connectivity failed" )
517 if ("v6" in src[0]):
518 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
519 utilities.assert_equals( expect=expect, actual=pa,
520 onpass="IPv6 connectivity successfully tested",
521 onfail="IPv6 connectivity failed" )
522 else:
523 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
524 utilities.assert_equals( expect=expect, actual=pa,
525 onpass="IP connectivity successfully tested",
526 onfail="IP connectivity failed" )
527 else:
528 # Verify ping between each host pair
529 hosts = entry[ 'hosts' ]
530 try:
531 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
532 except:
533 expect = main.FALSE
534 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
535 if basedOnIp:
536 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800537 pa = utilities.retry( main.Network.pingallHosts,
538 main.FALSE if expect else main.TRUE,
539 args=(hosts,),
540 attempts=retryAttempts,
541 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800542 utilities.assert_equals( expect=expect, actual=pa,
543 onpass="IPv4 connectivity successfully tested",
544 onfail="IPv4 connectivity failed" )
545 if ("v6" in hosts[0]):
546 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
547 utilities.assert_equals( expect=expect, actual=pa,
548 onpass="IPv6 connectivity successfully tested",
549 onfail="IPv6 connectivity failed" )
550 else:
You Wangf19d9f42018-02-23 16:34:19 -0800551 pa = main.Network.pingallHosts( hosts )
552 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800553 onpass="IP connectivity successfully tested",
554 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700555 if skipOnFail and pa != expect:
556 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700557 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700558 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800559
560 if dumpflows:
561 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
562 "flows",
563 main.logdir,
564 tag + "_FlowsOn" )
565 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
566 "groups",
567 main.logdir,
568 tag + "_GroupsOn" )
569
570 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700571 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700572 """
573 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
574 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
575 Kill a link and verify ONOS can see the proper link change
576 """
Jon Halla604fd42018-05-04 14:27:27 -0700577 if sleep is None:
578 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
579 else:
580 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700581 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700582 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
583 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
584 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700585 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700586 "Waiting %s seconds for link down to be discovered" % sleep )
587 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700588 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700589 main.FALSE,
590 kwargs={ 'numoswitch': switches,
591 'numolink': links },
592 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700593 sleep=sleep )
594 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700595 utilities.assert_equals( expect=main.TRUE, actual=result,
596 onpass="Link down successful",
597 onfail="Failed to turn off link?" )
598
599 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700600 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800601 """
602 links = list of links (src, dst) to bring down.
603 """
604
605 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700606 if sleep is None:
607 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
608 else:
609 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800610
611 for end1, end2 in links:
612 main.Network.link( END1=end1, END2=end2, OPTION="down")
613 main.Network.link( END1=end2, END2=end1, OPTION="down")
614
Jon Halla604fd42018-05-04 14:27:27 -0700615 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800616 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700617 "Waiting %s seconds for links down to be discovered" % sleep )
618 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800619
620 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
621 main.FALSE,
622 kwargs={ 'numoswitch': switches,
623 'numolink': linksAfter },
624 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700625 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800626
You Wang2854bce2018-03-30 10:15:32 -0700627 utilities.assert_equals( expect=main.TRUE, actual=topology,
628 onpass="Link batch down successful",
629 onfail="Link batch down failed" )
630
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800631 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700632 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800633 """
634 links = list of link (src, dst) to bring up again.
635 """
636
637 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700638 if sleep is None:
639 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
640 else:
641 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800642
643 for end1, end2 in links:
644 main.Network.link( END1=end1, END2=end2, OPTION="up")
645 main.Network.link( END1=end2, END2=end1, OPTION="up")
646
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800647 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700648 "Waiting %s seconds for links up to be discovered" % sleep )
649 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800650
651 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
652 main.FALSE,
653 kwargs={ 'numoswitch': switches,
654 'numolink': linksAfter },
655 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700656 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800657
You Wang2854bce2018-03-30 10:15:32 -0700658 utilities.assert_equals( expect=main.TRUE, actual=topology,
659 onpass="Link batch up successful",
660 onfail="Link batch up failed" )
661
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800662 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700663 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
664 """
665 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
666 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
667 switches, links: number of expected switches and links after link change, ex.: '4', '6'
668 """
669 if sleep is None:
670 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
671 else:
672 sleep = float( sleep )
673 main.step( "Disable a batch of ports" )
674 for dpid, port in ports:
675 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
676 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
677 time.sleep( sleep )
678 if switches and links:
679 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
680 numolink=links )
681 utilities.assert_equals( expect=main.TRUE, actual=result,
682 onpass="Port down successful",
683 onfail="Port down failed" )
684
685 @staticmethod
686 def enablePortBatch( main, ports, switches, links, sleep=None ):
687 """
688 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
689 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
690 switches, links: number of expected switches and links after link change, ex.: '4', '6'
691 """
692 if sleep is None:
693 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
694 else:
695 sleep = float( sleep )
696 main.step( "Enable a batch of ports" )
697 for dpid, port in ports:
698 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
699 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
700 time.sleep( sleep )
701 if switches and links:
702 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
703 numolink=links )
704 utilities.assert_equals( expect=main.TRUE, actual=result,
705 onpass="Port up successful",
706 onfail="Port up failed" )
707
708 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700709 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700710 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700711 """
712 Params:
713 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700714 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700715 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
716 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
717 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
718 Kill a link and verify ONOS can see the proper link change
719 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700720 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700721 if sleep is None:
722 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
723 else:
724 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700725 result = False
726 count = 0
727 while True:
728 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700729 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800730 main.Network.link( END1=end1, END2=end2, OPTION="up" )
731 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700732 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700733 "Waiting %s seconds for link up to be discovered" % sleep )
734 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700735
You Wangc02d8352018-04-17 16:42:10 -0700736 if portUp:
737 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
738 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700739 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700740
Jon Halla604fd42018-05-04 14:27:27 -0700741 result = ctrl.CLI.checkStatus( numoswitch=switches,
742 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700743 if count > 5 or result:
744 break
745 utilities.assert_equals( expect=main.TRUE, actual=result,
746 onpass="Link up successful",
747 onfail="Failed to bring link up" )
748
749 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700750 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700751 """
752 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
753 Completely kill a switch and verify ONOS can see the proper change
754 """
Jon Halla604fd42018-05-04 14:27:27 -0700755 if sleep is None:
756 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
757 else:
758 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700759 switch = switch if isinstance( switch, list ) else [ switch ]
760 main.step( "Kill " + str( switch ) )
761 for s in switch:
762 main.log.info( "Stopping " + s )
763 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700764 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700765
766 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700767 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700768 sleep ) )
769 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700770 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700771 main.FALSE,
772 kwargs={ 'numoswitch': switches,
773 'numolink': links },
774 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700775 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700776 utilities.assert_equals( expect=main.TRUE, actual=topology,
777 onpass="Kill switch successful",
778 onfail="Failed to kill switch?" )
779
780 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700781 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700782 """
783 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
784 Recover a switch and verify ONOS can see the proper change
785 """
Jon Halla604fd42018-05-04 14:27:27 -0700786 if sleep is None:
787 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
788 else:
789 sleep = float( sleep )
790 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700791 switch = switch if isinstance( switch, list ) else [ switch ]
792 main.step( "Recovering " + str( switch ) )
793 for s in switch:
794 main.log.info( "Starting " + s )
795 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700796 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700797 sleep ) )
798 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700799 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700800 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700801 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700802 sleep ) )
803 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700804
Devin Lim142b5342017-07-20 15:22:39 -0700805 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700806 main.FALSE,
807 kwargs={ 'numoswitch': switches,
808 'numolink': links },
809 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700810 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700811 utilities.assert_equals( expect=main.TRUE, actual=topology,
812 onpass="Switch recovery successful",
813 onfail="Failed to recover switch?" )
814
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700815 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700816 def killRouter( main, router, sleep=None ):
817 """
818 Kill bgpd process on a quagga router
819 router: name of the router to be killed. E.g. "bgp1"
820 """
821 sleep = float( sleep )
822 main.step( "Kill " + str( router ) )
823 if hasattr( main, 'Mininet1' ):
824 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
825 main.Mininet1.handle.expect( "mininet>" )
826 else:
827 # TODO: support killing router in physical network
828 pass
829 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
830 time.sleep( sleep )
831
832 @staticmethod
833 def recoverRouter( main, router, sleep=None ):
834 """
835 Restart bgpd process on a quagga router
836 router: name of the router to be recovered. E.g. "bgp1"
837 """
838 sleep = float( sleep )
839 main.step( "Recovering " + str( router ) )
840 if hasattr( main, 'Mininet1' ):
841 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
842 main.Mininet1.handle.expect( "mininet>" )
843 else:
844 # TODO: support recovering router in physical network
845 pass
846 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
847 time.sleep( sleep )
848
849 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700850 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700851 """
852 Stop Onos-cluster.
853 Stops Mininet
854 Copies ONOS log
855 """
You Wang4cc61912018-08-28 10:10:58 -0700856 from tests.dependencies.utils import Utils
857 main.utils = Utils()
858 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700859 if hasattr( main, "scapyHosts" ):
860 scapyResult = main.TRUE
861 for host in main.scapyHosts:
862 scapyResult = host.stopScapy() and scapyResult
863 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
864 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700865 if hasattr( main, 'Mininet1' ):
866 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
867 else:
868 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700869 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
870 main.scapyHosts = []
871
You Wang5da39c82018-04-26 22:55:08 -0700872 if removeHostComponent:
873 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
874 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700875 if hasattr( main, 'Mininet1' ):
876 pass
877 else:
878 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700879 main.Network.removeHostComponent( host )
880
You Wang5df1c6d2018-04-06 18:02:02 -0700881 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700882 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700883 else:
884 main.Network.disconnectInbandHosts()
885 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700886
You Wang5df1c6d2018-04-06 18:02:02 -0700887 if copyKarafLog:
888 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700889
Devin Lim142b5342017-07-20 15:22:39 -0700890 for ctrl in main.Cluster.active():
891 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700892
893 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700894 def verifyNodes( main ):
895 """
896 Verifies Each active node in the cluster has an accurate view of other node's and their status
897
898 Params:
899 nodes, integer array with position of the ONOS nodes in the CLIs array
900 """
901 nodeResults = utilities.retry( main.Cluster.nodesCheck,
902 False,
903 attempts=10,
904 sleep=10 )
905 utilities.assert_equals( expect=True, actual=nodeResults,
906 onpass="Nodes check successful",
907 onfail="Nodes check NOT successful" )
908
909 if not nodeResults:
910 for ctrl in main.Cluster.runningNodes:
911 main.log.debug( "{} components not ACTIVE: \n{}".format(
912 ctrl.name,
913 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
914 main.log.error( "Failed to kill ONOS, stopping test" )
915 main.cleanAndExit()
916
917 @staticmethod
918 def verifyTopology( main, switches, links, expNodes ):
919 """
920 Verifies that the ONOS cluster has an acuurate view of the topology
921
922 Params:
923 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
924 """
925 main.step( "Check number of topology elements" )
926 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
927 main.FALSE,
928 kwargs={ 'numoswitch': switches,
929 'numolink': links,
930 'numoctrl': expNodes },
931 attempts=10,
932 sleep=12 )
933 utilities.assert_equals( expect=main.TRUE, actual=topology,
934 onpass="Number of topology elements are correct",
935 onfail="Unexpected number of links, switches, and/or controllers" )
936
937 @staticmethod
938 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700939 """
940 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
941 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
942 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
943 """
Jon Halla604fd42018-05-04 14:27:27 -0700944 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800945 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700946 if sleep is None:
947 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
948 else:
949 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700950
Jon Hall1efcb3f2016-08-23 13:42:15 -0700951 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700952 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700953 utilities.assert_equals( expect=main.TRUE, actual=killResult,
954 onpass="ONOS instance Killed",
955 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700956 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700957 main.Cluster.reset()
958 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700959
Devin Lim142b5342017-07-20 15:22:39 -0700960 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700961 Testcaselib.verifyNodes( main )
962 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700963
964 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700965 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700966 """
967 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
968 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
969 Recover an ONOS instance and verify the ONOS cluster can see the proper change
970 """
Jon Hall3c910162018-03-07 14:42:16 -0800971 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700972 if sleep is None:
973 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
974 else:
975 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700976 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700977 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700978 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700979 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700980 utilities.assert_equals( expect=main.TRUE, actual=isUp,
981 onpass="ONOS service is ready",
982 onfail="ONOS service did not start properly" )
983 for i in nodes:
984 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700985 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900986 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700987 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
988 commandlineTimeout=60,
989 onosStartTimeout=100 )
990 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700991 utilities.assert_equals( expect=main.TRUE,
992 actual=cliResult,
993 onpass="ONOS CLI is ready",
994 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700995
Jon Halla604fd42018-05-04 14:27:27 -0700996 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700997 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700998 Testcaselib.verifyNodes( main )
999 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001000
Devin Lim142b5342017-07-20 15:22:39 -07001001 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
1002 main.FALSE,
1003 attempts=10,
1004 sleep=12 )
1005 if ready:
1006 ready = main.TRUE
1007 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001008 onpass="ONOS summary command succeded",
1009 onfail="ONOS summary command failed" )
1010 if not ready:
1011 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001012 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001013
1014 @staticmethod
1015 def addHostCfg( main ):
1016 """
1017 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001018 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001019 """
1020 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001021 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001022 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001023 hostCfg = json.load( template )
1024 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1025 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001026 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001027 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1028 subjectClass="hosts",
1029 subjectKey=urllib.quote( mac,
1030 safe='' ),
1031 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001032 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1033 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001034 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001035 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1036 subjectClass="hosts",
1037 subjectKey=urllib.quote( mac,
1038 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001039 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001040 main.pingChart.update( { 'vlan1': { "expect": "True",
1041 "hosts": [ "olt1", "vsg1" ] } } )
1042 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1043 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001044 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001045 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001046 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1047 subjectClass="apps",
1048 subjectKey="org.onosproject.segmentrouting",
1049 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001050
1051 @staticmethod
1052 def delHostCfg( main ):
1053 """
1054 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001055 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001056 """
1057 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001058 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001059 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001060 hostCfg = json.load( template )
1061 main.step( "Removing host configuration" )
1062 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001063 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001064 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1065 subjectKey=urllib.quote(
1066 mac,
1067 safe='' ),
1068 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001069 main.step( "Removing configuration" )
1070 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001071 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001072 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1073 subjectKey=urllib.quote(
1074 mac,
1075 safe='' ),
1076 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001077 main.step( "Removing vlan configuration" )
1078 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001079 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1080 subjectKey="org.onosproject.segmentrouting",
1081 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001082
1083 @staticmethod
1084 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1085 """
1086 Verifies IP address assignment from the hosts
1087 """
1088 main.step( "Verify IP address assignment from hosts" )
1089 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001090 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001091 # Find out names of disconnected hosts
1092 disconnectedHosts = []
1093 if hasattr( main, "disconnectedIpv4Hosts" ):
1094 for host in main.disconnectedIpv4Hosts:
1095 disconnectedHosts.append( host )
1096 if hasattr( main, "disconnectedIpv6Hosts" ):
1097 for host in main.disconnectedIpv6Hosts:
1098 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001099 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001100 # Exclude disconnected hosts
1101 if hostName in disconnectedHosts:
1102 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1103 continue
You Wang53dba1e2018-02-02 17:45:44 -08001104 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1105 main.FALSE,
1106 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001107 'prefix': ip,
1108 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001109 attempts=attempts,
1110 sleep=sleep )
1111 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1112 onpass="Verify network host IP succeded",
1113 onfail="Verify network host IP failed" )
1114
1115 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001116 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001117 """
1118 Verifies host IP address assignment from ONOS
1119 """
1120 main.step( "Verify host IP address assignment in ONOS" )
1121 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001122 # Find out IPs of disconnected hosts
1123 disconnectedIps = []
1124 if hasattr( main, "disconnectedIpv4Hosts" ):
1125 for host in main.disconnectedIpv4Hosts:
1126 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1127 if hasattr( main, "disconnectedIpv6Hosts" ):
1128 for host in main.disconnectedIpv6Hosts:
1129 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001130 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001131 # Exclude disconnected hosts
1132 if ip in disconnectedIps:
1133 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1134 continue
You Wang53dba1e2018-02-02 17:45:44 -08001135 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1136 main.FALSE,
1137 kwargs={ 'hostList': [ hostName ],
1138 'prefix': ip },
1139 attempts=attempts,
1140 sleep=sleep )
1141 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1142 onpass="Verify ONOS host IP succeded",
1143 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001144 if not ipResult and skipOnFail:
1145 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001146 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001147 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001148
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001149 @staticmethod
1150 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1151 """
1152 Description:
1153 Updates interface configuration in ONOS, with given IP and vlan parameters
1154 Required:
1155 * connectPoint: connect point to update configuration
1156 Optional:
1157 * ips: list of IP addresses, combined with '/xx' subnet representation,
1158 corresponding to 'ips' field in the configuration
1159 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1160 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1161 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1162 """
1163 cfg = dict()
1164 cfg[ "ports" ] = dict()
1165 cfg[ "ports" ][ connectPoint ] = dict()
1166 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1167 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1168 if untagged > 0:
1169 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1170 else:
1171 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1172 if native > 0:
1173 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1174
1175 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001176
1177 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001178 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001179 """
1180 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001181 scapyNames: list of names that will be used as component names for scapy hosts
1182 mininetNames: used when scapy host names are different from the host names
1183 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1184 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001185 """
1186 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001187 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1188 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001189 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001190 if hasattr( main, 'Mininet1' ):
1191 main.Scapy.createHostComponent( scapyName )
1192 scapyHandle = getattr( main, scapyName )
1193 if mininetNames:
1194 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1195 else:
1196 mininetName = None
1197 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001198 else:
You Wang1a704002018-11-02 17:49:18 -07001199 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001200 scapyHandle = getattr( main, scapyName )
1201 scapyHandle.connectInband()
1202 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001203 scapyHandle.startScapy()
1204 scapyHandle.updateSelf()
1205 main.log.debug( scapyHandle.name )
1206 main.log.debug( scapyHandle.hostIp )
1207 main.log.debug( scapyHandle.hostMac )
1208
1209 @staticmethod
1210 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1211 """
1212 Verify unicast traffic by pinging from source hosts to the destination IP
1213 and capturing the packets at the destination host using Scapy.
1214 srcHosts: List of host names to send the ping packets
1215 dstIp: destination IP of the ping packets
1216 dstHost: host that runs Scapy to capture the packets
1217 dstIntf: name of the interface on the destination host
1218 expect: use True if the ping is expected to be captured at destination;
1219 Otherwise False
1220 skipOnFail: skip the rest of this test case if result is not expected
1221 maxRetry: number of retries allowed
1222 """
1223 from tests.dependencies.topology import Topology
1224 try:
1225 main.topo
1226 except ( NameError, AttributeError ):
1227 main.topo = Topology()
1228 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1229 result = main.TRUE
1230 for srcHost in srcHosts:
1231 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1232 expect, maxRetry, True )
1233 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001234 result = main.FALSE
1235 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1236 utilities.assert_equals( expect=main.TRUE,
1237 actual=result,
1238 onpass="Verify traffic to {}: Pass".format( dstIp ),
1239 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1240 if skipOnFail and result != main.TRUE:
1241 Testcaselib.saveOnosDiagnostics( main )
1242 Testcaselib.cleanup( main, copyKarafLog=False )
1243 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001244
1245 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001246 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001247 """
1248 Verify multicast traffic using scapy
1249 """
You Wangc564c6f2018-05-01 15:24:57 -07001250 from tests.dependencies.topology import Topology
1251 try:
1252 main.topo
1253 except ( NameError, AttributeError ):
1254 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001255 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001256 routeData = main.multicastConfig[ routeName ]
1257 srcs = main.mcastRoutes[ routeName ][ "src" ]
1258 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1259 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1260 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001261 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001262 for src in srcs:
1263 srcEntry = routeData[ "src" ][ src ]
1264 for dst in dsts:
1265 dstEntry = routeData[ "dst" ][ dst ]
1266 sender = getattr( main, srcEntry[ "host" ] )
1267 receiver = getattr( main, dstEntry[ "host" ] )
1268 main.Network.addRoute( str( srcEntry[ "host" ] ),
1269 str( routeData[ "group" ] ),
1270 str( srcEntry[ "interface" ] ),
1271 True if routeData[ "ipVersion" ] == 6 else False )
1272 # Build the packet
1273 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1274 if routeData[ "ipVersion" ] == 4:
1275 sender.buildIP( dst=str( routeData[ "group" ] ) )
1276 elif routeData[ "ipVersion" ] == 6:
1277 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1278 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1279 sIface = srcEntry[ "interface" ]
1280 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1281 pktFilter = srcEntry[ "filter" ]
1282 pkt = srcEntry[ "packet" ]
1283 # Send packet and check received packet
1284 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001285 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001286 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001287 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1288 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001289 if not trafficResult:
1290 result = main.FALSE
1291 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1292 dstEntry[ "host" ] ) )
1293 utilities.assert_equals( expect=main.TRUE,
1294 actual=result,
1295 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1296 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001297 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001298 Testcaselib.saveOnosDiagnostics( main )
1299 Testcaselib.cleanup( main, copyKarafLog=False )
1300 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001301
1302 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001303 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001304 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1305 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001306 """
1307 Verify reachability from each host in srcList to each host in dstList
1308 """
1309 from tests.dependencies.topology import Topology
1310 try:
1311 main.topo
1312 except ( NameError, AttributeError ):
1313 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001314 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001315 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001316 utilities.assert_equals( expect=main.TRUE,
1317 actual=pingResult,
1318 onpass="{}: Pass".format( stepMsg ),
1319 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001320 if not pingResult and skipOnFail:
1321 Testcaselib.saveOnosDiagnostics( main )
1322 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1323 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001324
1325 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001326 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001327 """
1328 Verify if the specified host is discovered by ONOS on the given locations
1329 Required:
You Wang85747762018-05-11 15:51:50 -07001330 locationDict: a dictionary that maps host names to expected locations.
1331 locations could be a string or a list.
1332 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001333 Returns:
1334 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1335 """
You Wang85747762018-05-11 15:51:50 -07001336 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1337 result = main.TRUE
1338 for hostName, locations in locationDict.items():
1339 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1340 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1341 if not hostIp:
1342 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1343 if not hostIp:
1344 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1345 result = main.FALSE
1346 continue
1347 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1348 main.FALSE,
1349 args=( hostIp, locations ),
1350 attempts=retry + 1,
1351 sleep=10 )
1352 if not locationResult:
1353 result = main.FALSE
1354 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001355 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001356 onpass="Location verification passed",
1357 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001358
1359 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001360 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001361 """
1362 Move specified host from srcSw to dstSw.
1363 If srcSw and dstSw are same, the host will be moved from current port to
1364 next available port.
1365 Required:
1366 hostName: name of the host. e.g., "h1"
1367 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1368 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1369 gw: ip address of the gateway of the new location
1370 Optional:
1371 macAddr: if specified, change MAC address of the host to the specified MAC address.
1372 prefixLen: prefix length
1373 cfg: port configuration as JSON string
1374 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001375 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001376 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001377 if not hasattr( main, 'Mininet1' ):
1378 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1379 return
1380
You Wang6e5b48e2018-07-23 16:17:38 -07001381 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1382 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1383 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001384 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001385 if cfg:
1386 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1387 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001388 # Wait for the host to get RA for setting up default gateway
1389 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001390
1391 main.Mininet1.discoverHosts( [ hostName, ] )
1392
1393 # Update expectedHost when MAC address is changed.
1394 if macAddr is not None:
1395 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1396 if ipAddr is not None:
1397 for hostName, ip in main.expectedHosts[ "onos" ].items():
1398 if ip == ipAddr:
1399 vlan = hostName.split( "/" )[ -1 ]
1400 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001401 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001402 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001403
1404 @staticmethod
1405 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001406 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001407 """
1408 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1409 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1410 to next available port.
1411 Required:
1412 hostName: name of the host. e.g., "h1"
1413 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1414 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1415 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1416 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1417 gw: ip address of the gateway of the new location
1418 Optional:
1419 macAddr: if specified, change MAC address of the host to the specified MAC address.
1420 prefixLen: prefix length
1421 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001422 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001423 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001424 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001425 if not hasattr( main, 'Mininet1' ):
1426 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1427 return
1428
You Wang6e5b48e2018-07-23 16:17:38 -07001429 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1430 srcSw, srcPairSw, dstSw, dstPairSw ) )
1431 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1432 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1433 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001434 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001435 if cfg:
1436 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1437 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001438 # Wait for the host to get RA for setting up default gateway
1439 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001440
1441 main.Mininet1.discoverHosts( [ hostName, ] )
1442
1443 # Update expectedHost when MAC address is changed.
1444 if macAddr is not None:
1445 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1446 if ipAddr is not None:
1447 for hostName, ip in main.expectedHosts[ "onos" ].items():
1448 if ip == ipAddr:
1449 vlan = hostName.split( "/" )[ -1 ]
1450 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001451 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip