blob: 0d7dc4ec997a4b9249c6d3fb80c458d423fe5230 [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 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800324 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
325
Piera2a7e1b2016-10-04 11:51:43 -0700326 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700327 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700328 """
329 Check number of groups for each subnet on device deviceId and matches
330 it with an expected value. subnetDict is a dictionarty containing values
331 of the type "10.0.1.0/24" : 5.
332 """
You Wangc02f3be2018-05-18 12:14:23 -0700333 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
334 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
335 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700336
You Wangc02f3be2018-05-18 12:14:23 -0700337 result = main.TRUE
338 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700339 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700340 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700341 # this will match the group id that this flow entry points to, for example :
342 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700343 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700344 count = 0
345 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700346 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700347 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700348 if count - 1 != numberInSelect:
349 result = main.FALSE
350 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 ) )
351 utilities.assert_equals( expect=main.TRUE, actual=result,
352 onpass="All bucket numbers are as expected",
353 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700354
355 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900356 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700357 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800358 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900359 if tag == "":
360 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700361 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700362 main.FALSE,
363 kwargs={ 'min': minFlowCount },
364 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800365 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800366 if count == main.FALSE:
367 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700368 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700369 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800370 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700371 onpass="Flow count looks correct: " + str( count ),
372 onfail="Flow count looks wrong: " + str( count ) )
373
374 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700375 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700376 main.FALSE,
377 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800378 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800379 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700380 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700381 expect=main.TRUE,
382 actual=flowCheck,
383 onpass="Flow status is correct!",
384 onfail="Flow status is wrong!" )
385 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700386 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700387 "flows",
388 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900389 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700390 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700391 "groups",
392 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900393 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700394
395 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700396 def checkDevices( main, switches, tag="", sleep=10 ):
397 main.step(
398 "Check whether the switches count is equal to %s" % switches )
399 if tag == "":
400 tag = 'CASE%d' % main.CurrentTestCaseNumber
401 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
402 main.FALSE,
403 kwargs={ 'numoswitch': switches},
404 attempts=10,
405 sleep=sleep )
406 utilities.assert_equals( expect=main.TRUE, actual=result,
407 onpass="Device up successful",
408 onfail="Failed to boot up devices?" )
409
410 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800411 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
412 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800413 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
414 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
415 main.FALSE,
416 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800417 attempts=5,
418 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800419 if count == main.FALSE:
420 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800421 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800422 expect=True,
423 actual=( count > minFlowCount ),
424 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800425 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800426
427 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700428 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800429 main.step(
430 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
431 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
432 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700433 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800434 attempts=5,
435 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800436 if count == main.FALSE:
437 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800438 utilities.assertEquals(
439 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800440 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700441 onpass="Flow count looks correct: " + str( count ) ,
442 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800443
444 @staticmethod
445 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
446 main.step(
447 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
448 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
449 main.FALSE,
450 args=( dpid, groupCount, False, 1),
451 attempts=5,
452 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800453 if count == main.FALSE:
454 count = main.Cluseter.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800455 utilities.assertEquals(
456 expect=True,
457 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700458 onpass="Group count looks correct: " + str( count ) ,
459 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800460
461 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700462 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800463
464 for dpid, values in main.count.items():
465 flowCount = values["flows"]
466 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700467 main.log.report( "Check flow count for dpid " + str( dpid ) +
468 ", should be " + str( flowCount ) )
469 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800470
Jon Hall9677ed32018-04-24 11:16:23 -0700471 main.log.report( "Check group count for dpid " + str( dpid ) +
472 ", should be " + str( groupCount ) )
473 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800474
475 return
476
477 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700478 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
479 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800480 '''
You Wangba231e72018-03-01 13:18:21 -0800481 Verify connectivity between hosts according to the ping chart
482 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800483 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800484 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800485 '''
You Wangba231e72018-03-01 13:18:21 -0800486 main.log.report( "Check host connectivity" )
487 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800488 if tag == "":
489 tag = 'CASE%d' % main.CurrentTestCaseNumber
490 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800491 main.log.debug( "Entry in ping chart: %s" % entry )
492 expect = entry[ 'expect' ]
493 if expect == "Unidirectional":
494 # Verify ping from each src host to each dst host
495 src = entry[ 'src' ]
496 dst = entry[ 'dst' ]
497 expect = main.TRUE
498 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
499 if basedOnIp:
500 if ("v4" in src[0]):
501 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
502 utilities.assert_equals( expect=expect, actual=pa,
503 onpass="IPv4 connectivity successfully tested",
504 onfail="IPv4 connectivity failed" )
505 if ("v6" in src[0]):
506 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
507 utilities.assert_equals( expect=expect, actual=pa,
508 onpass="IPv6 connectivity successfully tested",
509 onfail="IPv6 connectivity failed" )
510 else:
511 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
512 utilities.assert_equals( expect=expect, actual=pa,
513 onpass="IP connectivity successfully tested",
514 onfail="IP connectivity failed" )
515 else:
516 # Verify ping between each host pair
517 hosts = entry[ 'hosts' ]
518 try:
519 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
520 except:
521 expect = main.FALSE
522 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
523 if basedOnIp:
524 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800525 pa = utilities.retry( main.Network.pingallHosts,
526 main.FALSE if expect else main.TRUE,
527 args=(hosts,),
528 attempts=retryAttempts,
529 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800530 utilities.assert_equals( expect=expect, actual=pa,
531 onpass="IPv4 connectivity successfully tested",
532 onfail="IPv4 connectivity failed" )
533 if ("v6" in hosts[0]):
534 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
535 utilities.assert_equals( expect=expect, actual=pa,
536 onpass="IPv6 connectivity successfully tested",
537 onfail="IPv6 connectivity failed" )
538 else:
You Wangf19d9f42018-02-23 16:34:19 -0800539 pa = main.Network.pingallHosts( hosts )
540 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800541 onpass="IP connectivity successfully tested",
542 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700543 if skipOnFail and pa != expect:
544 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700545 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700546 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800547
548 if dumpflows:
549 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
550 "flows",
551 main.logdir,
552 tag + "_FlowsOn" )
553 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
554 "groups",
555 main.logdir,
556 tag + "_GroupsOn" )
557
558 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700559 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700560 """
561 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
562 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
563 Kill a link and verify ONOS can see the proper link change
564 """
Jon Halla604fd42018-05-04 14:27:27 -0700565 if sleep is None:
566 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
567 else:
568 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700569 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700570 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
571 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
572 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700573 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700574 "Waiting %s seconds for link down to be discovered" % sleep )
575 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700576 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700577 main.FALSE,
578 kwargs={ 'numoswitch': switches,
579 'numolink': links },
580 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700581 sleep=sleep )
582 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700583 utilities.assert_equals( expect=main.TRUE, actual=result,
584 onpass="Link down successful",
585 onfail="Failed to turn off link?" )
586
587 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700588 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800589 """
590 links = list of links (src, dst) to bring down.
591 """
592
593 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700594 if sleep is None:
595 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
596 else:
597 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800598
599 for end1, end2 in links:
600 main.Network.link( END1=end1, END2=end2, OPTION="down")
601 main.Network.link( END1=end2, END2=end1, OPTION="down")
602
Jon Halla604fd42018-05-04 14:27:27 -0700603 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800604 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700605 "Waiting %s seconds for links down to be discovered" % sleep )
606 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800607
608 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
609 main.FALSE,
610 kwargs={ 'numoswitch': switches,
611 'numolink': linksAfter },
612 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700613 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800614
You Wang2854bce2018-03-30 10:15:32 -0700615 utilities.assert_equals( expect=main.TRUE, actual=topology,
616 onpass="Link batch down successful",
617 onfail="Link batch down failed" )
618
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800619 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700620 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800621 """
622 links = list of link (src, dst) to bring up again.
623 """
624
625 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700626 if sleep is None:
627 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
628 else:
629 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800630
631 for end1, end2 in links:
632 main.Network.link( END1=end1, END2=end2, OPTION="up")
633 main.Network.link( END1=end2, END2=end1, OPTION="up")
634
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800635 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700636 "Waiting %s seconds for links up to be discovered" % sleep )
637 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800638
639 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
640 main.FALSE,
641 kwargs={ 'numoswitch': switches,
642 'numolink': linksAfter },
643 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700644 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800645
You Wang2854bce2018-03-30 10:15:32 -0700646 utilities.assert_equals( expect=main.TRUE, actual=topology,
647 onpass="Link batch up successful",
648 onfail="Link batch up failed" )
649
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800650 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700651 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
652 """
653 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
654 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
655 switches, links: number of expected switches and links after link change, ex.: '4', '6'
656 """
657 if sleep is None:
658 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
659 else:
660 sleep = float( sleep )
661 main.step( "Disable a batch of ports" )
662 for dpid, port in ports:
663 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
664 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
665 time.sleep( sleep )
666 if switches and links:
667 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
668 numolink=links )
669 utilities.assert_equals( expect=main.TRUE, actual=result,
670 onpass="Port down successful",
671 onfail="Port down failed" )
672
673 @staticmethod
674 def enablePortBatch( main, ports, switches, links, sleep=None ):
675 """
676 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
677 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
678 switches, links: number of expected switches and links after link change, ex.: '4', '6'
679 """
680 if sleep is None:
681 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
682 else:
683 sleep = float( sleep )
684 main.step( "Enable a batch of ports" )
685 for dpid, port in ports:
686 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
687 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
688 time.sleep( sleep )
689 if switches and links:
690 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
691 numolink=links )
692 utilities.assert_equals( expect=main.TRUE, actual=result,
693 onpass="Port up successful",
694 onfail="Port up failed" )
695
696 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700697 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700698 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700699 """
700 Params:
701 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700702 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700703 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
704 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
705 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
706 Kill a link and verify ONOS can see the proper link change
707 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700708 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700709 if sleep is None:
710 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
711 else:
712 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700713 result = False
714 count = 0
715 while True:
716 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700717 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800718 main.Network.link( END1=end1, END2=end2, OPTION="up" )
719 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700720 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700721 "Waiting %s seconds for link up to be discovered" % sleep )
722 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700723
You Wangc02d8352018-04-17 16:42:10 -0700724 if portUp:
725 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
726 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700727 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700728
Jon Halla604fd42018-05-04 14:27:27 -0700729 result = ctrl.CLI.checkStatus( numoswitch=switches,
730 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700731 if count > 5 or result:
732 break
733 utilities.assert_equals( expect=main.TRUE, actual=result,
734 onpass="Link up successful",
735 onfail="Failed to bring link up" )
736
737 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700738 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700739 """
740 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
741 Completely kill a switch and verify ONOS can see the proper change
742 """
Jon Halla604fd42018-05-04 14:27:27 -0700743 if sleep is None:
744 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
745 else:
746 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700747 switch = switch if isinstance( switch, list ) else [ switch ]
748 main.step( "Kill " + str( switch ) )
749 for s in switch:
750 main.log.info( "Stopping " + s )
751 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700752 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700753
754 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700755 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700756 sleep ) )
757 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700758 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700759 main.FALSE,
760 kwargs={ 'numoswitch': switches,
761 'numolink': links },
762 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700763 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700764 utilities.assert_equals( expect=main.TRUE, actual=topology,
765 onpass="Kill switch successful",
766 onfail="Failed to kill switch?" )
767
768 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700769 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700770 """
771 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
772 Recover a switch and verify ONOS can see the proper change
773 """
Jon Halla604fd42018-05-04 14:27:27 -0700774 if sleep is None:
775 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
776 else:
777 sleep = float( sleep )
778 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700779 switch = switch if isinstance( switch, list ) else [ switch ]
780 main.step( "Recovering " + str( switch ) )
781 for s in switch:
782 main.log.info( "Starting " + s )
783 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700784 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700785 sleep ) )
786 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700787 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700788 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700789 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700790 sleep ) )
791 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700792
Devin Lim142b5342017-07-20 15:22:39 -0700793 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700794 main.FALSE,
795 kwargs={ 'numoswitch': switches,
796 'numolink': links },
797 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700798 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700799 utilities.assert_equals( expect=main.TRUE, actual=topology,
800 onpass="Switch recovery successful",
801 onfail="Failed to recover switch?" )
802
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700803 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700804 def killRouter( main, router, sleep=None ):
805 """
806 Kill bgpd process on a quagga router
807 router: name of the router to be killed. E.g. "bgp1"
808 """
809 sleep = float( sleep )
810 main.step( "Kill " + str( router ) )
811 if hasattr( main, 'Mininet1' ):
812 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
813 main.Mininet1.handle.expect( "mininet>" )
814 else:
815 # TODO: support killing router in physical network
816 pass
817 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
818 time.sleep( sleep )
819
820 @staticmethod
821 def recoverRouter( main, router, sleep=None ):
822 """
823 Restart bgpd process on a quagga router
824 router: name of the router to be recovered. E.g. "bgp1"
825 """
826 sleep = float( sleep )
827 main.step( "Recovering " + str( router ) )
828 if hasattr( main, 'Mininet1' ):
829 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
830 main.Mininet1.handle.expect( "mininet>" )
831 else:
832 # TODO: support recovering router in physical network
833 pass
834 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
835 time.sleep( sleep )
836
837 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700838 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700839 """
840 Stop Onos-cluster.
841 Stops Mininet
842 Copies ONOS log
843 """
You Wang4cc61912018-08-28 10:10:58 -0700844 from tests.dependencies.utils import Utils
845 main.utils = Utils()
846 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700847 if hasattr( main, "scapyHosts" ):
848 scapyResult = main.TRUE
849 for host in main.scapyHosts:
850 scapyResult = host.stopScapy() and scapyResult
851 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
852 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700853 if hasattr( main, 'Mininet1' ):
854 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
855 else:
856 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700857 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
858 main.scapyHosts = []
859
You Wang5da39c82018-04-26 22:55:08 -0700860 if removeHostComponent:
861 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
862 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700863 if hasattr( main, 'Mininet1' ):
864 pass
865 else:
866 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700867 main.Network.removeHostComponent( host )
868
You Wang5df1c6d2018-04-06 18:02:02 -0700869 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700870 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700871 else:
872 main.Network.disconnectInbandHosts()
873 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700874
You Wang5df1c6d2018-04-06 18:02:02 -0700875 if copyKarafLog:
876 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700877
Devin Lim142b5342017-07-20 15:22:39 -0700878 for ctrl in main.Cluster.active():
879 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700880
881 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700882 def verifyNodes( main ):
883 """
884 Verifies Each active node in the cluster has an accurate view of other node's and their status
885
886 Params:
887 nodes, integer array with position of the ONOS nodes in the CLIs array
888 """
889 nodeResults = utilities.retry( main.Cluster.nodesCheck,
890 False,
891 attempts=10,
892 sleep=10 )
893 utilities.assert_equals( expect=True, actual=nodeResults,
894 onpass="Nodes check successful",
895 onfail="Nodes check NOT successful" )
896
897 if not nodeResults:
898 for ctrl in main.Cluster.runningNodes:
899 main.log.debug( "{} components not ACTIVE: \n{}".format(
900 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800901 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -0800902 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -0700903 main.cleanAndExit()
904
905 @staticmethod
906 def verifyTopology( main, switches, links, expNodes ):
907 """
908 Verifies that the ONOS cluster has an acuurate view of the topology
909
910 Params:
911 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
912 """
913 main.step( "Check number of topology elements" )
914 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
915 main.FALSE,
916 kwargs={ 'numoswitch': switches,
917 'numolink': links,
918 'numoctrl': expNodes },
919 attempts=10,
920 sleep=12 )
921 utilities.assert_equals( expect=main.TRUE, actual=topology,
922 onpass="Number of topology elements are correct",
923 onfail="Unexpected number of links, switches, and/or controllers" )
924
925 @staticmethod
926 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700927 """
928 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
929 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
930 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
931 """
Jon Halla604fd42018-05-04 14:27:27 -0700932 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800933 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700934 if sleep is None:
935 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
936 else:
937 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700938
Jon Hall1efcb3f2016-08-23 13:42:15 -0700939 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700940 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700941 utilities.assert_equals( expect=main.TRUE, actual=killResult,
942 onpass="ONOS instance Killed",
943 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700944 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700945 main.Cluster.reset()
946 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700947
Devin Lim142b5342017-07-20 15:22:39 -0700948 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700949 Testcaselib.verifyNodes( main )
950 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700951
952 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700953 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700954 """
955 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
956 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
957 Recover an ONOS instance and verify the ONOS cluster can see the proper change
958 """
Jon Hall3c910162018-03-07 14:42:16 -0800959 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700960 if sleep is None:
961 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
962 else:
963 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700964 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700965 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700966 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700967 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700968 utilities.assert_equals( expect=main.TRUE, actual=isUp,
969 onpass="ONOS service is ready",
970 onfail="ONOS service did not start properly" )
971 for i in nodes:
972 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700973 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900974 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700975 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
976 commandlineTimeout=60,
977 onosStartTimeout=100 )
978 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700979 utilities.assert_equals( expect=main.TRUE,
980 actual=cliResult,
981 onpass="ONOS CLI is ready",
982 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700983
Jon Halla604fd42018-05-04 14:27:27 -0700984 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700985 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700986 Testcaselib.verifyNodes( main )
987 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700988
Devin Lim142b5342017-07-20 15:22:39 -0700989 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
990 main.FALSE,
991 attempts=10,
992 sleep=12 )
993 if ready:
994 ready = main.TRUE
995 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700996 onpass="ONOS summary command succeded",
997 onfail="ONOS summary command failed" )
998 if not ready:
999 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001000 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001001
1002 @staticmethod
1003 def addHostCfg( main ):
1004 """
1005 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001006 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001007 """
1008 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001009 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001010 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001011 hostCfg = json.load( template )
1012 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1013 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001014 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001015 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1016 subjectClass="hosts",
1017 subjectKey=urllib.quote( mac,
1018 safe='' ),
1019 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001020 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1021 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001022 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001023 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1024 subjectClass="hosts",
1025 subjectKey=urllib.quote( mac,
1026 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001027 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001028 main.pingChart.update( { 'vlan1': { "expect": "True",
1029 "hosts": [ "olt1", "vsg1" ] } } )
1030 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1031 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001032 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001033 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001034 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1035 subjectClass="apps",
1036 subjectKey="org.onosproject.segmentrouting",
1037 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001038
1039 @staticmethod
1040 def delHostCfg( main ):
1041 """
1042 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001043 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001044 """
1045 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001046 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001047 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001048 hostCfg = json.load( template )
1049 main.step( "Removing host configuration" )
1050 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001051 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001052 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1053 subjectKey=urllib.quote(
1054 mac,
1055 safe='' ),
1056 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001057 main.step( "Removing configuration" )
1058 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001059 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001060 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1061 subjectKey=urllib.quote(
1062 mac,
1063 safe='' ),
1064 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001065 main.step( "Removing vlan configuration" )
1066 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001067 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1068 subjectKey="org.onosproject.segmentrouting",
1069 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001070
1071 @staticmethod
1072 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1073 """
1074 Verifies IP address assignment from the hosts
1075 """
1076 main.step( "Verify IP address assignment from hosts" )
1077 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001078 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001079 # Find out names of disconnected hosts
1080 disconnectedHosts = []
1081 if hasattr( main, "disconnectedIpv4Hosts" ):
1082 for host in main.disconnectedIpv4Hosts:
1083 disconnectedHosts.append( host )
1084 if hasattr( main, "disconnectedIpv6Hosts" ):
1085 for host in main.disconnectedIpv6Hosts:
1086 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001087 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001088 # Exclude disconnected hosts
1089 if hostName in disconnectedHosts:
1090 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1091 continue
You Wang53dba1e2018-02-02 17:45:44 -08001092 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1093 main.FALSE,
1094 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001095 'prefix': ip,
1096 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001097 attempts=attempts,
1098 sleep=sleep )
1099 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1100 onpass="Verify network host IP succeded",
1101 onfail="Verify network host IP failed" )
1102
1103 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001104 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001105 """
1106 Verifies host IP address assignment from ONOS
1107 """
1108 main.step( "Verify host IP address assignment in ONOS" )
1109 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001110 # Find out IPs of disconnected hosts
1111 disconnectedIps = []
1112 if hasattr( main, "disconnectedIpv4Hosts" ):
1113 for host in main.disconnectedIpv4Hosts:
1114 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1115 if hasattr( main, "disconnectedIpv6Hosts" ):
1116 for host in main.disconnectedIpv6Hosts:
1117 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001118 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001119 # Exclude disconnected hosts
1120 if ip in disconnectedIps:
1121 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1122 continue
You Wang53dba1e2018-02-02 17:45:44 -08001123 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1124 main.FALSE,
1125 kwargs={ 'hostList': [ hostName ],
1126 'prefix': ip },
1127 attempts=attempts,
1128 sleep=sleep )
1129 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1130 onpass="Verify ONOS host IP succeded",
1131 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001132 if not ipResult and skipOnFail:
1133 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001134 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001135 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001136
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001137 @staticmethod
1138 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1139 """
1140 Description:
1141 Updates interface configuration in ONOS, with given IP and vlan parameters
1142 Required:
1143 * connectPoint: connect point to update configuration
1144 Optional:
1145 * ips: list of IP addresses, combined with '/xx' subnet representation,
1146 corresponding to 'ips' field in the configuration
1147 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1148 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1149 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1150 """
1151 cfg = dict()
1152 cfg[ "ports" ] = dict()
1153 cfg[ "ports" ][ connectPoint ] = dict()
1154 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1155 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1156 if untagged > 0:
1157 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1158 else:
1159 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1160 if native > 0:
1161 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1162
1163 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001164
1165 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001166 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001167 """
1168 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001169 scapyNames: list of names that will be used as component names for scapy hosts
1170 mininetNames: used when scapy host names are different from the host names
1171 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1172 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001173 """
1174 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001175 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1176 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001177 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001178 if hasattr( main, 'Mininet1' ):
1179 main.Scapy.createHostComponent( scapyName )
1180 scapyHandle = getattr( main, scapyName )
1181 if mininetNames:
1182 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1183 else:
1184 mininetName = None
1185 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001186 else:
You Wang0fc21702018-11-02 17:49:18 -07001187 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001188 scapyHandle = getattr( main, scapyName )
1189 scapyHandle.connectInband()
1190 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001191 scapyHandle.startScapy()
1192 scapyHandle.updateSelf()
1193 main.log.debug( scapyHandle.name )
1194 main.log.debug( scapyHandle.hostIp )
1195 main.log.debug( scapyHandle.hostMac )
1196
1197 @staticmethod
1198 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1199 """
1200 Verify unicast traffic by pinging from source hosts to the destination IP
1201 and capturing the packets at the destination host using Scapy.
1202 srcHosts: List of host names to send the ping packets
1203 dstIp: destination IP of the ping packets
1204 dstHost: host that runs Scapy to capture the packets
1205 dstIntf: name of the interface on the destination host
1206 expect: use True if the ping is expected to be captured at destination;
1207 Otherwise False
1208 skipOnFail: skip the rest of this test case if result is not expected
1209 maxRetry: number of retries allowed
1210 """
1211 from tests.dependencies.topology import Topology
1212 try:
1213 main.topo
1214 except ( NameError, AttributeError ):
1215 main.topo = Topology()
1216 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1217 result = main.TRUE
1218 for srcHost in srcHosts:
1219 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1220 expect, maxRetry, True )
1221 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001222 result = main.FALSE
1223 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1224 utilities.assert_equals( expect=main.TRUE,
1225 actual=result,
1226 onpass="Verify traffic to {}: Pass".format( dstIp ),
1227 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1228 if skipOnFail and result != main.TRUE:
1229 Testcaselib.saveOnosDiagnostics( main )
1230 Testcaselib.cleanup( main, copyKarafLog=False )
1231 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001232
1233 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001234 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001235 """
1236 Verify multicast traffic using scapy
1237 """
You Wangc564c6f2018-05-01 15:24:57 -07001238 from tests.dependencies.topology import Topology
1239 try:
1240 main.topo
1241 except ( NameError, AttributeError ):
1242 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001243 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001244 routeData = main.multicastConfig[ routeName ]
1245 srcs = main.mcastRoutes[ routeName ][ "src" ]
1246 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1247 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1248 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001249 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001250 for src in srcs:
1251 srcEntry = routeData[ "src" ][ src ]
1252 for dst in dsts:
1253 dstEntry = routeData[ "dst" ][ dst ]
1254 sender = getattr( main, srcEntry[ "host" ] )
1255 receiver = getattr( main, dstEntry[ "host" ] )
1256 main.Network.addRoute( str( srcEntry[ "host" ] ),
1257 str( routeData[ "group" ] ),
1258 str( srcEntry[ "interface" ] ),
1259 True if routeData[ "ipVersion" ] == 6 else False )
1260 # Build the packet
1261 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1262 if routeData[ "ipVersion" ] == 4:
1263 sender.buildIP( dst=str( routeData[ "group" ] ) )
1264 elif routeData[ "ipVersion" ] == 6:
1265 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1266 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1267 sIface = srcEntry[ "interface" ]
1268 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1269 pktFilter = srcEntry[ "filter" ]
1270 pkt = srcEntry[ "packet" ]
1271 # Send packet and check received packet
1272 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001273 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001274 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001275 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1276 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001277 if not trafficResult:
1278 result = main.FALSE
1279 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1280 dstEntry[ "host" ] ) )
1281 utilities.assert_equals( expect=main.TRUE,
1282 actual=result,
1283 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1284 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001285 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001286 Testcaselib.saveOnosDiagnostics( main )
1287 Testcaselib.cleanup( main, copyKarafLog=False )
1288 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001289
1290 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001291 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001292 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1293 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001294 """
1295 Verify reachability from each host in srcList to each host in dstList
1296 """
1297 from tests.dependencies.topology import Topology
1298 try:
1299 main.topo
1300 except ( NameError, AttributeError ):
1301 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001302 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001303 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001304 utilities.assert_equals( expect=main.TRUE,
1305 actual=pingResult,
1306 onpass="{}: Pass".format( stepMsg ),
1307 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001308 if not pingResult and skipOnFail:
1309 Testcaselib.saveOnosDiagnostics( main )
1310 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1311 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001312
1313 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001314 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001315 """
1316 Verify if the specified host is discovered by ONOS on the given locations
1317 Required:
You Wang85747762018-05-11 15:51:50 -07001318 locationDict: a dictionary that maps host names to expected locations.
1319 locations could be a string or a list.
1320 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001321 Returns:
1322 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1323 """
You Wang85747762018-05-11 15:51:50 -07001324 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1325 result = main.TRUE
1326 for hostName, locations in locationDict.items():
1327 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1328 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1329 if not hostIp:
1330 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1331 if not hostIp:
1332 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1333 result = main.FALSE
1334 continue
1335 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1336 main.FALSE,
1337 args=( hostIp, locations ),
1338 attempts=retry + 1,
1339 sleep=10 )
1340 if not locationResult:
1341 result = main.FALSE
1342 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001343 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001344 onpass="Location verification passed",
1345 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001346
1347 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001348 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001349 """
1350 Move specified host from srcSw to dstSw.
1351 If srcSw and dstSw are same, the host will be moved from current port to
1352 next available port.
1353 Required:
1354 hostName: name of the host. e.g., "h1"
1355 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1356 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1357 gw: ip address of the gateway of the new location
1358 Optional:
1359 macAddr: if specified, change MAC address of the host to the specified MAC address.
1360 prefixLen: prefix length
1361 cfg: port configuration as JSON string
1362 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001363 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001364 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001365 if not hasattr( main, 'Mininet1' ):
1366 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1367 return
1368
You Wang6e5b48e2018-07-23 16:17:38 -07001369 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1370 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1371 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001372 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001373 if cfg:
1374 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1375 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001376 # Wait for the host to get RA for setting up default gateway
1377 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001378
1379 main.Mininet1.discoverHosts( [ hostName, ] )
1380
1381 # Update expectedHost when MAC address is changed.
1382 if macAddr is not None:
1383 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1384 if ipAddr is not None:
1385 for hostName, ip in main.expectedHosts[ "onos" ].items():
1386 if ip == ipAddr:
1387 vlan = hostName.split( "/" )[ -1 ]
1388 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001389 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001390 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001391
1392 @staticmethod
1393 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001394 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001395 """
1396 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1397 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1398 to next available port.
1399 Required:
1400 hostName: name of the host. e.g., "h1"
1401 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1402 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1403 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1404 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1405 gw: ip address of the gateway of the new location
1406 Optional:
1407 macAddr: if specified, change MAC address of the host to the specified MAC address.
1408 prefixLen: prefix length
1409 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001410 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001411 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001412 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001413 if not hasattr( main, 'Mininet1' ):
1414 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1415 return
1416
You Wang6e5b48e2018-07-23 16:17:38 -07001417 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1418 srcSw, srcPairSw, dstSw, dstPairSw ) )
1419 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1420 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1421 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001422 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001423 if cfg:
1424 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1425 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001426 # Wait for the host to get RA for setting up default gateway
1427 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001428
1429 main.Mininet1.discoverHosts( [ hostName, ] )
1430
1431 # Update expectedHost when MAC address is changed.
1432 if macAddr is not None:
1433 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1434 if ipAddr is not None:
1435 for hostName, ip in main.expectedHosts[ "onos" ].items():
1436 if ip == ipAddr:
1437 vlan = hostName.split( "/" )[ -1 ]
1438 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001439 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip