blob: c8110d2b9809816a3a8a98c672159753f2fdbd57 [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 """
68 main.log.info( "ONOS Single node cluster restart " +
69 "HA test - initialization" )
70 main.case( "Setting up test environment" )
Jon Hall783bbf92015-07-23 14:33:19 -070071 main.caseExplanation = "Setup the test environment including " +\
Jon Hall85794ff2015-07-08 14:12:30 -070072 "installing ONOS, starting Mininet and ONOS" +\
73 "cli sessions."
Jon Hall85794ff2015-07-08 14:12:30 -070074
Devin Lim142b5342017-07-20 15:22:39 -070075 # set global variables
Devin Lim58046fa2017-07-05 16:55:00 -070076 # These are for csv plotting in jenkins
77 main.HAlabels = []
78 main.HAdata = []
Jon Halle1a3b752015-07-22 13:02:46 -070079 try:
Devin Lim142b5342017-07-20 15:22:39 -070080 from tests.dependencies.ONOSSetup import ONOSSetup
81 main.testSetUp = ONOSSetup()
82 except ImportError:
83 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070084 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -070085 main.testSetUp.envSetupDescription()
86 try:
Jon Hall53c5e662016-04-13 16:06:56 -070087 from tests.HA.dependencies.HA import HA
Jon Hall41d39f12016-04-11 22:54:35 -070088 main.HA = HA()
Devin Lim142b5342017-07-20 15:22:39 -070089 # load some variables from the params file
90 cellName = main.params[ 'ENV' ][ 'cellName' ]
91 main.apps = main.params[ 'ENV' ][ 'appString' ]
92 main.numCtrls = int( main.params[ 'num_controllers' ] )
93 stepResult = main.testSetUp.envSetup()
94 except Exception as e:
95 main.testSetUp.envSetupException( e )
96 main.testSetUp.evnSetupConclusion( stepResult )
Devin Lim142b5342017-07-20 15:22:39 -070097 main.Cluster.setRunningNode( int( main.params[ 'num_controllers' ] ) )
98 ip = main.Cluster.getIps( allNode=True )
You Wanga0f6ff62018-01-11 15:46:30 -080099 main.testSetUp.ONOSSetUp( main.Cluster, cellName="SingleHA", removeLog=True,
Devin Lim142b5342017-07-20 15:22:39 -0700100 extraApply=[ main.testSetUp.createApplyCell,
101 main.HA.startingMininet,
102 main.testSetUp.createApplyCell ],
You Wang66763e62018-02-09 16:31:28 -0800103 applyArgs=[ [ main.Cluster, True, cellName, "", "", True, ip ],
Jon Hall4f360bc2017-09-07 10:19:52 -0700104 None,
You Wang66763e62018-02-09 16:31:28 -0800105 [ main.Cluster, True, "SingleHA", "", "",
Jon Hall4f360bc2017-09-07 10:19:52 -0700106 True, main.Cluster.runningNodes[ 0 ].ipAddress ] ] )
Jon Hall85794ff2015-07-08 14:12:30 -0700107
Devin Lim58046fa2017-07-05 16:55:00 -0700108 main.HA.initialSetUp()
Jon Hall9d2dcad2016-04-08 10:15:20 -0700109
Jon Hall85794ff2015-07-08 14:12:30 -0700110 def CASE2( self, main ):
111 """
112 Assign devices to controllers
113 """
Devin Lim58046fa2017-07-05 16:55:00 -0700114 main.HA.assignDevices( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700115
116 def CASE21( self, main ):
117 """
118 Assign mastership to controllers
119 """
Devin Lim58046fa2017-07-05 16:55:00 -0700120 main.HA.assignMastership( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700121
122 def CASE3( self, main ):
123 """
124 Assign intents
125 """
Devin Lim58046fa2017-07-05 16:55:00 -0700126 main.HA.assignIntents( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700127
128 def CASE4( self, main ):
129 """
130 Ping across added host intents
131 """
Jon Hallca319892017-06-15 15:25:22 -0700132 main.HA.pingAcrossHostIntent( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700133
134 def CASE5( self, main ):
135 """
136 Reading state of ONOS
137 """
138 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700139 assert main, "main not defined"
140 assert utilities.assert_equals, "utilities.assert_equals not defined"
141
142 main.case( "Setting up and gathering data for current state" )
143 # The general idea for this test case is to pull the state of
144 # ( intents,flows, topology,... ) from each ONOS node
145 # We can then compare them with each other and also with past states
146
147 main.step( "Check that each switch has a master" )
148 global mastershipState
149 mastershipState = '[]'
150
151 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700152 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700153
154 main.step( "Get the Mastership of each switch" )
Devin Lim142b5342017-07-20 15:22:39 -0700155 main.HA.checkTheRole()
Jon Hall85794ff2015-07-08 14:12:30 -0700156
157 main.step( "Get the intents from each controller" )
158 global intentState
159 intentState = []
Devin Lim142b5342017-07-20 15:22:39 -0700160 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700161 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700162 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700163 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700164 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700165 else:
166 intentCheck = main.TRUE
Jon Halla478b852017-12-04 15:00:15 -0800167 utilities.assert_equals(
168 expect=main.TRUE,
169 actual=intentCheck,
170 onpass="Intents are consistent across all ONOS nodes",
171 onfail="ONOS nodes have different views of intents" )
Jon Hall85794ff2015-07-08 14:12:30 -0700172
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 utilities.assert_equals(
233 expect=1,
234 actual=numClusters,
235 onpass="ONOS shows 1 SCC",
236 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
237
238 main.step( "Comparing ONOS topology to MN" )
239 devicesResults = main.TRUE
240 linksResults = main.TRUE
241 hostsResults = main.TRUE
242 mnSwitches = main.Mininet1.getSwitches()
243 mnLinks = main.Mininet1.getLinks()
244 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700245 for controller in main.Cluster.getRunningPos():
246 controllerStr = str( main.Cluster.active( controller ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700247 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700248 "Error" not in devices[ controller ] and\
249 "Error" not in ports[ controller ]:
250 currentDevicesResult = main.Mininet1.compareSwitches(
251 mnSwitches,
252 json.loads( devices[ controller ] ),
253 json.loads( ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700254 else:
255 currentDevicesResult = main.FALSE
256 utilities.assert_equals( expect=main.TRUE,
257 actual=currentDevicesResult,
258 onpass="ONOS" + controllerStr +
259 " Switches view is correct",
260 onfail="ONOS" + controllerStr +
261 " Switches view is incorrect" )
262 if links[ controller ] and "Error" not in links[ controller ]:
263 currentLinksResult = main.Mininet1.compareLinks(
264 mnSwitches, mnLinks,
265 json.loads( links[ controller ] ) )
266 else:
267 currentLinksResult = main.FALSE
268 utilities.assert_equals( expect=main.TRUE,
269 actual=currentLinksResult,
270 onpass="ONOS" + controllerStr +
271 " links view is correct",
272 onfail="ONOS" + controllerStr +
273 " links view is incorrect" )
274
Jon Halla440e872016-03-31 15:15:50 -0700275 if hosts[ controller ] and "Error" not in hosts[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700276 currentHostsResult = main.Mininet1.compareHosts(
277 mnHosts,
278 hosts[ controller ] )
279 else:
280 currentHostsResult = main.FALSE
281 utilities.assert_equals( expect=main.TRUE,
282 actual=currentHostsResult,
283 onpass="ONOS" + controllerStr +
284 " hosts exist in Mininet",
285 onfail="ONOS" + controllerStr +
286 " hosts don't match Mininet" )
287
288 devicesResults = devicesResults and currentDevicesResult
289 linksResults = linksResults and currentLinksResult
290 hostsResults = hostsResults and currentHostsResult
291
292 main.step( "Device information is correct" )
293 utilities.assert_equals(
294 expect=main.TRUE,
295 actual=devicesResults,
296 onpass="Device information is correct",
297 onfail="Device information is incorrect" )
298
299 main.step( "Links are correct" )
300 utilities.assert_equals(
301 expect=main.TRUE,
302 actual=linksResults,
303 onpass="Link are correct",
304 onfail="Links are incorrect" )
305
306 main.step( "Hosts are correct" )
307 utilities.assert_equals(
308 expect=main.TRUE,
309 actual=hostsResults,
310 onpass="Hosts are correct",
311 onfail="Hosts are incorrect" )
312
Jon Hall8bafdc02017-09-05 11:36:26 -0700313 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
314 mastershipState = ONOSMastership[ 0 ]
315
Jon Hall85794ff2015-07-08 14:12:30 -0700316 def CASE6( self, main ):
317 """
318 The Failure case.
319 """
320 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700321 assert main, "main not defined"
322 assert utilities.assert_equals, "utilities.assert_equals not defined"
323
Jon Hall85794ff2015-07-08 14:12:30 -0700324 main.case( "Restart ONOS node" )
Jon Hall783bbf92015-07-23 14:33:19 -0700325 main.caseExplanation = "Killing ONOS process and restart cli " +\
Jon Hall85794ff2015-07-08 14:12:30 -0700326 "sessions once onos is up."
Jon Hall96091e62015-09-21 17:34:17 -0700327
328 main.step( "Checking ONOS Logs for errors" )
Devin Lim142b5342017-07-20 15:22:39 -0700329 for ctrl in main.Cluster.active():
330 main.log.debug( "Checking logs for errors on " + ctrl.name + ":" )
331 main.log.warn( main.ONOSbench.checkLogs( ctrl.ip_address ) )
332 ctrl = main.Cluster.runningNodes[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700333 main.step( "Killing ONOS processes" )
Devin Lim142b5342017-07-20 15:22:39 -0700334 killResult = main.ONOSbench.onosKill( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700335 start = time.time()
336 utilities.assert_equals( expect=main.TRUE, actual=killResult,
337 onpass="ONOS Killed",
338 onfail="Error killing ONOS" )
339
340 main.step( "Checking if ONOS is up yet" )
341 count = 0
342 while count < 10:
Devin Lim142b5342017-07-20 15:22:39 -0700343 onos1Isup = main.ONOSbench.isup( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700344 if onos1Isup == main.TRUE:
345 elapsed = time.time() - start
346 break
347 else:
348 count = count + 1
349 utilities.assert_equals( expect=main.TRUE, actual=onos1Isup,
350 onpass="ONOS is back up",
351 onfail="ONOS failed to start" )
352
Jon Hall6509dbf2016-06-21 17:01:17 -0700353 main.step( "Starting ONOS CLI sessions" )
Devin Lim142b5342017-07-20 15:22:39 -0700354 cliResults = ctrl.CLI.startOnosCli( ctrl.ipAddress )
Jon Hall85794ff2015-07-08 14:12:30 -0700355 utilities.assert_equals( expect=main.TRUE, actual=cliResults,
356 onpass="ONOS cli startup successful",
357 onfail="ONOS cli startup failed" )
358
359 if elapsed:
360 main.log.info( "ESTIMATE: ONOS took %s seconds to restart" %
361 str( elapsed ) )
362 main.restartTime = elapsed
363 else:
364 main.restartTime = -1
365 time.sleep( 5 )
366 # rerun on election apps
Devin Lim142b5342017-07-20 15:22:39 -0700367 ctrl.CLI.electionTestRun()
Jon Hall85794ff2015-07-08 14:12:30 -0700368
369 def CASE7( self, main ):
370 """
371 Check state after ONOS failure
372 """
373 import json
Jon Hall85794ff2015-07-08 14:12:30 -0700374 assert main, "main not defined"
375 assert utilities.assert_equals, "utilities.assert_equals not defined"
376 main.case( "Running ONOS Constant State Tests" )
Jon Hall6e709752016-02-01 13:38:46 -0800377
Jon Hall85794ff2015-07-08 14:12:30 -0700378 # Assert that each device has a master
Devin Lim142b5342017-07-20 15:22:39 -0700379 main.HA.checkRoleNotNull()
Jon Hall85794ff2015-07-08 14:12:30 -0700380
381 main.step( "Check if switch roles are consistent across all nodes" )
Jon Hall8bafdc02017-09-05 11:36:26 -0700382 ONOSMastership, rolesResult, consistentMastership = main.HA.checkTheRole()
Devin Lim142b5342017-07-20 15:22:39 -0700383 ONOSMastership = ONOSMastership[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700384 description2 = "Compare switch roles from before failure"
385 main.step( description2 )
386
Devin Lim142b5342017-07-20 15:22:39 -0700387 currentJson = json.loads( ONOSMastership )
Jon Hall85794ff2015-07-08 14:12:30 -0700388 oldJson = json.loads( mastershipState )
389 mastershipCheck = main.TRUE
390 for i in range( 1, 29 ):
391 switchDPID = str(
392 main.Mininet1.getSwitchDPID( switch="s" + str( i ) ) )
393
394 current = [ switch[ 'master' ] for switch in currentJson
395 if switchDPID in switch[ 'id' ] ]
396 old = [ switch[ 'master' ] for switch in oldJson
397 if switchDPID in switch[ 'id' ] ]
398 if current == old:
399 mastershipCheck = mastershipCheck and main.TRUE
400 else:
Jon Hall8bafdc02017-09-05 11:36:26 -0700401 main.log.warn( "Mastership of switch %s changed; old: %s, new: %s" % ( switchDPID,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700402 old, current ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700403 mastershipCheck = main.FALSE
404 utilities.assert_equals(
405 expect=main.TRUE,
406 actual=mastershipCheck,
407 onpass="Mastership of Switches was not changed",
408 onfail="Mastership of some switches changed" )
409 mastershipCheck = mastershipCheck and consistentMastership
410
411 main.step( "Get the intents and compare across all nodes" )
Devin Lim142b5342017-07-20 15:22:39 -0700412 ONOSIntents = main.Cluster.runningNodes[ 0 ].CLI.intents( jsonFormat=True )
Jon Hall85794ff2015-07-08 14:12:30 -0700413 intentCheck = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700414 if "Error" in ONOSIntents or not ONOSIntents:
Jon Hall85794ff2015-07-08 14:12:30 -0700415 main.log.error( "Error in getting ONOS intents" )
Devin Lim142b5342017-07-20 15:22:39 -0700416 main.log.warn( "ONOS1 intents response: " + repr( ONOSIntents ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700417 else:
418 intentCheck = main.TRUE
419 utilities.assert_equals(
420 expect=main.TRUE,
421 actual=intentCheck,
422 onpass="Intents are consistent across all ONOS nodes",
423 onfail="ONOS nodes have different views of intents" )
424 # Print the intent states
425 intents = []
Devin Lim142b5342017-07-20 15:22:39 -0700426 intents.append( ONOSIntents )
Jon Hall85794ff2015-07-08 14:12:30 -0700427 intentStates = []
428 for node in intents: # Iter through ONOS nodes
429 nodeStates = []
430 # Iter through intents of a node
431 for intent in json.loads( node ):
432 nodeStates.append( intent[ 'state' ] )
433 intentStates.append( nodeStates )
Jon Hallf37d44d2017-05-24 10:37:30 -0700434 out = [ ( i, nodeStates.count( i ) ) for i in set( nodeStates ) ]
Jon Hall85794ff2015-07-08 14:12:30 -0700435 main.log.info( dict( out ) )
436
437 # NOTE: Store has no durability, so intents are lost across system
438 # restarts
Jon Hall85794ff2015-07-08 14:12:30 -0700439 main.step( "Get the OF Table entries and compare to before " +
440 "component failure" )
441 FlowTables = main.TRUE
Jon Hall85794ff2015-07-08 14:12:30 -0700442 for i in range( 28 ):
443 main.log.info( "Checking flow table on s" + str( i + 1 ) )
GlennRC68467eb2015-11-16 18:01:01 -0800444 tmpFlows = main.Mininet1.getFlowTable( "s" + str( i + 1 ), version="1.3", debug=False )
Jon Hallf37d44d2017-05-24 10:37:30 -0700445 curSwitch = main.Mininet1.flowTableComp( flows[ i ], tmpFlows )
Jon Hall41d39f12016-04-11 22:54:35 -0700446 FlowTables = FlowTables and curSwitch
447 if curSwitch == main.FALSE:
GlennRC68467eb2015-11-16 18:01:01 -0800448 main.log.warn( "Differences in flow table for switch: s{}".format( i + 1 ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700449 utilities.assert_equals(
450 expect=main.TRUE,
451 actual=FlowTables,
452 onpass="No changes were found in the flow tables",
453 onfail="Changes were found in the flow tables" )
454
455 main.step( "Leadership Election is still functional" )
456 # Test of LeadershipElection
457
Devin Lim142b5342017-07-20 15:22:39 -0700458 leader = main.Cluster.runningNodes[ 0 ].ipAddress
Jon Hall85794ff2015-07-08 14:12:30 -0700459 leaderResult = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700460 for ctrl in main.Cluster.active():
Jon Hall85794ff2015-07-08 14:12:30 -0700461 # loop through ONOScli handlers
Devin Lim142b5342017-07-20 15:22:39 -0700462 leaderN = ctrl.CLI.electionTestLeader()
Jon Hall85794ff2015-07-08 14:12:30 -0700463 # verify leader is ONOS1
464 # NOTE even though we restarted ONOS, it is the only one so onos 1
465 # must be leader
466 if leaderN == leader:
467 # all is well
468 pass
469 elif leaderN == main.FALSE:
470 # error in response
471 main.log.error( "Something is wrong with " +
472 "electionTestLeader function, check the" +
473 " error logs" )
474 leaderResult = main.FALSE
475 elif leader != leaderN:
476 leaderResult = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700477 main.log.error( ctrl.name + " sees " +
Jon Hall85794ff2015-07-08 14:12:30 -0700478 str( leaderN ) +
479 " as the leader of the election app. " +
480 "Leader should be " + str( leader ) )
481 utilities.assert_equals(
482 expect=main.TRUE,
483 actual=leaderResult,
484 onpass="Leadership election passed",
485 onfail="Something went wrong with Leadership election" )
486
487 def CASE8( self, main ):
488 """
489 Compare topo
490 """
491 import json
492 import time
Jon Hall85794ff2015-07-08 14:12:30 -0700493 assert main, "main not defined"
494 assert utilities.assert_equals, "utilities.assert_equals not defined"
495
496 main.case( "Compare ONOS Topology view to Mininet topology" )
Jon Hall783bbf92015-07-23 14:33:19 -0700497 main.caseExplanation = "Compare topology objects between Mininet" +\
Jon Hall85794ff2015-07-08 14:12:30 -0700498 " and ONOS"
Jon Hall85794ff2015-07-08 14:12:30 -0700499 topoResult = main.FALSE
500 elapsed = 0
501 count = 0
Jon Halle9b1fa32015-12-08 15:32:21 -0800502 main.step( "Comparing ONOS topology to MN topology" )
Jon Hall85794ff2015-07-08 14:12:30 -0700503 startTime = time.time()
Devin Lim142b5342017-07-20 15:22:39 -0700504 ctrl = main.Cluster.active( 0 )
Jon Hall85794ff2015-07-08 14:12:30 -0700505 # Give time for Gossip to work
Jon Halle9b1fa32015-12-08 15:32:21 -0800506 while topoResult == main.FALSE and ( elapsed < 60 or count < 3 ):
Jon Hall96091e62015-09-21 17:34:17 -0700507 devicesResults = main.TRUE
508 linksResults = main.TRUE
509 hostsResults = main.TRUE
510 hostAttachmentResults = True
Jon Hall85794ff2015-07-08 14:12:30 -0700511 count += 1
512 cliStart = time.time()
513 devices = []
Devin Lim142b5342017-07-20 15:22:39 -0700514 devices.append( ctrl.CLI.devices() )
Jon Hall85794ff2015-07-08 14:12:30 -0700515 hosts = []
Devin Lim142b5342017-07-20 15:22:39 -0700516 hosts.append( json.loads( ctrl.CLI.hosts() ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700517 ipResult = main.TRUE
518 for controller in range( 0, len( hosts ) ):
519 controllerStr = str( controller + 1 )
520 for host in hosts[ controller ]:
521 if host is None or host.get( 'ipAddresses', [] ) == []:
522 main.log.error(
523 "DEBUG:Error with host ips on controller" +
524 controllerStr + ": " + str( host ) )
525 ipResult = main.FALSE
526 ports = []
Devin Lim142b5342017-07-20 15:22:39 -0700527 ports.append( ctrl.CLI.ports() )
Jon Hall85794ff2015-07-08 14:12:30 -0700528 links = []
Devin Lim142b5342017-07-20 15:22:39 -0700529 links.append( ctrl.CLI.links() )
Jon Hall85794ff2015-07-08 14:12:30 -0700530 clusters = []
Devin Lim142b5342017-07-20 15:22:39 -0700531 clusters.append( ctrl.CLI.clusters() )
Jon Hall85794ff2015-07-08 14:12:30 -0700532
533 elapsed = time.time() - startTime
534 cliTime = time.time() - cliStart
535 print "CLI time: " + str( cliTime )
536
537 mnSwitches = main.Mininet1.getSwitches()
538 mnLinks = main.Mininet1.getLinks()
539 mnHosts = main.Mininet1.getHosts()
Devin Lim142b5342017-07-20 15:22:39 -0700540 for controller in main.Cluster.getRunningPos():
541 controllerStr = str( controller )
Jon Hall85794ff2015-07-08 14:12:30 -0700542 if devices[ controller ] and ports[ controller ] and\
Jon Hallf37d44d2017-05-24 10:37:30 -0700543 "Error" not in devices[ controller ] and\
544 "Error" not in ports[ controller ]:
Jon Hall85794ff2015-07-08 14:12:30 -0700545
Jon Hallc6793552016-01-19 14:18:37 -0800546 try:
547 currentDevicesResult = main.Mininet1.compareSwitches(
548 mnSwitches,
549 json.loads( devices[ controller ] ),
550 json.loads( ports[ controller ] ) )
Jon Halla478b852017-12-04 15:00:15 -0800551 except ( TypeError, ValueError ):
Jon Hallc6793552016-01-19 14:18:37 -0800552 main.log.exception( "Object not as expected; devices={!r}\nports={!r}".format(
553 devices[ controller ], ports[ controller ] ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700554 else:
555 currentDevicesResult = main.FALSE
556 utilities.assert_equals( expect=main.TRUE,
557 actual=currentDevicesResult,
558 onpass="ONOS" + controllerStr +
559 " Switches view is correct",
560 onfail="ONOS" + controllerStr +
561 " Switches view is incorrect" )
562
563 if links[ controller ] and "Error" not in links[ controller ]:
564 currentLinksResult = main.Mininet1.compareLinks(
565 mnSwitches, mnLinks,
566 json.loads( links[ controller ] ) )
567 else:
568 currentLinksResult = main.FALSE
569 utilities.assert_equals( expect=main.TRUE,
570 actual=currentLinksResult,
571 onpass="ONOS" + controllerStr +
572 " links view is correct",
573 onfail="ONOS" + controllerStr +
574 " links view is incorrect" )
575
576 if hosts[ controller ] or "Error" not in hosts[ controller ]:
577 currentHostsResult = main.Mininet1.compareHosts(
578 mnHosts,
579 hosts[ controller ] )
580 else:
581 currentHostsResult = main.FALSE
582 utilities.assert_equals( expect=main.TRUE,
583 actual=currentHostsResult,
584 onpass="ONOS" + controllerStr +
585 " hosts exist in Mininet",
586 onfail="ONOS" + controllerStr +
587 " hosts don't match Mininet" )
588 # CHECKING HOST ATTACHMENT POINTS
589 hostAttachment = True
590 zeroHosts = False
591 # FIXME: topo-HA/obelisk specific mappings:
592 # key is mac and value is dpid
593 mappings = {}
594 for i in range( 1, 29 ): # hosts 1 through 28
595 # set up correct variables:
Jon Hallf37d44d2017-05-24 10:37:30 -0700596 macId = "00:" * 5 + hex( i ).split( "0x" )[ 1 ].upper().zfill( 2 )
Jon Hall85794ff2015-07-08 14:12:30 -0700597 if i == 1:
Jon Hallf37d44d2017-05-24 10:37:30 -0700598 deviceId = "1000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700599 elif i == 2:
Jon Hallf37d44d2017-05-24 10:37:30 -0700600 deviceId = "2000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700601 elif i == 3:
Jon Hallf37d44d2017-05-24 10:37:30 -0700602 deviceId = "3000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700603 elif i == 4:
Jon Hallf37d44d2017-05-24 10:37:30 -0700604 deviceId = "3004".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700605 elif i == 5:
Jon Hallf37d44d2017-05-24 10:37:30 -0700606 deviceId = "5000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700607 elif i == 6:
Jon Hallf37d44d2017-05-24 10:37:30 -0700608 deviceId = "6000".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700609 elif i == 7:
Jon Hallf37d44d2017-05-24 10:37:30 -0700610 deviceId = "6007".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700611 elif i >= 8 and i <= 17:
612 dpid = '3' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700613 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700614 elif i >= 18 and i <= 27:
615 dpid = '6' + str( i ).zfill( 3 )
Jon Hallf37d44d2017-05-24 10:37:30 -0700616 deviceId = dpid.zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700617 elif i == 28:
Jon Hallf37d44d2017-05-24 10:37:30 -0700618 deviceId = "2800".zfill( 16 )
Jon Hall85794ff2015-07-08 14:12:30 -0700619 mappings[ macId ] = deviceId
620 if hosts[ controller ] or "Error" not in hosts[ controller ]:
621 if hosts[ controller ] == []:
622 main.log.warn( "There are no hosts discovered" )
623 zeroHosts = True
624 else:
625 for host in hosts[ controller ]:
626 mac = None
627 location = None
628 device = None
629 port = None
630 try:
631 mac = host.get( 'mac' )
632 assert mac, "mac field could not be found for this host object"
633
Jeremy Ronquillo0e538bc2017-06-13 15:16:09 -0700634 location = host.get( 'locations' )[ 0 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700635 assert location, "location field could not be found for this host object"
636
637 # Trim the protocol identifier off deviceId
Jon Hallf37d44d2017-05-24 10:37:30 -0700638 device = str( location.get( 'elementId' ) ).split( ':' )[ 1 ]
Jon Hall85794ff2015-07-08 14:12:30 -0700639 assert device, "elementId field could not be found for this host location object"
640
641 port = location.get( 'port' )
642 assert port, "port field could not be found for this host location object"
643
644 # Now check if this matches where they should be
645 if mac and device and port:
646 if str( port ) != "1":
647 main.log.error( "The attachment port is incorrect for " +
648 "host " + str( mac ) +
Jon Hallf37d44d2017-05-24 10:37:30 -0700649 ". Expected: 1 Actual: " + str( port ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700650 hostAttachment = False
651 if device != mappings[ str( mac ) ]:
652 main.log.error( "The attachment device is incorrect for " +
653 "host " + str( mac ) +
654 ". Expected: " + mappings[ str( mac ) ] +
655 " Actual: " + device )
656 hostAttachment = False
657 else:
658 hostAttachment = False
659 except AssertionError:
660 main.log.exception( "Json object not as expected" )
661 main.log.error( repr( host ) )
662 hostAttachment = False
663 else:
664 main.log.error( "No hosts json output or \"Error\"" +
665 " in output. hosts = " +
666 repr( hosts[ controller ] ) )
667 if zeroHosts is False:
668 hostAttachment = True
669
Jon Hall85794ff2015-07-08 14:12:30 -0700670 devicesResults = devicesResults and currentDevicesResult
671 linksResults = linksResults and currentLinksResult
672 hostsResults = hostsResults and currentHostsResult
673 hostAttachmentResults = hostAttachmentResults and\
674 hostAttachment
675
Jon Halla440e872016-03-31 15:15:50 -0700676 # "consistent" results don't make sense for single instance
Jon Hall85794ff2015-07-08 14:12:30 -0700677 # there should always only be one cluster
Jon Hall85794ff2015-07-08 14:12:30 -0700678 clusterResults = main.FALSE
Jon Halla440e872016-03-31 15:15:50 -0700679 try:
680 numClusters = len( json.loads( clusters[ 0 ] ) )
681 except ( ValueError, TypeError ):
682 main.log.exception( "Error parsing clusters[0]: " +
Jon Hallf37d44d2017-05-24 10:37:30 -0700683 repr( clusters[ 0 ] ) )
Jon Halla440e872016-03-31 15:15:50 -0700684 numClusters = "ERROR"
685 clusterResults = main.FALSE
Jon Hall85794ff2015-07-08 14:12:30 -0700686 if numClusters == 1:
687 clusterResults = main.TRUE
688 utilities.assert_equals(
689 expect=1,
690 actual=numClusters,
691 onpass="ONOS shows 1 SCC",
692 onfail="ONOS shows " + str( numClusters ) + " SCCs" )
693
694 topoResult = ( devicesResults and linksResults
695 and hostsResults and ipResult and clusterResults and
696 hostAttachmentResults )
697
698 topoResult = topoResult and int( count <= 2 )
699 note = "note it takes about " + str( int( cliTime ) ) + \
700 " seconds for the test to make all the cli calls to fetch " +\
701 "the topology from each ONOS instance"
702 main.log.info(
703 "Very crass estimate for topology discovery/convergence( " +
704 str( note ) + " ): " + str( elapsed ) + " seconds, " +
705 str( count ) + " tries" )
706 utilities.assert_equals( expect=main.TRUE, actual=topoResult,
707 onpass="Topology Check Test successful",
708 onfail="Topology Check Test NOT successful" )
Jon Hall41d39f12016-04-11 22:54:35 -0700709 main.step( "Checking ONOS nodes" )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800710 nodeResults = utilities.retry( main.Cluster.nodesCheck,
Jon Hall41d39f12016-04-11 22:54:35 -0700711 False,
Jon Hall41d39f12016-04-11 22:54:35 -0700712 attempts=5 )
713
714 utilities.assert_equals( expect=True, actual=nodeResults,
715 onpass="Nodes check successful",
716 onfail="Nodes check NOT successful" )
717 if not nodeResults:
Devin Lim142b5342017-07-20 15:22:39 -0700718 for ctrl in main.Cluster.active():
Jon Hall41d39f12016-04-11 22:54:35 -0700719 main.log.debug( "{} components not ACTIVE: \n{}".format(
Devin Lim142b5342017-07-20 15:22:39 -0700720 ctrl.name,
721 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
Jon Hall85794ff2015-07-08 14:12:30 -0700722
Jon Halld2871c22016-07-26 11:01:14 -0700723 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700724 main.cleanAndExit()
Jon Halld2871c22016-07-26 11:01:14 -0700725
Jon Hall85794ff2015-07-08 14:12:30 -0700726 def CASE9( self, main ):
727 """
728 Link s3-s28 down
729 """
Devin Lim58046fa2017-07-05 16:55:00 -0700730 main.HA.linkDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700731
732 def CASE10( self, main ):
733 """
734 Link s3-s28 up
735 """
Devin Lim58046fa2017-07-05 16:55:00 -0700736 main.HA.linkUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700737
738 def CASE11( self, main ):
739 """
740 Switch Down
741 """
742 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700743 main.HA.switchDown( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700744
745 def CASE12( self, main ):
746 """
747 Switch Up
748 """
749 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700750 main.HA.switchUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700751
752 def CASE13( self, main ):
753 """
754 Clean up
755 """
Devin Lim58046fa2017-07-05 16:55:00 -0700756 main.HAlabels.append( "Restart" )
757 main.HAdata.append( str( main.restartTime ) )
758 main.HA.cleanUp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700759
760 def CASE14( self, main ):
761 """
762 start election app on all onos nodes
763 """
Devin Lim58046fa2017-07-05 16:55:00 -0700764 main.HA.startElectionApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700765
766 def CASE15( self, main ):
767 """
768 Check that Leadership Election is still functional
acsmars71adceb2015-08-31 15:09:26 -0700769 15.1 Run election on each node
770 15.2 Check that each node has the same leaders and candidates
771 15.3 Find current leader and withdraw
772 15.4 Check that a new node was elected leader
773 15.5 Check that that new leader was the candidate of old leader
774 15.6 Run for election on old leader
775 15.7 Check that oldLeader is a candidate, and leader if only 1 node
776 15.8 Make sure that the old leader was added to the candidate list
777
778 old and new variable prefixes refer to data from before vs after
779 withdrawl and later before withdrawl vs after re-election
Jon Hall85794ff2015-07-08 14:12:30 -0700780 """
Devin Lim58046fa2017-07-05 16:55:00 -0700781 main.HA.isElectionFunctional( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700782
783 def CASE16( self, main ):
784 """
785 Install Distributed Primitives app
786 """
Devin Lim58046fa2017-07-05 16:55:00 -0700787 main.HA.installDistributedPrimitiveApp( main )
Jon Hall85794ff2015-07-08 14:12:30 -0700788
789 def CASE17( self, main ):
790 """
791 Check for basic functionality with distributed primitives
792 """
Devin Lim58046fa2017-07-05 16:55:00 -0700793 main.HA.checkDistPrimitivesFunc( main )