blob: 38e3e2fe5e5d8fe3876ed25dfd9ef501b69ecd76 [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'
62 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
63 main.forJson = "json/"
64 main.forChart = "chart/"
65 main.forConfig = "conf/"
66 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080067 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080068 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070069 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070070 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080071 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
72 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070073 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070074 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070075
Devin Lim0c972b72018-02-08 14:53:59 -080076 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070077 except Exception as e:
78 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070079
Devin Lim58046fa2017-07-05 16:55:00 -070080 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070081
Jon Hall1efcb3f2016-08-23 13:42:15 -070082 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080083 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
84 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070085 """
86 - Set up cell
87 - Create cell file
88 - Set cell file
89 - Verify cell file
90 - Kill ONOS process
91 - Uninstall ONOS cluster
92 - Verify ONOS start up
93 - Install ONOS cluster
94 - Connect to cli
95 """
96 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -080097 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -070098 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -080099 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
100 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700101 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800102 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800103 skipPack=skipPackage,
104 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800105 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700106 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
107 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800108 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700109 attempts=10 )
110 if ready:
111 ready = main.TRUE
112 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700113 onpass="ONOS summary command succeded",
114 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700115 if not ready:
116 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700117 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700118
Devin Lim142b5342017-07-20 15:22:39 -0700119 for ctrl in main.Cluster.active():
120 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700121 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700122 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700123 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
124 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
125 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700126 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
127 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700128
129 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800130 def loadCount( main ):
131 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700132 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800133
134 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800135 def loadJson( main ):
136 with open( "%s%s.json" % ( main.configPath + main.forJson,
137 main.cfgName ) ) as cfg:
138 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
139
140 @staticmethod
141 def loadChart( main ):
142 try:
143 with open( "%s%s.chart" % ( main.configPath + main.forChart,
144 main.cfgName ) ) as chart:
145 main.pingChart = json.load(chart)
146 except IOError:
147 main.log.warn( "No chart file found." )
148
149 @staticmethod
150 def loadHost( main ):
151 with open( "%s%s.host" % ( main.configPath + main.forHost,
152 main.cfgName ) ) as host:
153 main.expectedHosts = json.load( host )
154
155 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800156 def loadSwitchFailureChart( main ):
157 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
158 main.cfgName ) ) as sfc:
159 main.switchFailureChart = json.load( sfc )
160
161 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800162 def loadLinkFailureChart( main ):
163 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700164 main.cfgName ) ) as lfc:
165 main.linkFailureChart = json.load( lfc )
166
167 @staticmethod
168 def loadMulticastConfig( main ):
169 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
170 main.cfgName ) ) as cfg:
171 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800172
173 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700174 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800175 copyResult = main.ONOSbench.scp( main.Mininet1,
176 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700177 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800178 direction="to" )
179 if main.topologyLib:
180 for lib in main.topologyLib.split(","):
181 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
182 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700183 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800184 direction="to" )
185 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700186 import re
187 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
188 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800189 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700190 # Update zebra configurations with correct ONOS instance IP
191 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
192 ip = controllerIPs[ index ]
193 index = ( index + 1 ) % len( controllerIPs )
194 with open( main.configPath + main.forConfig + conf ) as f:
195 s = f.read()
196 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
197 with open( main.configPath + main.forConfig + conf, "w" ) as f:
198 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800199 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800200 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800201 "~/",
202 direction="to" )
203 stepResult = copyResult
204 utilities.assert_equals( expect=main.TRUE,
205 actual=stepResult,
206 onpass="Successfully copied topo files",
207 onfail="Failed to copy topo files" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700208 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700209 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700210 main.topology = topology
211 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700212 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700213 stepResult = topoResult
214 utilities.assert_equals( expect=main.TRUE,
215 actual=stepResult,
216 onpass="Successfully loaded topology",
217 onfail="Failed to load topology" )
218 # Exit if topology did not load properly
219 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700220 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700221
222 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700223 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800224 main.step( "Connecting to physical netowrk" )
225 topoResult = main.NetworkBench.connectToNet()
226 stepResult = topoResult
227 utilities.assert_equals( expect=main.TRUE,
228 actual=stepResult,
229 onpass="Successfully loaded topology",
230 onfail="Failed to load topology" )
231 # Exit if topology did not load properly
232 if not topoResult:
233 main.cleanAndExit()
234
235 main.step( "Assign switches to controllers." )
236 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700237 switches = main.NetworkBench.getSwitches()
238 pool = []
239 for name in switches.keys():
240 thread = main.Thread( target=main.NetworkBench.assignSwController,
241 name="assignSwitchToController",
242 args=[ name, main.Cluster.getIps(), '6653' ] )
243 pool.append( thread )
244 thread.start()
245 for thread in pool:
246 thread.join( 300 )
247 if not thread.result:
248 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800249 utilities.assert_equals( expect=main.TRUE,
250 actual=stepResult,
251 onpass="Successfully assign switches to controllers",
252 onfail="Failed to assign switches to controllers" )
253
You Wang4cc61912018-08-28 10:10:58 -0700254 # Check devices
255 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
256 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
257 # Connecting to hosts that only have data plane connectivity
258 main.step( "Connecting inband hosts" )
259 stepResult = main.Network.connectInbandHosts()
260 utilities.assert_equals( expect=main.TRUE,
261 actual=stepResult,
262 onpass="Successfully connected inband hosts",
263 onfail="Failed to connect inband hosts" )
264
You Wang84f981d2018-01-12 16:11:50 -0800265 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700266 def saveOnosDiagnostics( main ):
267 """
268 Get onos-diags.tar.gz and save it to the log directory.
269 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
270 """
271 main.log.info( "Collecting onos-diags..." )
272 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
273 main.logdir,
274 "-CASE%d" % main.CurrentTestCaseNumber )
275
276 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700277 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700278 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700279
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700280 main.failures = int( main.params[ 'failures' ] )
281 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700282
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700283 if main.cfgName == '2x2':
284 spine = {}
285 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
286 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
287 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700288
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700289 spine = {}
290 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
291 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
292 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700293
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700294 elif main.cfgName == '4x4':
295 spine = {}
296 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
297 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
298 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700299
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700300 spine = {}
301 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
302 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
303 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700304
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700305 spine = {}
306 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
307 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
308 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700309
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700310 spine = {}
311 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
312 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
313 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700314
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700315 else:
Piera2a7e1b2016-10-04 11:51:43 -0700316 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700317 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800318
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800319 @staticmethod
320 def addStaticOnosRoute( main, subnet, intf):
321 """
322 Adds an ONOS static route with the use route-add command.
323 """
324 main.step("Add static route for subnet {0} towards router interface {1}".format(subnet, intf))
325 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
326
327 utilities.assert_equals( expect=True, actual=( not routeResult ),
328 onpass="route-add command succeeded",
329 onfail="route-add command failed")
Piera2a7e1b2016-10-04 11:51:43 -0700330
331 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700332 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700333 """
334 Check number of groups for each subnet on device deviceId and matches
335 it with an expected value. subnetDict is a dictionarty containing values
336 of the type "10.0.1.0/24" : 5.
337 """
You Wangc02f3be2018-05-18 12:14:23 -0700338 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
339 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
340 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700341
You Wangc02f3be2018-05-18 12:14:23 -0700342 result = main.TRUE
343 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700344 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700345 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700346 # this will match the group id that this flow entry points to, for example :
347 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700348 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700349 count = 0
350 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700351 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700352 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700353 if count - 1 != numberInSelect:
354 result = main.FALSE
355 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 ) )
356 utilities.assert_equals( expect=main.TRUE, actual=result,
357 onpass="All bucket numbers are as expected",
358 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700359
360 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900361 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700362 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800363 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900364 if tag == "":
365 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700366 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700367 main.FALSE,
368 kwargs={ 'min': minFlowCount },
369 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800370 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800371 if count == main.FALSE:
372 count == main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700373 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700374 expect=True,
steven30801a0cc1422019-01-26 10:06:51 +0800375 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700376 onpass="Flow count looks correct: " + str( count ),
377 onfail="Flow count looks wrong: " + str( count ) )
378
379 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700380 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700381 main.FALSE,
382 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800383 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800384 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700385 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700386 expect=main.TRUE,
387 actual=flowCheck,
388 onpass="Flow status is correct!",
389 onfail="Flow status is wrong!" )
390 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700391 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700392 "flows",
393 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900394 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700395 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700396 "groups",
397 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900398 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700399
400 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700401 def checkDevices( main, switches, tag="", sleep=10 ):
402 main.step(
403 "Check whether the switches count is equal to %s" % switches )
404 if tag == "":
405 tag = 'CASE%d' % main.CurrentTestCaseNumber
406 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
407 main.FALSE,
408 kwargs={ 'numoswitch': switches},
409 attempts=10,
410 sleep=sleep )
411 utilities.assert_equals( expect=main.TRUE, actual=result,
412 onpass="Device up successful",
413 onfail="Failed to boot up devices?" )
414
415 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800416 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
417 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800418 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
419 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
420 main.FALSE,
421 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800422 attempts=5,
423 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800424 if count == main.FALSE:
425 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800426 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800427 expect=True,
428 actual=( count > minFlowCount ),
429 onpass="Flow count looks correct: " + str( count ),
steven30801a0cc1422019-01-26 10:06:51 +0800430 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800431
432 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700433 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800434 main.step(
435 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
436 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
437 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700438 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800439 attempts=5,
440 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800441 if count == main.FALSE:
442 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800443 utilities.assertEquals(
444 expect=True,
steven30801a0cc1422019-01-26 10:06:51 +0800445 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700446 onpass="Flow count looks correct: " + str( count ) ,
447 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800448
449 @staticmethod
450 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
451 main.step(
452 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
453 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
454 main.FALSE,
455 args=( dpid, groupCount, False, 1),
456 attempts=5,
457 sleep=sleep )
steven30801a0cc1422019-01-26 10:06:51 +0800458 if count == main.FALSE:
459 count = main.Cluseter.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800460 utilities.assertEquals(
461 expect=True,
462 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700463 onpass="Group count looks correct: " + str( count ) ,
464 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800465
466 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700467 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800468
469 for dpid, values in main.count.items():
470 flowCount = values["flows"]
471 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700472 main.log.report( "Check flow count for dpid " + str( dpid ) +
473 ", should be " + str( flowCount ) )
474 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800475
Jon Hall9677ed32018-04-24 11:16:23 -0700476 main.log.report( "Check group count for dpid " + str( dpid ) +
477 ", should be " + str( groupCount ) )
478 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800479
480 return
481
482 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700483 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
484 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800485 '''
You Wangba231e72018-03-01 13:18:21 -0800486 Verify connectivity between hosts according to the ping chart
487 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800488 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800489 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800490 '''
You Wangba231e72018-03-01 13:18:21 -0800491 main.log.report( "Check host connectivity" )
492 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800493 if tag == "":
494 tag = 'CASE%d' % main.CurrentTestCaseNumber
495 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800496 main.log.debug( "Entry in ping chart: %s" % entry )
497 expect = entry[ 'expect' ]
498 if expect == "Unidirectional":
499 # Verify ping from each src host to each dst host
500 src = entry[ 'src' ]
501 dst = entry[ 'dst' ]
502 expect = main.TRUE
503 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
504 if basedOnIp:
505 if ("v4" in src[0]):
506 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
507 utilities.assert_equals( expect=expect, actual=pa,
508 onpass="IPv4 connectivity successfully tested",
509 onfail="IPv4 connectivity failed" )
510 if ("v6" in src[0]):
511 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
512 utilities.assert_equals( expect=expect, actual=pa,
513 onpass="IPv6 connectivity successfully tested",
514 onfail="IPv6 connectivity failed" )
515 else:
516 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
517 utilities.assert_equals( expect=expect, actual=pa,
518 onpass="IP connectivity successfully tested",
519 onfail="IP connectivity failed" )
520 else:
521 # Verify ping between each host pair
522 hosts = entry[ 'hosts' ]
523 try:
524 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
525 except:
526 expect = main.FALSE
527 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
528 if basedOnIp:
529 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800530 pa = utilities.retry( main.Network.pingallHosts,
531 main.FALSE if expect else main.TRUE,
532 args=(hosts,),
533 attempts=retryAttempts,
534 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800535 utilities.assert_equals( expect=expect, actual=pa,
536 onpass="IPv4 connectivity successfully tested",
537 onfail="IPv4 connectivity failed" )
538 if ("v6" in hosts[0]):
539 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
540 utilities.assert_equals( expect=expect, actual=pa,
541 onpass="IPv6 connectivity successfully tested",
542 onfail="IPv6 connectivity failed" )
543 else:
You Wangf19d9f42018-02-23 16:34:19 -0800544 pa = main.Network.pingallHosts( hosts )
545 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800546 onpass="IP connectivity successfully tested",
547 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700548 if skipOnFail and pa != expect:
549 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700550 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700551 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800552
553 if dumpflows:
554 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
555 "flows",
556 main.logdir,
557 tag + "_FlowsOn" )
558 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
559 "groups",
560 main.logdir,
561 tag + "_GroupsOn" )
562
563 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700564 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700565 """
566 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
567 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
568 Kill a link and verify ONOS can see the proper link change
569 """
Jon Halla604fd42018-05-04 14:27:27 -0700570 if sleep is None:
571 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
572 else:
573 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700574 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700575 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
576 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
577 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700578 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700579 "Waiting %s seconds for link down to be discovered" % sleep )
580 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700581 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700582 main.FALSE,
583 kwargs={ 'numoswitch': switches,
584 'numolink': links },
585 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700586 sleep=sleep )
587 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700588 utilities.assert_equals( expect=main.TRUE, actual=result,
589 onpass="Link down successful",
590 onfail="Failed to turn off link?" )
591
592 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700593 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800594 """
595 links = list of links (src, dst) to bring down.
596 """
597
598 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700599 if sleep is None:
600 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
601 else:
602 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800603
604 for end1, end2 in links:
605 main.Network.link( END1=end1, END2=end2, OPTION="down")
606 main.Network.link( END1=end2, END2=end1, OPTION="down")
607
Jon Halla604fd42018-05-04 14:27:27 -0700608 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800609 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700610 "Waiting %s seconds for links down to be discovered" % sleep )
611 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800612
613 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
614 main.FALSE,
615 kwargs={ 'numoswitch': switches,
616 'numolink': linksAfter },
617 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700618 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800619
You Wang2854bce2018-03-30 10:15:32 -0700620 utilities.assert_equals( expect=main.TRUE, actual=topology,
621 onpass="Link batch down successful",
622 onfail="Link batch down failed" )
623
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800624 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700625 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800626 """
627 links = list of link (src, dst) to bring up again.
628 """
629
630 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700631 if sleep is None:
632 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
633 else:
634 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800635
636 for end1, end2 in links:
637 main.Network.link( END1=end1, END2=end2, OPTION="up")
638 main.Network.link( END1=end2, END2=end1, OPTION="up")
639
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800640 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700641 "Waiting %s seconds for links up to be discovered" % sleep )
642 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800643
644 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
645 main.FALSE,
646 kwargs={ 'numoswitch': switches,
647 'numolink': linksAfter },
648 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700649 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800650
You Wang2854bce2018-03-30 10:15:32 -0700651 utilities.assert_equals( expect=main.TRUE, actual=topology,
652 onpass="Link batch up successful",
653 onfail="Link batch up failed" )
654
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800655 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700656 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
657 """
658 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
659 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
660 switches, links: number of expected switches and links after link change, ex.: '4', '6'
661 """
662 if sleep is None:
663 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
664 else:
665 sleep = float( sleep )
666 main.step( "Disable a batch of ports" )
667 for dpid, port in ports:
668 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
669 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
670 time.sleep( sleep )
671 if switches and links:
672 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
673 numolink=links )
674 utilities.assert_equals( expect=main.TRUE, actual=result,
675 onpass="Port down successful",
676 onfail="Port down failed" )
677
678 @staticmethod
679 def enablePortBatch( main, ports, switches, links, sleep=None ):
680 """
681 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
682 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
683 switches, links: number of expected switches and links after link change, ex.: '4', '6'
684 """
685 if sleep is None:
686 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
687 else:
688 sleep = float( sleep )
689 main.step( "Enable a batch of ports" )
690 for dpid, port in ports:
691 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
692 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
693 time.sleep( sleep )
694 if switches and links:
695 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
696 numolink=links )
697 utilities.assert_equals( expect=main.TRUE, actual=result,
698 onpass="Port up successful",
699 onfail="Port up failed" )
700
701 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700702 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700703 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700704 """
705 Params:
706 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700707 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700708 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
709 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
710 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
711 Kill a link and verify ONOS can see the proper link change
712 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700713 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700714 if sleep is None:
715 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
716 else:
717 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700718 result = False
719 count = 0
720 while True:
721 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700722 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800723 main.Network.link( END1=end1, END2=end2, OPTION="up" )
724 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700725 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700726 "Waiting %s seconds for link up to be discovered" % sleep )
727 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700728
You Wangc02d8352018-04-17 16:42:10 -0700729 if portUp:
730 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
731 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700732 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700733
Jon Halla604fd42018-05-04 14:27:27 -0700734 result = ctrl.CLI.checkStatus( numoswitch=switches,
735 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700736 if count > 5 or result:
737 break
738 utilities.assert_equals( expect=main.TRUE, actual=result,
739 onpass="Link up successful",
740 onfail="Failed to bring link up" )
741
742 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700743 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700744 """
745 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
746 Completely kill a switch and verify ONOS can see the proper change
747 """
Jon Halla604fd42018-05-04 14:27:27 -0700748 if sleep is None:
749 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
750 else:
751 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700752 switch = switch if isinstance( switch, list ) else [ switch ]
753 main.step( "Kill " + str( switch ) )
754 for s in switch:
755 main.log.info( "Stopping " + s )
756 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700757 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700758
759 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700760 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700761 sleep ) )
762 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700763 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700764 main.FALSE,
765 kwargs={ 'numoswitch': switches,
766 'numolink': links },
767 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700768 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700769 utilities.assert_equals( expect=main.TRUE, actual=topology,
770 onpass="Kill switch successful",
771 onfail="Failed to kill switch?" )
772
773 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700774 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700775 """
776 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
777 Recover a switch and verify ONOS can see the proper change
778 """
Jon Halla604fd42018-05-04 14:27:27 -0700779 if sleep is None:
780 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
781 else:
782 sleep = float( sleep )
783 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700784 switch = switch if isinstance( switch, list ) else [ switch ]
785 main.step( "Recovering " + str( switch ) )
786 for s in switch:
787 main.log.info( "Starting " + s )
788 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700789 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700790 sleep ) )
791 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700792 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700793 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700794 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700795 sleep ) )
796 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700797
Devin Lim142b5342017-07-20 15:22:39 -0700798 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700799 main.FALSE,
800 kwargs={ 'numoswitch': switches,
801 'numolink': links },
802 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700803 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700804 utilities.assert_equals( expect=main.TRUE, actual=topology,
805 onpass="Switch recovery successful",
806 onfail="Failed to recover switch?" )
807
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700808 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700809 def killRouter( main, router, sleep=None ):
810 """
811 Kill bgpd process on a quagga router
812 router: name of the router to be killed. E.g. "bgp1"
813 """
814 sleep = float( sleep )
815 main.step( "Kill " + str( router ) )
816 if hasattr( main, 'Mininet1' ):
817 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
818 main.Mininet1.handle.expect( "mininet>" )
819 else:
820 # TODO: support killing router in physical network
821 pass
822 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
823 time.sleep( sleep )
824
825 @staticmethod
826 def recoverRouter( main, router, sleep=None ):
827 """
828 Restart bgpd process on a quagga router
829 router: name of the router to be recovered. E.g. "bgp1"
830 """
831 sleep = float( sleep )
832 main.step( "Recovering " + str( router ) )
833 if hasattr( main, 'Mininet1' ):
834 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
835 main.Mininet1.handle.expect( "mininet>" )
836 else:
837 # TODO: support recovering router in physical network
838 pass
839 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
840 time.sleep( sleep )
841
842 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700843 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700844 """
845 Stop Onos-cluster.
846 Stops Mininet
847 Copies ONOS log
848 """
You Wang4cc61912018-08-28 10:10:58 -0700849 from tests.dependencies.utils import Utils
850 main.utils = Utils()
851 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700852 if hasattr( main, "scapyHosts" ):
853 scapyResult = main.TRUE
854 for host in main.scapyHosts:
855 scapyResult = host.stopScapy() and scapyResult
856 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
857 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700858 if hasattr( main, 'Mininet1' ):
859 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
860 else:
861 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700862 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
863 main.scapyHosts = []
864
You Wang5da39c82018-04-26 22:55:08 -0700865 if removeHostComponent:
866 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
867 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700868 if hasattr( main, 'Mininet1' ):
869 pass
870 else:
871 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700872 main.Network.removeHostComponent( host )
873
You Wang5df1c6d2018-04-06 18:02:02 -0700874 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700875 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700876 else:
877 main.Network.disconnectInbandHosts()
878 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700879
You Wang5df1c6d2018-04-06 18:02:02 -0700880 if copyKarafLog:
881 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700882
Devin Lim142b5342017-07-20 15:22:39 -0700883 for ctrl in main.Cluster.active():
884 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700885
886 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700887 def verifyNodes( main ):
888 """
889 Verifies Each active node in the cluster has an accurate view of other node's and their status
890
891 Params:
892 nodes, integer array with position of the ONOS nodes in the CLIs array
893 """
894 nodeResults = utilities.retry( main.Cluster.nodesCheck,
895 False,
896 attempts=10,
897 sleep=10 )
898 utilities.assert_equals( expect=True, actual=nodeResults,
899 onpass="Nodes check successful",
900 onfail="Nodes check NOT successful" )
901
902 if not nodeResults:
903 for ctrl in main.Cluster.runningNodes:
904 main.log.debug( "{} components not ACTIVE: \n{}".format(
905 ctrl.name,
906 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
907 main.log.error( "Failed to kill ONOS, stopping test" )
908 main.cleanAndExit()
909
910 @staticmethod
911 def verifyTopology( main, switches, links, expNodes ):
912 """
913 Verifies that the ONOS cluster has an acuurate view of the topology
914
915 Params:
916 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
917 """
918 main.step( "Check number of topology elements" )
919 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
920 main.FALSE,
921 kwargs={ 'numoswitch': switches,
922 'numolink': links,
923 'numoctrl': expNodes },
924 attempts=10,
925 sleep=12 )
926 utilities.assert_equals( expect=main.TRUE, actual=topology,
927 onpass="Number of topology elements are correct",
928 onfail="Unexpected number of links, switches, and/or controllers" )
929
930 @staticmethod
931 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700932 """
933 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
934 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
935 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
936 """
Jon Halla604fd42018-05-04 14:27:27 -0700937 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800938 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700939 if sleep is None:
940 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
941 else:
942 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700943
Jon Hall1efcb3f2016-08-23 13:42:15 -0700944 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700945 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700946 utilities.assert_equals( expect=main.TRUE, actual=killResult,
947 onpass="ONOS instance Killed",
948 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700949 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700950 main.Cluster.reset()
951 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700952
Devin Lim142b5342017-07-20 15:22:39 -0700953 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700954 Testcaselib.verifyNodes( main )
955 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700956
957 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700958 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700959 """
960 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
961 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
962 Recover an ONOS instance and verify the ONOS cluster can see the proper change
963 """
Jon Hall3c910162018-03-07 14:42:16 -0800964 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700965 if sleep is None:
966 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
967 else:
968 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700969 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700970 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700971 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700972 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700973 utilities.assert_equals( expect=main.TRUE, actual=isUp,
974 onpass="ONOS service is ready",
975 onfail="ONOS service did not start properly" )
976 for i in nodes:
977 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700978 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900979 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700980 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
981 commandlineTimeout=60,
982 onosStartTimeout=100 )
983 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700984 utilities.assert_equals( expect=main.TRUE,
985 actual=cliResult,
986 onpass="ONOS CLI is ready",
987 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700988
Jon Halla604fd42018-05-04 14:27:27 -0700989 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700990 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700991 Testcaselib.verifyNodes( main )
992 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700993
Devin Lim142b5342017-07-20 15:22:39 -0700994 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
995 main.FALSE,
996 attempts=10,
997 sleep=12 )
998 if ready:
999 ready = main.TRUE
1000 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001001 onpass="ONOS summary command succeded",
1002 onfail="ONOS summary command failed" )
1003 if not ready:
1004 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001005 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001006
1007 @staticmethod
1008 def addHostCfg( main ):
1009 """
1010 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001011 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001012 """
1013 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001014 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001015 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001016 hostCfg = json.load( template )
1017 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1018 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001019 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001020 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1021 subjectClass="hosts",
1022 subjectKey=urllib.quote( mac,
1023 safe='' ),
1024 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001025 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1026 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001027 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001028 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1029 subjectClass="hosts",
1030 subjectKey=urllib.quote( mac,
1031 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001032 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001033 main.pingChart.update( { 'vlan1': { "expect": "True",
1034 "hosts": [ "olt1", "vsg1" ] } } )
1035 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1036 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001037 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001038 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001039 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1040 subjectClass="apps",
1041 subjectKey="org.onosproject.segmentrouting",
1042 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001043
1044 @staticmethod
1045 def delHostCfg( main ):
1046 """
1047 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001048 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001049 """
1050 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001051 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001052 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001053 hostCfg = json.load( template )
1054 main.step( "Removing host configuration" )
1055 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001056 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001057 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1058 subjectKey=urllib.quote(
1059 mac,
1060 safe='' ),
1061 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001062 main.step( "Removing configuration" )
1063 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001064 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001065 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1066 subjectKey=urllib.quote(
1067 mac,
1068 safe='' ),
1069 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001070 main.step( "Removing vlan configuration" )
1071 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001072 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1073 subjectKey="org.onosproject.segmentrouting",
1074 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001075
1076 @staticmethod
1077 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1078 """
1079 Verifies IP address assignment from the hosts
1080 """
1081 main.step( "Verify IP address assignment from hosts" )
1082 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001083 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001084 # Find out names of disconnected hosts
1085 disconnectedHosts = []
1086 if hasattr( main, "disconnectedIpv4Hosts" ):
1087 for host in main.disconnectedIpv4Hosts:
1088 disconnectedHosts.append( host )
1089 if hasattr( main, "disconnectedIpv6Hosts" ):
1090 for host in main.disconnectedIpv6Hosts:
1091 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001092 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001093 # Exclude disconnected hosts
1094 if hostName in disconnectedHosts:
1095 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1096 continue
You Wang53dba1e2018-02-02 17:45:44 -08001097 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1098 main.FALSE,
1099 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001100 'prefix': ip,
1101 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001102 attempts=attempts,
1103 sleep=sleep )
1104 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1105 onpass="Verify network host IP succeded",
1106 onfail="Verify network host IP failed" )
1107
1108 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001109 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001110 """
1111 Verifies host IP address assignment from ONOS
1112 """
1113 main.step( "Verify host IP address assignment in ONOS" )
1114 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001115 # Find out IPs of disconnected hosts
1116 disconnectedIps = []
1117 if hasattr( main, "disconnectedIpv4Hosts" ):
1118 for host in main.disconnectedIpv4Hosts:
1119 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1120 if hasattr( main, "disconnectedIpv6Hosts" ):
1121 for host in main.disconnectedIpv6Hosts:
1122 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001123 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001124 # Exclude disconnected hosts
1125 if ip in disconnectedIps:
1126 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1127 continue
You Wang53dba1e2018-02-02 17:45:44 -08001128 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1129 main.FALSE,
1130 kwargs={ 'hostList': [ hostName ],
1131 'prefix': ip },
1132 attempts=attempts,
1133 sleep=sleep )
1134 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1135 onpass="Verify ONOS host IP succeded",
1136 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001137 if not ipResult and skipOnFail:
1138 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001139 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001140 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001141
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001142 @staticmethod
1143 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1144 """
1145 Description:
1146 Updates interface configuration in ONOS, with given IP and vlan parameters
1147 Required:
1148 * connectPoint: connect point to update configuration
1149 Optional:
1150 * ips: list of IP addresses, combined with '/xx' subnet representation,
1151 corresponding to 'ips' field in the configuration
1152 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1153 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1154 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1155 """
1156 cfg = dict()
1157 cfg[ "ports" ] = dict()
1158 cfg[ "ports" ][ connectPoint ] = dict()
1159 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1160 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1161 if untagged > 0:
1162 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1163 else:
1164 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1165 if native > 0:
1166 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1167
1168 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001169
1170 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001171 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001172 """
1173 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001174 scapyNames: list of names that will be used as component names for scapy hosts
1175 mininetNames: used when scapy host names are different from the host names
1176 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1177 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001178 """
1179 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001180 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1181 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001182 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001183 if hasattr( main, 'Mininet1' ):
1184 main.Scapy.createHostComponent( scapyName )
1185 scapyHandle = getattr( main, scapyName )
1186 if mininetNames:
1187 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1188 else:
1189 mininetName = None
1190 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001191 else:
You Wang1a704002018-11-02 17:49:18 -07001192 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001193 scapyHandle = getattr( main, scapyName )
1194 scapyHandle.connectInband()
1195 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001196 scapyHandle.startScapy()
1197 scapyHandle.updateSelf()
1198 main.log.debug( scapyHandle.name )
1199 main.log.debug( scapyHandle.hostIp )
1200 main.log.debug( scapyHandle.hostMac )
1201
1202 @staticmethod
1203 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1204 """
1205 Verify unicast traffic by pinging from source hosts to the destination IP
1206 and capturing the packets at the destination host using Scapy.
1207 srcHosts: List of host names to send the ping packets
1208 dstIp: destination IP of the ping packets
1209 dstHost: host that runs Scapy to capture the packets
1210 dstIntf: name of the interface on the destination host
1211 expect: use True if the ping is expected to be captured at destination;
1212 Otherwise False
1213 skipOnFail: skip the rest of this test case if result is not expected
1214 maxRetry: number of retries allowed
1215 """
1216 from tests.dependencies.topology import Topology
1217 try:
1218 main.topo
1219 except ( NameError, AttributeError ):
1220 main.topo = Topology()
1221 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1222 result = main.TRUE
1223 for srcHost in srcHosts:
1224 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1225 expect, maxRetry, True )
1226 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001227 result = main.FALSE
1228 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1229 utilities.assert_equals( expect=main.TRUE,
1230 actual=result,
1231 onpass="Verify traffic to {}: Pass".format( dstIp ),
1232 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1233 if skipOnFail and result != main.TRUE:
1234 Testcaselib.saveOnosDiagnostics( main )
1235 Testcaselib.cleanup( main, copyKarafLog=False )
1236 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001237
1238 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001239 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001240 """
1241 Verify multicast traffic using scapy
1242 """
You Wangc564c6f2018-05-01 15:24:57 -07001243 from tests.dependencies.topology import Topology
1244 try:
1245 main.topo
1246 except ( NameError, AttributeError ):
1247 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001248 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001249 routeData = main.multicastConfig[ routeName ]
1250 srcs = main.mcastRoutes[ routeName ][ "src" ]
1251 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1252 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1253 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001254 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001255 for src in srcs:
1256 srcEntry = routeData[ "src" ][ src ]
1257 for dst in dsts:
1258 dstEntry = routeData[ "dst" ][ dst ]
1259 sender = getattr( main, srcEntry[ "host" ] )
1260 receiver = getattr( main, dstEntry[ "host" ] )
1261 main.Network.addRoute( str( srcEntry[ "host" ] ),
1262 str( routeData[ "group" ] ),
1263 str( srcEntry[ "interface" ] ),
1264 True if routeData[ "ipVersion" ] == 6 else False )
1265 # Build the packet
1266 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1267 if routeData[ "ipVersion" ] == 4:
1268 sender.buildIP( dst=str( routeData[ "group" ] ) )
1269 elif routeData[ "ipVersion" ] == 6:
1270 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1271 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1272 sIface = srcEntry[ "interface" ]
1273 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1274 pktFilter = srcEntry[ "filter" ]
1275 pkt = srcEntry[ "packet" ]
1276 # Send packet and check received packet
1277 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001278 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001279 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001280 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1281 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001282 if not trafficResult:
1283 result = main.FALSE
1284 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1285 dstEntry[ "host" ] ) )
1286 utilities.assert_equals( expect=main.TRUE,
1287 actual=result,
1288 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1289 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001290 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001291 Testcaselib.saveOnosDiagnostics( main )
1292 Testcaselib.cleanup( main, copyKarafLog=False )
1293 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001294
1295 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001296 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001297 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1298 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001299 """
1300 Verify reachability from each host in srcList to each host in dstList
1301 """
1302 from tests.dependencies.topology import Topology
1303 try:
1304 main.topo
1305 except ( NameError, AttributeError ):
1306 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001307 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001308 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001309 utilities.assert_equals( expect=main.TRUE,
1310 actual=pingResult,
1311 onpass="{}: Pass".format( stepMsg ),
1312 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001313 if not pingResult and skipOnFail:
1314 Testcaselib.saveOnosDiagnostics( main )
1315 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1316 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001317
1318 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001319 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001320 """
1321 Verify if the specified host is discovered by ONOS on the given locations
1322 Required:
You Wang85747762018-05-11 15:51:50 -07001323 locationDict: a dictionary that maps host names to expected locations.
1324 locations could be a string or a list.
1325 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001326 Returns:
1327 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1328 """
You Wang85747762018-05-11 15:51:50 -07001329 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1330 result = main.TRUE
1331 for hostName, locations in locationDict.items():
1332 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1333 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1334 if not hostIp:
1335 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1336 if not hostIp:
1337 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1338 result = main.FALSE
1339 continue
1340 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1341 main.FALSE,
1342 args=( hostIp, locations ),
1343 attempts=retry + 1,
1344 sleep=10 )
1345 if not locationResult:
1346 result = main.FALSE
1347 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001348 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001349 onpass="Location verification passed",
1350 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001351
1352 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001353 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001354 """
1355 Move specified host from srcSw to dstSw.
1356 If srcSw and dstSw are same, the host will be moved from current port to
1357 next available port.
1358 Required:
1359 hostName: name of the host. e.g., "h1"
1360 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1361 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1362 gw: ip address of the gateway of the new location
1363 Optional:
1364 macAddr: if specified, change MAC address of the host to the specified MAC address.
1365 prefixLen: prefix length
1366 cfg: port configuration as JSON string
1367 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001368 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001369 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001370 if not hasattr( main, 'Mininet1' ):
1371 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1372 return
1373
You Wang6e5b48e2018-07-23 16:17:38 -07001374 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1375 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1376 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001377 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001378 if cfg:
1379 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1380 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001381 # Wait for the host to get RA for setting up default gateway
1382 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001383
1384 main.Mininet1.discoverHosts( [ hostName, ] )
1385
1386 # Update expectedHost when MAC address is changed.
1387 if macAddr is not None:
1388 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1389 if ipAddr is not None:
1390 for hostName, ip in main.expectedHosts[ "onos" ].items():
1391 if ip == ipAddr:
1392 vlan = hostName.split( "/" )[ -1 ]
1393 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001394 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001395 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001396
1397 @staticmethod
1398 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001399 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001400 """
1401 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1402 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1403 to next available port.
1404 Required:
1405 hostName: name of the host. e.g., "h1"
1406 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1407 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1408 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1409 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1410 gw: ip address of the gateway of the new location
1411 Optional:
1412 macAddr: if specified, change MAC address of the host to the specified MAC address.
1413 prefixLen: prefix length
1414 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001415 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001416 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001417 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001418 if not hasattr( main, 'Mininet1' ):
1419 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1420 return
1421
You Wang6e5b48e2018-07-23 16:17:38 -07001422 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1423 srcSw, srcPairSw, dstSw, dstPairSw ) )
1424 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1425 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1426 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001427 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001428 if cfg:
1429 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1430 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001431 # Wait for the host to get RA for setting up default gateway
1432 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001433
1434 main.Mininet1.discoverHosts( [ hostName, ] )
1435
1436 # Update expectedHost when MAC address is changed.
1437 if macAddr is not None:
1438 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1439 if ipAddr is not None:
1440 for hostName, ip in main.expectedHosts[ "onos" ].items():
1441 if ip == ipAddr:
1442 vlan = hostName.split( "/" )[ -1 ]
1443 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001444 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip