blob: 74b2fc1bb90f9ecc9a83a84bf463762c3ad443c5 [file] [log] [blame]
Jon Hall85794ff2015-07-08 14:12:30 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2015 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"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070021"""
Jon Hall85794ff2015-07-08 14:12:30 -070022Description: This test is to determine if a single
23 instance ONOS 'cluster' can handle a restart
24
25List of test cases:
26CASE1: Compile ONOS and push it to the test machines
27CASE2: Assign devices to controllers
28CASE21: Assign mastership to controllers
29CASE3: Assign intents
30CASE4: Ping across added host intents
31CASE5: Reading state of ONOS
32CASE6: The Failure case.
33CASE7: Check state after control plane failure
34CASE8: Compare topo
35CASE9: Link s3-s28 down
36CASE10: Link s3-s28 up
37CASE11: Switch down
38CASE12: Switch up
39CASE13: Clean up
40CASE14: start election app on all onos nodes
41CASE15: Check that Leadership Election is still functional
42CASE16: Install Distributed Primitives app
43CASE17: Check for basic functionality with distributed primitives
44"""
Jon Hall85794ff2015-07-08 14:12:30 -070045class HAsingleInstanceRestart:
46
47 def __init__( self ):
48 self.default = ''
49
50 def CASE1( self, main ):
51 """
52 CASE1 is to compile ONOS and push it to the test machines
53
54 Startup sequence:
55 cell <name>
56 onos-verify-cell
57 NOTE: temporary - onos-remove-raft-logs
58 onos-uninstall
59 start mininet
60 git pull
61 mvn clean install
62 onos-package
63 onos-install -f
64 onos-wait-for-start
65 start cli sessions
66 start tcpdump
67 """
Jon Halle1a3b752015-07-22 13:02:46 -070068 import imp
Jon Hallf3d16e72015-12-16 17:45:08 -080069 import time
Jon Halla440e872016-03-31 15:15:50 -070070 import json
Jon Hall85794ff2015-07-08 14:12:30 -070071 main.log.info( "ONOS Single node cluster restart " +
72 "HA test - initialization" )
73 main.case( "Setting up test environment" )
Jon Hall783bbf92015-07-23 14:33:19 -070074 main.caseExplanation = "Setup the test environment including " +\
Jon Hall85794ff2015-07-08 14:12:30 -070075 "installing ONOS, starting Mininet and ONOS" +\
76 "cli sessions."
Jon Hall85794ff2015-07-08 14:12:30 -070077
Devin Lim142b5342017-07-20 15:22:39 -070078 # set global variables
Devin Lim58046fa2017-07-05 16:55:00 -070079 # These are for csv plotting in jenkins
80 main.HAlabels = []
81 main.HAdata = []
Jon Halle1a3b752015-07-22 13:02:46 -070082 try:
Devin Lim142b5342017-07-20 15:22:39 -070083 from tests.dependencies.ONOSSetup import ONOSSetup
84 main.testSetUp = ONOSSetup()
85 except ImportError:
86 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070087 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -070088 main.testSetUp.envSetupDescription()
89 try:
Jon Hall53c5e662016-04-13 16:06:56 -070090 from tests.HA.dependencies.HA import HA
Jon Hall41d39f12016-04-11 22:54:35 -070091 main.HA = HA()
Devin Lim142b5342017-07-20 15:22:39 -070092 # load some variables from the params file
93 cellName = main.params[ 'ENV' ][ 'cellName' ]
94 main.apps = main.params[ 'ENV' ][ 'appString' ]
95 main.numCtrls = int( main.params[ 'num_controllers' ] )
96 stepResult = main.testSetUp.envSetup()
97 except Exception as e:
98 main.testSetUp.envSetupException( e )
99 main.testSetUp.evnSetupConclusion( stepResult )
Devin Lim142b5342017-07-20 15:22:39 -0700100 main.Cluster.setRunningNode( int( main.params[ 'num_controllers' ] ) )
101 ip = main.Cluster.getIps( allNode=True )
102 main.testSetUp.ONOSSetUp( main.Mininet1, main.Cluster, cellName="SingleHA", removeLog=True,
103 extraApply=[ main.testSetUp.createApplyCell,
104 main.HA.startingMininet,
105 main.testSetUp.createApplyCell ],
Jon Hall4f360bc2017-09-07 10:19:52 -0700106 applyArgs=[ [ main.Cluster, True, cellName, main.Mininet1, True, ip ],
107 None,
108 [ main.Cluster, True, "SingleHA", main.Mininet1,
109 True, main.Cluster.runningNodes[ 0 ].ipAddress ] ] )
Jon Hall85794ff2015-07-08 14:12:30 -0700110
Devin Lim58046fa2017-07-05 16:55:00 -0700111 main.HA.initialSetUp()
Jon Hall9d2dcad2016-04-08 10:15:20 -0700112
Jon Hall85794ff2015-07-08 14:12:30 -0700113 def CASE2( self, main ):
114 """
115 Assign devices to controllers
116 """
Devin Lim58046fa2017-07-05 16:55:00 -0700117 main.HA.assignDevices( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700118
119 def CASE21( self, main ):
120 """
121 Assign mastership to controllers
122 """
Devin Lim58046fa2017-07-05 16:55:00 -0700123 main.HA.assignMastership( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700124
125 def CASE3( self, main ):
126 """
127 Assign intents
128 """
Devin Lim58046fa2017-07-05 16:55:00 -0700129 main.HA.assignIntents( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700130
131 def CASE4( self, main ):
132 """
133 Ping across added host intents
134 """
Jon Hallca319892017-06-15 15:25:22 -0700135 main.HA.pingAcrossHostIntent( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700136
137 def CASE5( self, main ):
138 """
139 Reading state of ONOS
140 """
141 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700142 assert main, "main not defined"
143 assert utilities.assert_equals, "utilities.assert_equals not defined"
144
145 main.case( "Setting up and gathering data for current state" )
146 # The general idea for this test case is to pull the state of
147 # ( intents,flows, topology,... ) from each ONOS node
148 # We can then compare them with each other and also with past states
149
150 main.step( "Check that each switch has a master" )
151 global mastershipState
152 mastershipState = '[]'
153
154 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700155 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700156
157 main.step( "Get the Mastership of each switch" )
Devin Lim142b5342017-07-20 15:22:39 -0700158 main.HA.checkTheRole()
Jon Hall85794ff2015-07-08 14:12:30 -0700159
160 main.step( "Get the intents from each controller" )
161 global intentState
162 intentState = []
Devin Lim142b5342017-07-20 15:22:39 -0700163 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700164 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700165 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700166 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700167 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700168 else:
169 intentCheck = main.TRUE
170
171 main.step( "Get the flows from each controller" )
172 global flowState
173 flowState = []
174 flowCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700175 ONOSFlows = main.Cluster.runningNodes[ 0 ].CLI.flows( jsonFormat=True )
176 if "Error" in ONOSFlows or not ONOSFlows:
Jon Hall85794ff2015-07-08 14:12:30 -0700177 main.log.error( "Error in getting ONOS flows" )
Devin Lim142b5342017-07-20 15:22:39 -0700178 main.log.warn( "ONOS1 flows repsponse: " + ONOSFlows )
Jon Hall85794ff2015-07-08 14:12:30 -0700179 else:
180 # TODO: Do a better check, maybe compare flows on switches?
Devin Lim142b5342017-07-20 15:22:39 -0700181 flowState = ONOSFlows
Jon Hall85794ff2015-07-08 14:12:30 -0700182 flowCheck = main.TRUE
183
184 main.step( "Get the OF Table entries" )
185 global flows
186 flows = []
187 for i in range( 1, 29 ):
GlennRC68467eb2015-11-16 18:01:01 -0800188 flows.append( main.Mininet1.getFlowTable( "s" + str( i ), version="1.3", debug=False ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700189 if flowCheck == main.FALSE:
190 for table in flows:
191 main.log.warn( table )
192 # TODO: Compare switch flow tables with ONOS flow tables
193
194 main.step( "Collecting topology information from ONOS" )
195 devices = []
Devin Lim142b5342017-07-20 15:22:39 -0700196 devices.append( main.Cluster.runningNodes[ 0 ].CLI.devices() )
Jon Hall85794ff2015-07-08 14:12:30 -0700197 hosts = []
Devin Lim142b5342017-07-20 15:22:39 -0700198 hosts.append( json.loads( main.Cluster.runningNodes[ 0 ].CLI.hosts() ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700199 ports = []
Devin Lim142b5342017-07-20 15:22:39 -0700200 ports.append( main.Cluster.runningNodes[ 0 ].CLI.ports() )
Jon Hall85794ff2015-07-08 14:12:30 -0700201 links = []
Devin Lim142b5342017-07-20 15:22:39 -0700202 links.append( main.Cluster.runningNodes[ 0 ].CLI.links() )
Jon Hall85794ff2015-07-08 14:12:30 -0700203 clusters = []
Devin Lim142b5342017-07-20 15:22:39 -0700204 clusters.append( main.Cluster.runningNodes[ 0 ].CLI.clusters() )
Jon Hall85794ff2015-07-08 14:12:30 -0700205
206 main.step( "Each host has an IP address" )
207 ipResult = main.TRUE
208 for controller in range( 0, len( hosts ) ):
Devin Lim142b5342017-07-20 15:22:39 -0700209 controllerStr = str( main.Cluster.active( controller ) )
Jon Halla440e872016-03-31 15:15:50 -0700210 if hosts[ controller ]:
211 for host in hosts[ controller ]:
Jon Hallf37d44d2017-05-24 10:37:30 -0700212 if not host.get( 'ipAddresses', [] ):
Jon Halla440e872016-03-31 15:15:50 -0700213 main.log.error( "Error with host ips on controller" +
214 controllerStr + ": " + str( host ) )
215 ipResult = main.FALSE
Jon Hall85794ff2015-07-08 14:12:30 -0700216 utilities.assert_equals(
217 expect=main.TRUE,
218 actual=ipResult,
219 onpass="The ips of the hosts aren't empty",
220 onfail="The ip of at least one host is missing" )
221
222 # there should always only be one cluster
223 main.step( "There is only one dataplane cluster" )
224 try:
225 numClusters = len( json.loads( clusters[ 0 ] ) )
226 except ( ValueError, TypeError ):
227 main.log.exception( "Error parsing clusters[0]: " +
228 repr( clusters[ 0 ] ) )
Jon Hall6e709752016-02-01 13:38:46 -0800229 numClusters = "ERROR"
Jon Hall85794ff2015-07-08 14:12:30 -0700230 clusterResults = main.FALSE
231 if numClusters == 1:
232 clusterResults = main.TRUE
233 utilities.assert_equals(
234 expect=1,
235 actual=numClusters,
236 onpass="ONOS shows 1 SCC",
237 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
238
239 main.step( "Comparing ONOS topology to MN" )
240 devicesResults = main.TRUE
241 linksResults = main.TRUE
242 hostsResults = main.TRUE
243 mnSwitches = main.Mininet1.getSwitches()
244 mnLinks = main.Mininet1.getLinks()
245 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700246 for controller in main.Cluster.getRunningPos():
247 controllerStr = str( main.Cluster.active( controller ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700248 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700249 "Error" not in devices[ controller ] and\
250 "Error" not in ports[ controller ]:
251 currentDevicesResult = main.Mininet1.compareSwitches(
252 mnSwitches,
253 json.loads( devices[ controller ] ),
254 json.loads( ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700255 else:
256 currentDevicesResult = main.FALSE
257 utilities.assert_equals( expect=main.TRUE,
258 actual=currentDevicesResult,
259 onpass="ONOS" + controllerStr +
260 " Switches view is correct",
261 onfail="ONOS" + controllerStr +
262 " Switches view is incorrect" )
263 if links[ controller ] and "Error" not in links[ controller ]:
264 currentLinksResult = main.Mininet1.compareLinks(
265 mnSwitches, mnLinks,
266 json.loads( links[ controller ] ) )
267 else:
268 currentLinksResult = main.FALSE
269 utilities.assert_equals( expect=main.TRUE,
270 actual=currentLinksResult,
271 onpass="ONOS" + controllerStr +
272 " links view is correct",
273 onfail="ONOS" + controllerStr +
274 " links view is incorrect" )
275
Jon Halla440e872016-03-31 15:15:50 -0700276 if hosts[ controller ] and "Error" not in hosts[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700277 currentHostsResult = main.Mininet1.compareHosts(
278 mnHosts,
279 hosts[ controller ] )
280 else:
281 currentHostsResult = main.FALSE
282 utilities.assert_equals( expect=main.TRUE,
283 actual=currentHostsResult,
284 onpass="ONOS" + controllerStr +
285 " hosts exist in Mininet",
286 onfail="ONOS" + controllerStr +
287 " hosts don't match Mininet" )
288
289 devicesResults = devicesResults and currentDevicesResult
290 linksResults = linksResults and currentLinksResult
291 hostsResults = hostsResults and currentHostsResult
292
293 main.step( "Device information is correct" )
294 utilities.assert_equals(
295 expect=main.TRUE,
296 actual=devicesResults,
297 onpass="Device information is correct",
298 onfail="Device information is incorrect" )
299
300 main.step( "Links are correct" )
301 utilities.assert_equals(
302 expect=main.TRUE,
303 actual=linksResults,
304 onpass="Link are correct",
305 onfail="Links are incorrect" )
306
307 main.step( "Hosts are correct" )
308 utilities.assert_equals(
309 expect=main.TRUE,
310 actual=hostsResults,
311 onpass="Hosts are correct",
312 onfail="Hosts are incorrect" )
313
Jon Hall8bafdc02017-09-05 11:36:26 -0700314 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
315 mastershipState = ONOSMastership[ 0 ]
316
Jon Hall85794ff2015-07-08 14:12:30 -0700317 def CASE6( self, main ):
318 """
319 The Failure case.
320 """
321 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700322 assert main, "main not defined"
323 assert utilities.assert_equals, "utilities.assert_equals not defined"
324
325 # Reset non-persistent variables
326 try:
327 iCounterValue = 0
328 except NameError:
329 main.log.error( "iCounterValue not defined, setting to 0" )
330 iCounterValue = 0
331
332 main.case( "Restart ONOS node" )
Jon Hall783bbf92015-07-23 14:33:19 -0700333 main.caseExplanation = "Killing ONOS process and restart cli " +\
Jon Hall85794ff2015-07-08 14:12:30 -0700334 "sessions once onos is up."
Jon Hall96091e62015-09-21 17:34:17 -0700335
336 main.step( "Checking ONOS Logs for errors" )
Devin Lim142b5342017-07-20 15:22:39 -0700337 for ctrl in main.Cluster.active():
338 main.log.debug( "Checking logs for errors on " + ctrl.name + ":" )
339 main.log.warn( main.ONOSbench.checkLogs( ctrl.ip_address ) )
340 ctrl = main.Cluster.runningNodes[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700341 main.step( "Killing ONOS processes" )
Devin Lim142b5342017-07-20 15:22:39 -0700342 killResult = main.ONOSbench.onosKill( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700343 start = time.time()
344 utilities.assert_equals( expect=main.TRUE, actual=killResult,
345 onpass="ONOS Killed",
346 onfail="Error killing ONOS" )
347
348 main.step( "Checking if ONOS is up yet" )
349 count = 0
350 while count < 10:
Devin Lim142b5342017-07-20 15:22:39 -0700351 onos1Isup = main.ONOSbench.isup( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700352 if onos1Isup == main.TRUE:
353 elapsed = time.time() - start
354 break
355 else:
356 count = count + 1
357 utilities.assert_equals( expect=main.TRUE, actual=onos1Isup,
358 onpass="ONOS is back up",
359 onfail="ONOS failed to start" )
360
Jon Hall6509dbf2016-06-21 17:01:17 -0700361 main.step( "Starting ONOS CLI sessions" )
Devin Lim142b5342017-07-20 15:22:39 -0700362 cliResults = ctrl.CLI.startOnosCli( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700363 utilities.assert_equals( expect=main.TRUE, actual=cliResults,
364 onpass="ONOS cli startup successful",
365 onfail="ONOS cli startup failed" )
366
367 if elapsed:
368 main.log.info( "ESTIMATE: ONOS took %s seconds to restart" %
369 str( elapsed ) )
370 main.restartTime = elapsed
371 else:
372 main.restartTime = -1
373 time.sleep( 5 )
374 # rerun on election apps
Devin Lim142b5342017-07-20 15:22:39 -0700375 ctrl.CLI.electionTestRun()
Jon Hall85794ff2015-07-08 14:12:30 -0700376
377 def CASE7( self, main ):
378 """
379 Check state after ONOS failure
380 """
381 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700382 assert main, "main not defined"
383 assert utilities.assert_equals, "utilities.assert_equals not defined"
384 main.case( "Running ONOS Constant State Tests" )
Jon Hall6e709752016-02-01 13:38:46 -0800385
Jon Hall85794ff2015-07-08 14:12:30 -0700386 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700387 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700388
389 main.step( "Check if switch roles are consistent across all nodes" )
Jon Hall8bafdc02017-09-05 11:36:26 -0700390 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
Devin Lim142b5342017-07-20 15:22:39 -0700391 ONOSMastership = ONOSMastership[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700392 description2 = "Compare switch roles from before failure"
393 main.step( description2 )
394
Devin Lim142b5342017-07-20 15:22:39 -0700395 currentJson = json.loads( ONOSMastership )
Jon Hall85794ff2015-07-08 14:12:30 -0700396 oldJson = json.loads( mastershipState )
397 mastershipCheck = main.TRUE
398 for i in range( 1, 29 ):
399 switchDPID = str(
400 main.Mininet1.getSwitchDPID( switch="s" + str( i ) ) )
401
402 current = [ switch[ 'master' ] for switch in currentJson
403 if switchDPID in switch[ 'id' ] ]
404 old = [ switch[ 'master' ] for switch in oldJson
405 if switchDPID in switch[ 'id' ] ]
406 if current == old:
407 mastershipCheck = mastershipCheck and main.TRUE
408 else:
Jon Hall8bafdc02017-09-05 11:36:26 -0700409 main.log.warn( "Mastership of switch %s changed; old: %s, new: %s" % ( switchDPID,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700410 old, current ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700411 mastershipCheck = main.FALSE
412 utilities.assert_equals(
413 expect=main.TRUE,
414 actual=mastershipCheck,
415 onpass="Mastership of Switches was not changed",
416 onfail="Mastership of some switches changed" )
417 mastershipCheck = mastershipCheck and consistentMastership
418
419 main.step( "Get the intents and compare across all nodes" )
Devin Lim142b5342017-07-20 15:22:39 -0700420 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700421 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700422 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700423 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700424 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700425 else:
426 intentCheck = main.TRUE
427 utilities.assert_equals(
428 expect=main.TRUE,
429 actual=intentCheck,
430 onpass="Intents are consistent across all ONOS nodes",
431 onfail="ONOS nodes have different views of intents" )
432 # Print the intent states
433 intents = []
Devin Lim142b5342017-07-20 15:22:39 -0700434 intents.append( ONOSIntents )
Jon Hall85794ff2015-07-08 14:12:30 -0700435 intentStates = []
436 for node in intents: # Iter through ONOS nodes
437 nodeStates = []
438 # Iter through intents of a node
439 for intent in json.loads( node ):
440 nodeStates.append( intent[ 'state' ] )
441 intentStates.append( nodeStates )
Jon Hallf37d44d2017-05-24 10:37:30 -0700442 out = [ ( i, nodeStates.count( i ) ) for i in set( nodeStates ) ]
Jon Hall85794ff2015-07-08 14:12:30 -0700443 main.log.info( dict( out ) )
444
445 # NOTE: Store has no durability, so intents are lost across system
446 # restarts
Jon Hall85794ff2015-07-08 14:12:30 -0700447 main.step( "Get the OF Table entries and compare to before " +
448 "component failure" )
449 FlowTables = main.TRUE
Jon Hall85794ff2015-07-08 14:12:30 -0700450 for i in range( 28 ):
451 main.log.info( "Checking flow table on s" + str( i + 1 ) )
GlennRC68467eb2015-11-16 18:01:01 -0800452 tmpFlows = main.Mininet1.getFlowTable( "s" + str( i + 1 ), version="1.3", debug=False )
Jon Hallf37d44d2017-05-24 10:37:30 -0700453 curSwitch = main.Mininet1.flowTableComp( flows[ i ], tmpFlows )
Jon Hall41d39f12016-04-11 22:54:35 -0700454 FlowTables = FlowTables and curSwitch
455 if curSwitch == main.FALSE:
GlennRC68467eb2015-11-16 18:01:01 -0800456 main.log.warn( "Differences in flow table for switch: s{}".format( i + 1 ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700457 utilities.assert_equals(
458 expect=main.TRUE,
459 actual=FlowTables,
460 onpass="No changes were found in the flow tables",
461 onfail="Changes were found in the flow tables" )
462
463 main.step( "Leadership Election is still functional" )
464 # Test of LeadershipElection
465
Devin Lim142b5342017-07-20 15:22:39 -0700466 leader = main.Cluster.runningNodes[ 0 ].ipAddress
Jon Hall85794ff2015-07-08 14:12:30 -0700467 leaderResult = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700468 for ctrl in main.Cluster.active():
Jon Hall85794ff2015-07-08 14:12:30 -0700469 # loop through ONOScli handlers
Devin Lim142b5342017-07-20 15:22:39 -0700470 leaderN = ctrl.CLI.electionTestLeader()
Jon Hall85794ff2015-07-08 14:12:30 -0700471 # verify leader is ONOS1
472 # NOTE even though we restarted ONOS, it is the only one so onos 1
473 # must be leader
474 if leaderN == leader:
475 # all is well
476 pass
477 elif leaderN == main.FALSE:
478 # error in response
479 main.log.error( "Something is wrong with " +
480 "electionTestLeader function, check the" +
481 " error logs" )
482 leaderResult = main.FALSE
483 elif leader != leaderN:
484 leaderResult = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700485 main.log.error( ctrl.name + " sees " +
Jon Hall85794ff2015-07-08 14:12:30 -0700486 str( leaderN ) +
487 " as the leader of the election app. " +
488 "Leader should be " + str( leader ) )
489 utilities.assert_equals(
490 expect=main.TRUE,
491 actual=leaderResult,
492 onpass="Leadership election passed",
493 onfail="Something went wrong with Leadership election" )
494
495 def CASE8( self, main ):
496 """
497 Compare topo
498 """
499 import json
500 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700501 assert main, "main not defined"
502 assert utilities.assert_equals, "utilities.assert_equals not defined"
503
504 main.case( "Compare ONOS Topology view to Mininet topology" )
Jon Hall783bbf92015-07-23 14:33:19 -0700505 main.caseExplanation = "Compare topology objects between Mininet" +\
Jon Hall85794ff2015-07-08 14:12:30 -0700506 " and ONOS"
Jon Hall85794ff2015-07-08 14:12:30 -0700507 topoResult = main.FALSE
508 elapsed = 0
509 count = 0
Jon Halle9b1fa32015-12-08 15:32:21 -0800510 main.step( "Comparing ONOS topology to MN topology" )
Jon Hall85794ff2015-07-08 14:12:30 -0700511 startTime = time.time()
Devin Lim142b5342017-07-20 15:22:39 -0700512 ctrl = main.Cluster.active( 0 )
Jon Hall85794ff2015-07-08 14:12:30 -0700513 # Give time for Gossip to work
Jon Halle9b1fa32015-12-08 15:32:21 -0800514 while topoResult == main.FALSE and ( elapsed < 60 or count < 3 ):
Jon Hall96091e62015-09-21 17:34:17 -0700515 devicesResults = main.TRUE
516 linksResults = main.TRUE
517 hostsResults = main.TRUE
518 hostAttachmentResults = True
Jon Hall85794ff2015-07-08 14:12:30 -0700519 count += 1
520 cliStart = time.time()
521 devices = []
Devin Lim142b5342017-07-20 15:22:39 -0700522 devices.append( ctrl.CLI.devices() )
Jon Hall85794ff2015-07-08 14:12:30 -0700523 hosts = []
Devin Lim142b5342017-07-20 15:22:39 -0700524 hosts.append( json.loads( ctrl.CLI.hosts() ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700525 ipResult = main.TRUE
526 for controller in range( 0, len( hosts ) ):
527 controllerStr = str( controller + 1 )
528 for host in hosts[ controller ]:
529 if host is None or host.get( 'ipAddresses', [] ) == []:
530 main.log.error(
531 "DEBUG:Error with host ips on controller" +
532 controllerStr + ": " + str( host ) )
533 ipResult = main.FALSE
534 ports = []
Devin Lim142b5342017-07-20 15:22:39 -0700535 ports.append( ctrl.CLI.ports() )
Jon Hall85794ff2015-07-08 14:12:30 -0700536 links = []
Devin Lim142b5342017-07-20 15:22:39 -0700537 links.append( ctrl.CLI.links() )
Jon Hall85794ff2015-07-08 14:12:30 -0700538 clusters = []
Devin Lim142b5342017-07-20 15:22:39 -0700539 clusters.append( ctrl.CLI.clusters() )
Jon Hall85794ff2015-07-08 14:12:30 -0700540
541 elapsed = time.time() - startTime
542 cliTime = time.time() - cliStart
543 print "CLI time: " + str( cliTime )
544
545 mnSwitches = main.Mininet1.getSwitches()
546 mnLinks = main.Mininet1.getLinks()
547 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700548 for controller in main.Cluster.getRunningPos():
549 controllerStr = str( controller )
Jon Hall85794ff2015-07-08 14:12:30 -0700550 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700551 "Error" not in devices[ controller ] and\
552 "Error" not in ports[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700553
Jon Hallc6793552016-01-19 14:18:37 -0800554 try:
555 currentDevicesResult = main.Mininet1.compareSwitches(
556 mnSwitches,
557 json.loads( devices[ controller ] ),
558 json.loads( ports[ controller ] ) )
559 except ( TypeError, ValueError ) as e:
560 main.log.exception( "Object not as expected; devices={!r}\nports={!r}".format(
561 devices[ controller ], ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700562 else:
563 currentDevicesResult = main.FALSE
564 utilities.assert_equals( expect=main.TRUE,
565 actual=currentDevicesResult,
566 onpass="ONOS" + controllerStr +
567 " Switches view is correct",
568 onfail="ONOS" + controllerStr +
569 " Switches view is incorrect" )
570
571 if links[ controller ] and "Error" not in links[ controller ]:
572 currentLinksResult = main.Mininet1.compareLinks(
573 mnSwitches, mnLinks,
574 json.loads( links[ controller ] ) )
575 else:
576 currentLinksResult = main.FALSE
577 utilities.assert_equals( expect=main.TRUE,
578 actual=currentLinksResult,
579 onpass="ONOS" + controllerStr +
580 " links view is correct",
581 onfail="ONOS" + controllerStr +
582 " links view is incorrect" )
583
584 if hosts[ controller ] or "Error" not in hosts[ controller ]:
585 currentHostsResult = main.Mininet1.compareHosts(
586 mnHosts,
587 hosts[ controller ] )
588 else:
589 currentHostsResult = main.FALSE
590 utilities.assert_equals( expect=main.TRUE,
591 actual=currentHostsResult,
592 onpass="ONOS" + controllerStr +
593 " hosts exist in Mininet",
594 onfail="ONOS" + controllerStr +
595 " hosts don't match Mininet" )
596 # CHECKING HOST ATTACHMENT POINTS
597 hostAttachment = True
598 zeroHosts = False
599 # FIXME: topo-HA/obelisk specific mappings:
600 # key is mac and value is dpid
601 mappings = {}
602 for i in range( 1, 29 ): # hosts 1 through 28
603 # set up correct variables:
Jon Hallf37d44d2017-05-24 10:37:30 -0700604 macId = "00:" * 5 + hex( i ).split( "0x" )[ 1 ].upper().zfill( 2 )
Jon Hall85794ff2015-07-08 14:12:30 -0700605 if i == 1:
Jon Hallf37d44d2017-05-24 10:37:30 -0700606 deviceId = "1000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700607 elif i == 2:
Jon Hallf37d44d2017-05-24 10:37:30 -0700608 deviceId = "2000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700609 elif i == 3:
Jon Hallf37d44d2017-05-24 10:37:30 -0700610 deviceId = "3000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700611 elif i == 4:
Jon Hallf37d44d2017-05-24 10:37:30 -0700612 deviceId = "3004".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700613 elif i == 5:
Jon Hallf37d44d2017-05-24 10:37:30 -0700614 deviceId = "5000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700615 elif i == 6:
Jon Hallf37d44d2017-05-24 10:37:30 -0700616 deviceId = "6000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700617 elif i == 7:
Jon Hallf37d44d2017-05-24 10:37:30 -0700618 deviceId = "6007".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700619 elif i >= 8 and i <= 17:
620 dpid = '3' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700621 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700622 elif i >= 18 and i <= 27:
623 dpid = '6' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700624 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700625 elif i == 28:
Jon Hallf37d44d2017-05-24 10:37:30 -0700626 deviceId = "2800".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700627 mappings[ macId ] = deviceId
628 if hosts[ controller ] or "Error" not in hosts[ controller ]:
629 if hosts[ controller ] == []:
630 main.log.warn( "There are no hosts discovered" )
631 zeroHosts = True
632 else:
633 for host in hosts[ controller ]:
634 mac = None
635 location = None
636 device = None
637 port = None
638 try:
639 mac = host.get( 'mac' )
640 assert mac, "mac field could not be found for this host object"
641
Jeremy Ronquillo0e538bc2017-06-13 15:16:09 -0700642 location = host.get( 'locations' )[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700643 assert location, "location field could not be found for this host object"
644
645 # Trim the protocol identifier off deviceId
Jon Hallf37d44d2017-05-24 10:37:30 -0700646 device = str( location.get( 'elementId' ) ).split( ':' )[ 1 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700647 assert device, "elementId field could not be found for this host location object"
648
649 port = location.get( 'port' )
650 assert port, "port field could not be found for this host location object"
651
652 # Now check if this matches where they should be
653 if mac and device and port:
654 if str( port ) != "1":
655 main.log.error( "The attachment port is incorrect for " +
656 "host " + str( mac ) +
Jon Hallf37d44d2017-05-24 10:37:30 -0700657 ". Expected: 1 Actual: " + str( port ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700658 hostAttachment = False
659 if device != mappings[ str( mac ) ]:
660 main.log.error( "The attachment device is incorrect for " +
661 "host " + str( mac ) +
662 ". Expected: " + mappings[ str( mac ) ] +
663 " Actual: " + device )
664 hostAttachment = False
665 else:
666 hostAttachment = False
667 except AssertionError:
668 main.log.exception( "Json object not as expected" )
669 main.log.error( repr( host ) )
670 hostAttachment = False
671 else:
672 main.log.error( "No hosts json output or \"Error\"" +
673 " in output. hosts = " +
674 repr( hosts[ controller ] ) )
675 if zeroHosts is False:
676 hostAttachment = True
677
Jon Hall85794ff2015-07-08 14:12:30 -0700678 devicesResults = devicesResults and currentDevicesResult
679 linksResults = linksResults and currentLinksResult
680 hostsResults = hostsResults and currentHostsResult
681 hostAttachmentResults = hostAttachmentResults and\
682 hostAttachment
683
Jon Halla440e872016-03-31 15:15:50 -0700684 # "consistent" results don't make sense for single instance
Jon Hall85794ff2015-07-08 14:12:30 -0700685 # there should always only be one cluster
Jon Hall85794ff2015-07-08 14:12:30 -0700686 clusterResults = main.FALSE
Jon Halla440e872016-03-31 15:15:50 -0700687 try:
688 numClusters = len( json.loads( clusters[ 0 ] ) )
689 except ( ValueError, TypeError ):
690 main.log.exception( "Error parsing clusters[0]: " +
Jon Hallf37d44d2017-05-24 10:37:30 -0700691 repr( clusters[ 0 ] ) )
Jon Halla440e872016-03-31 15:15:50 -0700692 numClusters = "ERROR"
693 clusterResults = main.FALSE
Jon Hall85794ff2015-07-08 14:12:30 -0700694 if numClusters == 1:
695 clusterResults = main.TRUE
696 utilities.assert_equals(
697 expect=1,
698 actual=numClusters,
699 onpass="ONOS shows 1 SCC",
700 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
701
702 topoResult = ( devicesResults and linksResults
703 and hostsResults and ipResult and clusterResults and
704 hostAttachmentResults )
705
706 topoResult = topoResult and int( count <= 2 )
707 note = "note it takes about " + str( int( cliTime ) ) + \
708 " seconds for the test to make all the cli calls to fetch " +\
709 "the topology from each ONOS instance"
710 main.log.info(
711 "Very crass estimate for topology discovery/convergence( " +
712 str( note ) + " ): " + str( elapsed ) + " seconds, " +
713 str( count ) + " tries" )
714 utilities.assert_equals( expect=main.TRUE, actual=topoResult,
715 onpass="Topology Check Test successful",
716 onfail="Topology Check Test NOT successful" )
Jon Hall41d39f12016-04-11 22:54:35 -0700717 main.step( "Checking ONOS nodes" )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800718 nodeResults = utilities.retry( main.Cluster.nodesCheck,
Jon Hall41d39f12016-04-11 22:54:35 -0700719 False,
Jon Hall41d39f12016-04-11 22:54:35 -0700720 attempts=5 )
721
722 utilities.assert_equals( expect=True, actual=nodeResults,
723 onpass="Nodes check successful",
724 onfail="Nodes check NOT successful" )
725 if not nodeResults:
Devin Lim142b5342017-07-20 15:22:39 -0700726 for ctrl in main.Cluster.active():
Jon Hall41d39f12016-04-11 22:54:35 -0700727 main.log.debug( "{} components not ACTIVE: \n{}".format(
Devin Lim142b5342017-07-20 15:22:39 -0700728 ctrl.name,
729 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700730
Jon Halld2871c22016-07-26 11:01:14 -0700731 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700732 main.cleanAndExit()
Jon Halld2871c22016-07-26 11:01:14 -0700733
Jon Hall85794ff2015-07-08 14:12:30 -0700734 def CASE9( self, main ):
735 """
736 Link s3-s28 down
737 """
Devin Lim58046fa2017-07-05 16:55:00 -0700738 main.HA.linkDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700739
740 def CASE10( self, main ):
741 """
742 Link s3-s28 up
743 """
Devin Lim58046fa2017-07-05 16:55:00 -0700744 main.HA.linkUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700745
746 def CASE11( self, main ):
747 """
748 Switch Down
749 """
750 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700751 main.HA.switchDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700752
753 def CASE12( self, main ):
754 """
755 Switch Up
756 """
757 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700758 main.HA.switchUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700759
760 def CASE13( self, main ):
761 """
762 Clean up
763 """
Devin Lim58046fa2017-07-05 16:55:00 -0700764 main.HAlabels.append( "Restart" )
765 main.HAdata.append( str( main.restartTime ) )
766 main.HA.cleanUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700767
768 def CASE14( self, main ):
769 """
770 start election app on all onos nodes
771 """
Devin Lim58046fa2017-07-05 16:55:00 -0700772 main.HA.startElectionApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700773
774 def CASE15( self, main ):
775 """
776 Check that Leadership Election is still functional
acsmars71adceb2015-08-31 15:09:26 -0700777 15.1 Run election on each node
778 15.2 Check that each node has the same leaders and candidates
779 15.3 Find current leader and withdraw
780 15.4 Check that a new node was elected leader
781 15.5 Check that that new leader was the candidate of old leader
782 15.6 Run for election on old leader
783 15.7 Check that oldLeader is a candidate, and leader if only 1 node
784 15.8 Make sure that the old leader was added to the candidate list
785
786 old and new variable prefixes refer to data from before vs after
787 withdrawl and later before withdrawl vs after re-election
Jon Hall85794ff2015-07-08 14:12:30 -0700788 """
Devin Lim58046fa2017-07-05 16:55:00 -0700789 main.HA.isElectionFunctional( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700790
791 def CASE16( self, main ):
792 """
793 Install Distributed Primitives app
794 """
Devin Lim58046fa2017-07-05 16:55:00 -0700795 main.HA.installDistributedPrimitiveApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700796
797 def CASE17( self, main ):
798 """
799 Check for basic functionality with distributed primitives
800 """
Devin Lim58046fa2017-07-05 16:55:00 -0700801 main.HA.checkDistPrimitivesFunc( main )