blob: eeb43108182e6060dabe5c8dd19cbe36abd7ca71 [file] [log] [blame]
Jon Hall85794ff2015-07-08 14:12:30 -07001"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07002Copyright 2015 Open Networking Foundation (ONF)
3
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
11 (at your option) any later version.
12
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"""
21
22"""
Jon Hall85794ff2015-07-08 14:12:30 -070023Description: This test is to determine if a single
24 instance ONOS 'cluster' can handle a restart
25
26List of test cases:
27CASE1: Compile ONOS and push it to the test machines
28CASE2: Assign devices to controllers
29CASE21: Assign mastership to controllers
30CASE3: Assign intents
31CASE4: Ping across added host intents
32CASE5: Reading state of ONOS
33CASE6: The Failure case.
34CASE7: Check state after control plane failure
35CASE8: Compare topo
36CASE9: Link s3-s28 down
37CASE10: Link s3-s28 up
38CASE11: Switch down
39CASE12: Switch up
40CASE13: Clean up
41CASE14: start election app on all onos nodes
42CASE15: Check that Leadership Election is still functional
43CASE16: Install Distributed Primitives app
44CASE17: Check for basic functionality with distributed primitives
45"""
Jon Hall85794ff2015-07-08 14:12:30 -070046class HAsingleInstanceRestart:
47
48 def __init__( self ):
49 self.default = ''
50
51 def CASE1( self, main ):
52 """
53 CASE1 is to compile ONOS and push it to the test machines
54
55 Startup sequence:
56 cell <name>
57 onos-verify-cell
58 NOTE: temporary - onos-remove-raft-logs
59 onos-uninstall
60 start mininet
61 git pull
62 mvn clean install
63 onos-package
64 onos-install -f
65 onos-wait-for-start
66 start cli sessions
67 start tcpdump
68 """
Jon Halle1a3b752015-07-22 13:02:46 -070069 import imp
Jon Hallf3d16e72015-12-16 17:45:08 -080070 import time
Jon Halla440e872016-03-31 15:15:50 -070071 import json
Jon Hall85794ff2015-07-08 14:12:30 -070072 main.log.info( "ONOS Single node cluster restart " +
73 "HA test - initialization" )
74 main.case( "Setting up test environment" )
Jon Hall783bbf92015-07-23 14:33:19 -070075 main.caseExplanation = "Setup the test environment including " +\
Jon Hall85794ff2015-07-08 14:12:30 -070076 "installing ONOS, starting Mininet and ONOS" +\
77 "cli sessions."
Jon Hall85794ff2015-07-08 14:12:30 -070078
Devin Lim142b5342017-07-20 15:22:39 -070079 # set global variables
Devin Lim58046fa2017-07-05 16:55:00 -070080 # These are for csv plotting in jenkins
81 main.HAlabels = []
82 main.HAdata = []
Jon Halle1a3b752015-07-22 13:02:46 -070083 try:
Devin Lim142b5342017-07-20 15:22:39 -070084 from tests.dependencies.ONOSSetup import ONOSSetup
85 main.testSetUp = ONOSSetup()
86 except ImportError:
87 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070088 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -070089 main.testSetUp.envSetupDescription()
90 try:
Jon Hall53c5e662016-04-13 16:06:56 -070091 from tests.HA.dependencies.HA import HA
Jon Hall41d39f12016-04-11 22:54:35 -070092 main.HA = HA()
Devin Lim142b5342017-07-20 15:22:39 -070093 # load some variables from the params file
94 cellName = main.params[ 'ENV' ][ 'cellName' ]
95 main.apps = main.params[ 'ENV' ][ 'appString' ]
96 main.numCtrls = int( main.params[ 'num_controllers' ] )
97 stepResult = main.testSetUp.envSetup()
98 except Exception as e:
99 main.testSetUp.envSetupException( e )
100 main.testSetUp.evnSetupConclusion( stepResult )
Devin Lim58046fa2017-07-05 16:55:00 -0700101 main.HA.generateGraph( "HAsingleInstanceRestart" )
Devin Lim142b5342017-07-20 15:22:39 -0700102 main.Cluster.setRunningNode( int( main.params[ 'num_controllers' ] ) )
103 ip = main.Cluster.getIps( allNode=True )
104 main.testSetUp.ONOSSetUp( main.Mininet1, main.Cluster, cellName="SingleHA", removeLog=True,
105 extraApply=[ main.testSetUp.createApplyCell,
106 main.HA.startingMininet,
107 main.testSetUp.createApplyCell ],
Jon Hall4f360bc2017-09-07 10:19:52 -0700108 applyArgs=[ [ main.Cluster, True, cellName, main.Mininet1, True, ip ],
109 None,
110 [ main.Cluster, True, "SingleHA", main.Mininet1,
111 True, main.Cluster.runningNodes[ 0 ].ipAddress ] ] )
Jon Hall85794ff2015-07-08 14:12:30 -0700112
Devin Lim58046fa2017-07-05 16:55:00 -0700113 main.HA.initialSetUp()
Jon Hall9d2dcad2016-04-08 10:15:20 -0700114
Jon Hall85794ff2015-07-08 14:12:30 -0700115 def CASE2( self, main ):
116 """
117 Assign devices to controllers
118 """
Devin Lim58046fa2017-07-05 16:55:00 -0700119 main.HA.assignDevices( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700120
121 def CASE21( self, main ):
122 """
123 Assign mastership to controllers
124 """
Devin Lim58046fa2017-07-05 16:55:00 -0700125 main.HA.assignMastership( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700126
127 def CASE3( self, main ):
128 """
129 Assign intents
130 """
Devin Lim58046fa2017-07-05 16:55:00 -0700131 main.HA.assignIntents( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700132
133 def CASE4( self, main ):
134 """
135 Ping across added host intents
136 """
Jon Hallca319892017-06-15 15:25:22 -0700137 main.HA.pingAcrossHostIntent( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700138
139 def CASE5( self, main ):
140 """
141 Reading state of ONOS
142 """
143 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700144 assert main, "main not defined"
145 assert utilities.assert_equals, "utilities.assert_equals not defined"
146
147 main.case( "Setting up and gathering data for current state" )
148 # The general idea for this test case is to pull the state of
149 # ( intents,flows, topology,... ) from each ONOS node
150 # We can then compare them with each other and also with past states
151
152 main.step( "Check that each switch has a master" )
153 global mastershipState
154 mastershipState = '[]'
155
156 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700157 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700158
159 main.step( "Get the Mastership of each switch" )
Devin Lim142b5342017-07-20 15:22:39 -0700160 main.HA.checkTheRole()
Jon Hall85794ff2015-07-08 14:12:30 -0700161
162 main.step( "Get the intents from each controller" )
163 global intentState
164 intentState = []
Devin Lim142b5342017-07-20 15:22:39 -0700165 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700166 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700167 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700168 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700169 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700170 else:
171 intentCheck = main.TRUE
172
173 main.step( "Get the flows from each controller" )
174 global flowState
175 flowState = []
176 flowCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700177 ONOSFlows = main.Cluster.runningNodes[ 0 ].CLI.flows( jsonFormat=True )
178 if "Error" in ONOSFlows or not ONOSFlows:
Jon Hall85794ff2015-07-08 14:12:30 -0700179 main.log.error( "Error in getting ONOS flows" )
Devin Lim142b5342017-07-20 15:22:39 -0700180 main.log.warn( "ONOS1 flows repsponse: " + ONOSFlows )
Jon Hall85794ff2015-07-08 14:12:30 -0700181 else:
182 # TODO: Do a better check, maybe compare flows on switches?
Devin Lim142b5342017-07-20 15:22:39 -0700183 flowState = ONOSFlows
Jon Hall85794ff2015-07-08 14:12:30 -0700184 flowCheck = main.TRUE
185
186 main.step( "Get the OF Table entries" )
187 global flows
188 flows = []
189 for i in range( 1, 29 ):
GlennRC68467eb2015-11-16 18:01:01 -0800190 flows.append( main.Mininet1.getFlowTable( "s" + str( i ), version="1.3", debug=False ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700191 if flowCheck == main.FALSE:
192 for table in flows:
193 main.log.warn( table )
194 # TODO: Compare switch flow tables with ONOS flow tables
195
196 main.step( "Collecting topology information from ONOS" )
197 devices = []
Devin Lim142b5342017-07-20 15:22:39 -0700198 devices.append( main.Cluster.runningNodes[ 0 ].CLI.devices() )
Jon Hall85794ff2015-07-08 14:12:30 -0700199 hosts = []
Devin Lim142b5342017-07-20 15:22:39 -0700200 hosts.append( json.loads( main.Cluster.runningNodes[ 0 ].CLI.hosts() ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700201 ports = []
Devin Lim142b5342017-07-20 15:22:39 -0700202 ports.append( main.Cluster.runningNodes[ 0 ].CLI.ports() )
Jon Hall85794ff2015-07-08 14:12:30 -0700203 links = []
Devin Lim142b5342017-07-20 15:22:39 -0700204 links.append( main.Cluster.runningNodes[ 0 ].CLI.links() )
Jon Hall85794ff2015-07-08 14:12:30 -0700205 clusters = []
Devin Lim142b5342017-07-20 15:22:39 -0700206 clusters.append( main.Cluster.runningNodes[ 0 ].CLI.clusters() )
Jon Hall85794ff2015-07-08 14:12:30 -0700207
208 main.step( "Each host has an IP address" )
209 ipResult = main.TRUE
210 for controller in range( 0, len( hosts ) ):
Devin Lim142b5342017-07-20 15:22:39 -0700211 controllerStr = str( main.Cluster.active( controller ) )
Jon Halla440e872016-03-31 15:15:50 -0700212 if hosts[ controller ]:
213 for host in hosts[ controller ]:
Jon Hallf37d44d2017-05-24 10:37:30 -0700214 if not host.get( 'ipAddresses', [] ):
Jon Halla440e872016-03-31 15:15:50 -0700215 main.log.error( "Error with host ips on controller" +
216 controllerStr + ": " + str( host ) )
217 ipResult = main.FALSE
Jon Hall85794ff2015-07-08 14:12:30 -0700218 utilities.assert_equals(
219 expect=main.TRUE,
220 actual=ipResult,
221 onpass="The ips of the hosts aren't empty",
222 onfail="The ip of at least one host is missing" )
223
224 # there should always only be one cluster
225 main.step( "There is only one dataplane cluster" )
226 try:
227 numClusters = len( json.loads( clusters[ 0 ] ) )
228 except ( ValueError, TypeError ):
229 main.log.exception( "Error parsing clusters[0]: " +
230 repr( clusters[ 0 ] ) )
Jon Hall6e709752016-02-01 13:38:46 -0800231 numClusters = "ERROR"
Jon Hall85794ff2015-07-08 14:12:30 -0700232 clusterResults = main.FALSE
233 if numClusters == 1:
234 clusterResults = main.TRUE
235 utilities.assert_equals(
236 expect=1,
237 actual=numClusters,
238 onpass="ONOS shows 1 SCC",
239 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
240
241 main.step( "Comparing ONOS topology to MN" )
242 devicesResults = main.TRUE
243 linksResults = main.TRUE
244 hostsResults = main.TRUE
245 mnSwitches = main.Mininet1.getSwitches()
246 mnLinks = main.Mininet1.getLinks()
247 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700248 for controller in main.Cluster.getRunningPos():
249 controllerStr = str( main.Cluster.active( controller ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700250 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700251 "Error" not in devices[ controller ] and\
252 "Error" not in ports[ controller ]:
253 currentDevicesResult = main.Mininet1.compareSwitches(
254 mnSwitches,
255 json.loads( devices[ controller ] ),
256 json.loads( ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700257 else:
258 currentDevicesResult = main.FALSE
259 utilities.assert_equals( expect=main.TRUE,
260 actual=currentDevicesResult,
261 onpass="ONOS" + controllerStr +
262 " Switches view is correct",
263 onfail="ONOS" + controllerStr +
264 " Switches view is incorrect" )
265 if links[ controller ] and "Error" not in links[ controller ]:
266 currentLinksResult = main.Mininet1.compareLinks(
267 mnSwitches, mnLinks,
268 json.loads( links[ controller ] ) )
269 else:
270 currentLinksResult = main.FALSE
271 utilities.assert_equals( expect=main.TRUE,
272 actual=currentLinksResult,
273 onpass="ONOS" + controllerStr +
274 " links view is correct",
275 onfail="ONOS" + controllerStr +
276 " links view is incorrect" )
277
Jon Halla440e872016-03-31 15:15:50 -0700278 if hosts[ controller ] and "Error" not in hosts[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700279 currentHostsResult = main.Mininet1.compareHosts(
280 mnHosts,
281 hosts[ controller ] )
282 else:
283 currentHostsResult = main.FALSE
284 utilities.assert_equals( expect=main.TRUE,
285 actual=currentHostsResult,
286 onpass="ONOS" + controllerStr +
287 " hosts exist in Mininet",
288 onfail="ONOS" + controllerStr +
289 " hosts don't match Mininet" )
290
291 devicesResults = devicesResults and currentDevicesResult
292 linksResults = linksResults and currentLinksResult
293 hostsResults = hostsResults and currentHostsResult
294
295 main.step( "Device information is correct" )
296 utilities.assert_equals(
297 expect=main.TRUE,
298 actual=devicesResults,
299 onpass="Device information is correct",
300 onfail="Device information is incorrect" )
301
302 main.step( "Links are correct" )
303 utilities.assert_equals(
304 expect=main.TRUE,
305 actual=linksResults,
306 onpass="Link are correct",
307 onfail="Links are incorrect" )
308
309 main.step( "Hosts are correct" )
310 utilities.assert_equals(
311 expect=main.TRUE,
312 actual=hostsResults,
313 onpass="Hosts are correct",
314 onfail="Hosts are incorrect" )
315
Jon Hall8bafdc02017-09-05 11:36:26 -0700316 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
317 mastershipState = ONOSMastership[ 0 ]
318
Jon Hall85794ff2015-07-08 14:12:30 -0700319 def CASE6( self, main ):
320 """
321 The Failure case.
322 """
323 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700324 assert main, "main not defined"
325 assert utilities.assert_equals, "utilities.assert_equals not defined"
326
327 # Reset non-persistent variables
328 try:
329 iCounterValue = 0
330 except NameError:
331 main.log.error( "iCounterValue not defined, setting to 0" )
332 iCounterValue = 0
333
334 main.case( "Restart ONOS node" )
Jon Hall783bbf92015-07-23 14:33:19 -0700335 main.caseExplanation = "Killing ONOS process and restart cli " +\
Jon Hall85794ff2015-07-08 14:12:30 -0700336 "sessions once onos is up."
Jon Hall96091e62015-09-21 17:34:17 -0700337
338 main.step( "Checking ONOS Logs for errors" )
Devin Lim142b5342017-07-20 15:22:39 -0700339 for ctrl in main.Cluster.active():
340 main.log.debug( "Checking logs for errors on " + ctrl.name + ":" )
341 main.log.warn( main.ONOSbench.checkLogs( ctrl.ip_address ) )
342 ctrl = main.Cluster.runningNodes[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700343 main.step( "Killing ONOS processes" )
Devin Lim142b5342017-07-20 15:22:39 -0700344 killResult = main.ONOSbench.onosKill( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700345 start = time.time()
346 utilities.assert_equals( expect=main.TRUE, actual=killResult,
347 onpass="ONOS Killed",
348 onfail="Error killing ONOS" )
349
350 main.step( "Checking if ONOS is up yet" )
351 count = 0
352 while count < 10:
Devin Lim142b5342017-07-20 15:22:39 -0700353 onos1Isup = main.ONOSbench.isup( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700354 if onos1Isup == main.TRUE:
355 elapsed = time.time() - start
356 break
357 else:
358 count = count + 1
359 utilities.assert_equals( expect=main.TRUE, actual=onos1Isup,
360 onpass="ONOS is back up",
361 onfail="ONOS failed to start" )
362
Jon Hall6509dbf2016-06-21 17:01:17 -0700363 main.step( "Starting ONOS CLI sessions" )
Devin Lim142b5342017-07-20 15:22:39 -0700364 cliResults = ctrl.CLI.startOnosCli( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700365 utilities.assert_equals( expect=main.TRUE, actual=cliResults,
366 onpass="ONOS cli startup successful",
367 onfail="ONOS cli startup failed" )
368
369 if elapsed:
370 main.log.info( "ESTIMATE: ONOS took %s seconds to restart" %
371 str( elapsed ) )
372 main.restartTime = elapsed
373 else:
374 main.restartTime = -1
375 time.sleep( 5 )
376 # rerun on election apps
Devin Lim142b5342017-07-20 15:22:39 -0700377 ctrl.CLI.electionTestRun()
Jon Hall85794ff2015-07-08 14:12:30 -0700378
379 def CASE7( self, main ):
380 """
381 Check state after ONOS failure
382 """
383 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700384 assert main, "main not defined"
385 assert utilities.assert_equals, "utilities.assert_equals not defined"
386 main.case( "Running ONOS Constant State Tests" )
Jon Hall6e709752016-02-01 13:38:46 -0800387
Jon Hall85794ff2015-07-08 14:12:30 -0700388 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700389 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700390
391 main.step( "Check if switch roles are consistent across all nodes" )
Jon Hall8bafdc02017-09-05 11:36:26 -0700392 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
Devin Lim142b5342017-07-20 15:22:39 -0700393 ONOSMastership = ONOSMastership[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700394 description2 = "Compare switch roles from before failure"
395 main.step( description2 )
396
Devin Lim142b5342017-07-20 15:22:39 -0700397 currentJson = json.loads( ONOSMastership )
Jon Hall85794ff2015-07-08 14:12:30 -0700398 oldJson = json.loads( mastershipState )
399 mastershipCheck = main.TRUE
400 for i in range( 1, 29 ):
401 switchDPID = str(
402 main.Mininet1.getSwitchDPID( switch="s" + str( i ) ) )
403
404 current = [ switch[ 'master' ] for switch in currentJson
405 if switchDPID in switch[ 'id' ] ]
406 old = [ switch[ 'master' ] for switch in oldJson
407 if switchDPID in switch[ 'id' ] ]
408 if current == old:
409 mastershipCheck = mastershipCheck and main.TRUE
410 else:
Jon Hall8bafdc02017-09-05 11:36:26 -0700411 main.log.warn( "Mastership of switch %s changed; old: %s, new: %s" % ( switchDPID,
412 old, current ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700413 mastershipCheck = main.FALSE
414 utilities.assert_equals(
415 expect=main.TRUE,
416 actual=mastershipCheck,
417 onpass="Mastership of Switches was not changed",
418 onfail="Mastership of some switches changed" )
419 mastershipCheck = mastershipCheck and consistentMastership
420
421 main.step( "Get the intents and compare across all nodes" )
Devin Lim142b5342017-07-20 15:22:39 -0700422 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700423 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700424 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700425 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700426 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700427 else:
428 intentCheck = main.TRUE
429 utilities.assert_equals(
430 expect=main.TRUE,
431 actual=intentCheck,
432 onpass="Intents are consistent across all ONOS nodes",
433 onfail="ONOS nodes have different views of intents" )
434 # Print the intent states
435 intents = []
Devin Lim142b5342017-07-20 15:22:39 -0700436 intents.append( ONOSIntents )
Jon Hall85794ff2015-07-08 14:12:30 -0700437 intentStates = []
438 for node in intents: # Iter through ONOS nodes
439 nodeStates = []
440 # Iter through intents of a node
441 for intent in json.loads( node ):
442 nodeStates.append( intent[ 'state' ] )
443 intentStates.append( nodeStates )
Jon Hallf37d44d2017-05-24 10:37:30 -0700444 out = [ ( i, nodeStates.count( i ) ) for i in set( nodeStates ) ]
Jon Hall85794ff2015-07-08 14:12:30 -0700445 main.log.info( dict( out ) )
446
447 # NOTE: Store has no durability, so intents are lost across system
448 # restarts
449 """
450 main.step( "Compare current intents with intents before the failure" )
451 # NOTE: this requires case 5 to pass for intentState to be set.
452 # maybe we should stop the test if that fails?
453 sameIntents = main.FALSE
Jon Halla440e872016-03-31 15:15:50 -0700454 try:
455 intentState
456 except NameError:
457 main.log.warn( "No previous intent state was saved" )
458 else:
459 if intentState and intentState == ONOSIntents[ 0 ]:
460 sameIntents = main.TRUE
461 main.log.info( "Intents are consistent with before failure" )
462 # TODO: possibly the states have changed? we may need to figure out
463 # what the acceptable states are
464 elif len( intentState ) == len( ONOSIntents[ 0 ] ):
465 sameIntents = main.TRUE
466 try:
467 before = json.loads( intentState )
468 after = json.loads( ONOSIntents[ 0 ] )
469 for intent in before:
470 if intent not in after:
471 sameIntents = main.FALSE
472 main.log.debug( "Intent is not currently in ONOS " +
473 "(at least in the same form):" )
474 main.log.debug( json.dumps( intent ) )
475 except ( ValueError, TypeError ):
476 main.log.exception( "Exception printing intents" )
Jon Hallf37d44d2017-05-24 10:37:30 -0700477 main.log.debug( repr( ONOSIntents[ 0 ] ) )
Jon Halla440e872016-03-31 15:15:50 -0700478 main.log.debug( repr( intentState ) )
479 if sameIntents == main.FALSE:
480 try:
481 main.log.debug( "ONOS intents before: " )
482 main.log.debug( json.dumps( json.loads( intentState ),
483 sort_keys=True, indent=4,
484 separators=( ',', ': ' ) ) )
485 main.log.debug( "Current ONOS intents: " )
486 main.log.debug( json.dumps( json.loads( ONOSIntents[ 0 ] ),
487 sort_keys=True, indent=4,
488 separators=( ',', ': ' ) ) )
489 except ( ValueError, TypeError ):
490 main.log.exception( "Exception printing intents" )
Jon Hallf37d44d2017-05-24 10:37:30 -0700491 main.log.debug( repr( ONOSIntents[ 0 ] ) )
Jon Halla440e872016-03-31 15:15:50 -0700492 main.log.debug( repr( intentState ) )
493 utilities.assert_equals(
494 expect=main.TRUE,
495 actual=sameIntents,
496 onpass="Intents are consistent with before failure",
497 onfail="The Intents changed during failure" )
Jon Hall85794ff2015-07-08 14:12:30 -0700498 intentCheck = intentCheck and sameIntents
499 """
500 main.step( "Get the OF Table entries and compare to before " +
501 "component failure" )
502 FlowTables = main.TRUE
Jon Hall85794ff2015-07-08 14:12:30 -0700503 for i in range( 28 ):
504 main.log.info( "Checking flow table on s" + str( i + 1 ) )
GlennRC68467eb2015-11-16 18:01:01 -0800505 tmpFlows = main.Mininet1.getFlowTable( "s" + str( i + 1 ), version="1.3", debug=False )
Jon Hallf37d44d2017-05-24 10:37:30 -0700506 curSwitch = main.Mininet1.flowTableComp( flows[ i ], tmpFlows )
Jon Hall41d39f12016-04-11 22:54:35 -0700507 FlowTables = FlowTables and curSwitch
508 if curSwitch == main.FALSE:
GlennRC68467eb2015-11-16 18:01:01 -0800509 main.log.warn( "Differences in flow table for switch: s{}".format( i + 1 ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700510 utilities.assert_equals(
511 expect=main.TRUE,
512 actual=FlowTables,
513 onpass="No changes were found in the flow tables",
514 onfail="Changes were found in the flow tables" )
515
516 main.step( "Leadership Election is still functional" )
517 # Test of LeadershipElection
518
Devin Lim142b5342017-07-20 15:22:39 -0700519 leader = main.Cluster.runningNodes[ 0 ].ipAddress
Jon Hall85794ff2015-07-08 14:12:30 -0700520 leaderResult = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700521 for ctrl in main.Cluster.active():
Jon Hall85794ff2015-07-08 14:12:30 -0700522 # loop through ONOScli handlers
Devin Lim142b5342017-07-20 15:22:39 -0700523 leaderN = ctrl.CLI.electionTestLeader()
Jon Hall85794ff2015-07-08 14:12:30 -0700524 # verify leader is ONOS1
525 # NOTE even though we restarted ONOS, it is the only one so onos 1
526 # must be leader
527 if leaderN == leader:
528 # all is well
529 pass
530 elif leaderN == main.FALSE:
531 # error in response
532 main.log.error( "Something is wrong with " +
533 "electionTestLeader function, check the" +
534 " error logs" )
535 leaderResult = main.FALSE
536 elif leader != leaderN:
537 leaderResult = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700538 main.log.error( ctrl.name + " sees " +
Jon Hall85794ff2015-07-08 14:12:30 -0700539 str( leaderN ) +
540 " as the leader of the election app. " +
541 "Leader should be " + str( leader ) )
542 utilities.assert_equals(
543 expect=main.TRUE,
544 actual=leaderResult,
545 onpass="Leadership election passed",
546 onfail="Something went wrong with Leadership election" )
547
548 def CASE8( self, main ):
549 """
550 Compare topo
551 """
552 import json
553 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700554 assert main, "main not defined"
555 assert utilities.assert_equals, "utilities.assert_equals not defined"
556
557 main.case( "Compare ONOS Topology view to Mininet topology" )
Jon Hall783bbf92015-07-23 14:33:19 -0700558 main.caseExplanation = "Compare topology objects between Mininet" +\
Jon Hall85794ff2015-07-08 14:12:30 -0700559 " and ONOS"
Jon Hall85794ff2015-07-08 14:12:30 -0700560 topoResult = main.FALSE
561 elapsed = 0
562 count = 0
Jon Halle9b1fa32015-12-08 15:32:21 -0800563 main.step( "Comparing ONOS topology to MN topology" )
Jon Hall85794ff2015-07-08 14:12:30 -0700564 startTime = time.time()
Devin Lim142b5342017-07-20 15:22:39 -0700565 ctrl = main.Cluster.active( 0 )
Jon Hall85794ff2015-07-08 14:12:30 -0700566 # Give time for Gossip to work
Jon Halle9b1fa32015-12-08 15:32:21 -0800567 while topoResult == main.FALSE and ( elapsed < 60 or count < 3 ):
Jon Hall96091e62015-09-21 17:34:17 -0700568 devicesResults = main.TRUE
569 linksResults = main.TRUE
570 hostsResults = main.TRUE
571 hostAttachmentResults = True
Jon Hall85794ff2015-07-08 14:12:30 -0700572 count += 1
573 cliStart = time.time()
574 devices = []
Devin Lim142b5342017-07-20 15:22:39 -0700575 devices.append( ctrl.CLI.devices() )
Jon Hall85794ff2015-07-08 14:12:30 -0700576 hosts = []
Devin Lim142b5342017-07-20 15:22:39 -0700577 hosts.append( json.loads( ctrl.CLI.hosts() ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700578 ipResult = main.TRUE
579 for controller in range( 0, len( hosts ) ):
580 controllerStr = str( controller + 1 )
581 for host in hosts[ controller ]:
582 if host is None or host.get( 'ipAddresses', [] ) == []:
583 main.log.error(
584 "DEBUG:Error with host ips on controller" +
585 controllerStr + ": " + str( host ) )
586 ipResult = main.FALSE
587 ports = []
Devin Lim142b5342017-07-20 15:22:39 -0700588 ports.append( ctrl.CLI.ports() )
Jon Hall85794ff2015-07-08 14:12:30 -0700589 links = []
Devin Lim142b5342017-07-20 15:22:39 -0700590 links.append( ctrl.CLI.links() )
Jon Hall85794ff2015-07-08 14:12:30 -0700591 clusters = []
Devin Lim142b5342017-07-20 15:22:39 -0700592 clusters.append( ctrl.CLI.clusters() )
Jon Hall85794ff2015-07-08 14:12:30 -0700593
594 elapsed = time.time() - startTime
595 cliTime = time.time() - cliStart
596 print "CLI time: " + str( cliTime )
597
598 mnSwitches = main.Mininet1.getSwitches()
599 mnLinks = main.Mininet1.getLinks()
600 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700601 for controller in main.Cluster.getRunningPos():
602 controllerStr = str( controller )
Jon Hall85794ff2015-07-08 14:12:30 -0700603 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700604 "Error" not in devices[ controller ] and\
605 "Error" not in ports[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700606
Jon Hallc6793552016-01-19 14:18:37 -0800607 try:
608 currentDevicesResult = main.Mininet1.compareSwitches(
609 mnSwitches,
610 json.loads( devices[ controller ] ),
611 json.loads( ports[ controller ] ) )
612 except ( TypeError, ValueError ) as e:
613 main.log.exception( "Object not as expected; devices={!r}\nports={!r}".format(
614 devices[ controller ], ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700615 else:
616 currentDevicesResult = main.FALSE
617 utilities.assert_equals( expect=main.TRUE,
618 actual=currentDevicesResult,
619 onpass="ONOS" + controllerStr +
620 " Switches view is correct",
621 onfail="ONOS" + controllerStr +
622 " Switches view is incorrect" )
623
624 if links[ controller ] and "Error" not in links[ controller ]:
625 currentLinksResult = main.Mininet1.compareLinks(
626 mnSwitches, mnLinks,
627 json.loads( links[ controller ] ) )
628 else:
629 currentLinksResult = main.FALSE
630 utilities.assert_equals( expect=main.TRUE,
631 actual=currentLinksResult,
632 onpass="ONOS" + controllerStr +
633 " links view is correct",
634 onfail="ONOS" + controllerStr +
635 " links view is incorrect" )
636
637 if hosts[ controller ] or "Error" not in hosts[ controller ]:
638 currentHostsResult = main.Mininet1.compareHosts(
639 mnHosts,
640 hosts[ controller ] )
641 else:
642 currentHostsResult = main.FALSE
643 utilities.assert_equals( expect=main.TRUE,
644 actual=currentHostsResult,
645 onpass="ONOS" + controllerStr +
646 " hosts exist in Mininet",
647 onfail="ONOS" + controllerStr +
648 " hosts don't match Mininet" )
649 # CHECKING HOST ATTACHMENT POINTS
650 hostAttachment = True
651 zeroHosts = False
652 # FIXME: topo-HA/obelisk specific mappings:
653 # key is mac and value is dpid
654 mappings = {}
655 for i in range( 1, 29 ): # hosts 1 through 28
656 # set up correct variables:
Jon Hallf37d44d2017-05-24 10:37:30 -0700657 macId = "00:" * 5 + hex( i ).split( "0x" )[ 1 ].upper().zfill( 2 )
Jon Hall85794ff2015-07-08 14:12:30 -0700658 if i == 1:
Jon Hallf37d44d2017-05-24 10:37:30 -0700659 deviceId = "1000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700660 elif i == 2:
Jon Hallf37d44d2017-05-24 10:37:30 -0700661 deviceId = "2000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700662 elif i == 3:
Jon Hallf37d44d2017-05-24 10:37:30 -0700663 deviceId = "3000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700664 elif i == 4:
Jon Hallf37d44d2017-05-24 10:37:30 -0700665 deviceId = "3004".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700666 elif i == 5:
Jon Hallf37d44d2017-05-24 10:37:30 -0700667 deviceId = "5000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700668 elif i == 6:
Jon Hallf37d44d2017-05-24 10:37:30 -0700669 deviceId = "6000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700670 elif i == 7:
Jon Hallf37d44d2017-05-24 10:37:30 -0700671 deviceId = "6007".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700672 elif i >= 8 and i <= 17:
673 dpid = '3' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700674 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700675 elif i >= 18 and i <= 27:
676 dpid = '6' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700677 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700678 elif i == 28:
Jon Hallf37d44d2017-05-24 10:37:30 -0700679 deviceId = "2800".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700680 mappings[ macId ] = deviceId
681 if hosts[ controller ] or "Error" not in hosts[ controller ]:
682 if hosts[ controller ] == []:
683 main.log.warn( "There are no hosts discovered" )
684 zeroHosts = True
685 else:
686 for host in hosts[ controller ]:
687 mac = None
688 location = None
689 device = None
690 port = None
691 try:
692 mac = host.get( 'mac' )
693 assert mac, "mac field could not be found for this host object"
694
Jeremy Ronquillo0e538bc2017-06-13 15:16:09 -0700695 location = host.get( 'locations' )[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700696 assert location, "location field could not be found for this host object"
697
698 # Trim the protocol identifier off deviceId
Jon Hallf37d44d2017-05-24 10:37:30 -0700699 device = str( location.get( 'elementId' ) ).split( ':' )[ 1 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700700 assert device, "elementId field could not be found for this host location object"
701
702 port = location.get( 'port' )
703 assert port, "port field could not be found for this host location object"
704
705 # Now check if this matches where they should be
706 if mac and device and port:
707 if str( port ) != "1":
708 main.log.error( "The attachment port is incorrect for " +
709 "host " + str( mac ) +
Jon Hallf37d44d2017-05-24 10:37:30 -0700710 ". Expected: 1 Actual: " + str( port ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700711 hostAttachment = False
712 if device != mappings[ str( mac ) ]:
713 main.log.error( "The attachment device is incorrect for " +
714 "host " + str( mac ) +
715 ". Expected: " + mappings[ str( mac ) ] +
716 " Actual: " + device )
717 hostAttachment = False
718 else:
719 hostAttachment = False
720 except AssertionError:
721 main.log.exception( "Json object not as expected" )
722 main.log.error( repr( host ) )
723 hostAttachment = False
724 else:
725 main.log.error( "No hosts json output or \"Error\"" +
726 " in output. hosts = " +
727 repr( hosts[ controller ] ) )
728 if zeroHosts is False:
729 hostAttachment = True
730
Jon Hall85794ff2015-07-08 14:12:30 -0700731 devicesResults = devicesResults and currentDevicesResult
732 linksResults = linksResults and currentLinksResult
733 hostsResults = hostsResults and currentHostsResult
734 hostAttachmentResults = hostAttachmentResults and\
735 hostAttachment
736
Jon Halla440e872016-03-31 15:15:50 -0700737 # "consistent" results don't make sense for single instance
Jon Hall85794ff2015-07-08 14:12:30 -0700738 # there should always only be one cluster
Jon Hall85794ff2015-07-08 14:12:30 -0700739 clusterResults = main.FALSE
Jon Halla440e872016-03-31 15:15:50 -0700740 try:
741 numClusters = len( json.loads( clusters[ 0 ] ) )
742 except ( ValueError, TypeError ):
743 main.log.exception( "Error parsing clusters[0]: " +
Jon Hallf37d44d2017-05-24 10:37:30 -0700744 repr( clusters[ 0 ] ) )
Jon Halla440e872016-03-31 15:15:50 -0700745 numClusters = "ERROR"
746 clusterResults = main.FALSE
Jon Hall85794ff2015-07-08 14:12:30 -0700747 if numClusters == 1:
748 clusterResults = main.TRUE
749 utilities.assert_equals(
750 expect=1,
751 actual=numClusters,
752 onpass="ONOS shows 1 SCC",
753 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
754
755 topoResult = ( devicesResults and linksResults
756 and hostsResults and ipResult and clusterResults and
757 hostAttachmentResults )
758
759 topoResult = topoResult and int( count <= 2 )
760 note = "note it takes about " + str( int( cliTime ) ) + \
761 " seconds for the test to make all the cli calls to fetch " +\
762 "the topology from each ONOS instance"
763 main.log.info(
764 "Very crass estimate for topology discovery/convergence( " +
765 str( note ) + " ): " + str( elapsed ) + " seconds, " +
766 str( count ) + " tries" )
767 utilities.assert_equals( expect=main.TRUE, actual=topoResult,
768 onpass="Topology Check Test successful",
769 onfail="Topology Check Test NOT successful" )
Jon Hall41d39f12016-04-11 22:54:35 -0700770 main.step( "Checking ONOS nodes" )
771 nodeResults = utilities.retry( main.HA.nodesCheck,
772 False,
Devin Lim142b5342017-07-20 15:22:39 -0700773 args=[ main.Cluster.active() ],
Jon Hall41d39f12016-04-11 22:54:35 -0700774 attempts=5 )
775
776 utilities.assert_equals( expect=True, actual=nodeResults,
777 onpass="Nodes check successful",
778 onfail="Nodes check NOT successful" )
779 if not nodeResults:
Devin Lim142b5342017-07-20 15:22:39 -0700780 for ctrl in main.Cluster.active():
Jon Hall41d39f12016-04-11 22:54:35 -0700781 main.log.debug( "{} components not ACTIVE: \n{}".format(
Devin Lim142b5342017-07-20 15:22:39 -0700782 ctrl.name,
783 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700784
Jon Halld2871c22016-07-26 11:01:14 -0700785 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700786 main.cleanAndExit()
Jon Halld2871c22016-07-26 11:01:14 -0700787
Jon Hall85794ff2015-07-08 14:12:30 -0700788 def CASE9( self, main ):
789 """
790 Link s3-s28 down
791 """
Devin Lim58046fa2017-07-05 16:55:00 -0700792 main.HA.linkDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700793
794 def CASE10( self, main ):
795 """
796 Link s3-s28 up
797 """
Devin Lim58046fa2017-07-05 16:55:00 -0700798 main.HA.linkUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700799
800 def CASE11( self, main ):
801 """
802 Switch Down
803 """
804 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700805 main.HA.switchDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700806
807 def CASE12( self, main ):
808 """
809 Switch Up
810 """
811 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700812 main.HA.switchUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700813
814 def CASE13( self, main ):
815 """
816 Clean up
817 """
Devin Lim58046fa2017-07-05 16:55:00 -0700818 main.HAlabels.append( "Restart" )
819 main.HAdata.append( str( main.restartTime ) )
820 main.HA.cleanUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700821
822 def CASE14( self, main ):
823 """
824 start election app on all onos nodes
825 """
Devin Lim58046fa2017-07-05 16:55:00 -0700826 main.HA.startElectionApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700827
828 def CASE15( self, main ):
829 """
830 Check that Leadership Election is still functional
acsmars71adceb2015-08-31 15:09:26 -0700831 15.1 Run election on each node
832 15.2 Check that each node has the same leaders and candidates
833 15.3 Find current leader and withdraw
834 15.4 Check that a new node was elected leader
835 15.5 Check that that new leader was the candidate of old leader
836 15.6 Run for election on old leader
837 15.7 Check that oldLeader is a candidate, and leader if only 1 node
838 15.8 Make sure that the old leader was added to the candidate list
839
840 old and new variable prefixes refer to data from before vs after
841 withdrawl and later before withdrawl vs after re-election
Jon Hall85794ff2015-07-08 14:12:30 -0700842 """
Devin Lim58046fa2017-07-05 16:55:00 -0700843 main.HA.isElectionFunctional( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700844
845 def CASE16( self, main ):
846 """
847 Install Distributed Primitives app
848 """
Devin Lim58046fa2017-07-05 16:55:00 -0700849 main.HA.installDistributedPrimitiveApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700850
851 def CASE17( self, main ):
852 """
853 Check for basic functionality with distributed primitives
854 """
Devin Lim58046fa2017-07-05 16:55:00 -0700855 main.HA.checkDistPrimitivesFunc( main )