blob: 9c2d180e73f18305b74754e5a32e764367edc50e [file] [log] [blame]
Jon Hall69b2b982016-05-11 12:04:59 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070021"""
Jon Hall69b2b982016-05-11 12:04:59 -070022Description: This test is to determine if ONOS can handle
23 dynamic swapping of cluster nodes.
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: Swap nodes
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 Hall69b2b982016-05-11 12:04:59 -070045class HAswapNodes:
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 Hall69b2b982016-05-11 12:04:59 -070068 main.log.info( "ONOS HA test: Restart all ONOS nodes - " +
69 "initialization" )
Jon Hall69b2b982016-05-11 12:04:59 -070070 # set global variables
71 # These are for csv plotting in jenkins
Devin Lim58046fa2017-07-05 16:55:00 -070072 main.HAlabels = []
73 main.HAdata = []
74 try:
75 from tests.dependencies.ONOSSetup import ONOSSetup
76 main.testSetUp = ONOSSetup()
77 except ImportError:
78 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070079 main.cleanAndExit()
Devin Lim58046fa2017-07-05 16:55:00 -070080 main.testSetUp.envSetupDescription()
Jon Hall69b2b982016-05-11 12:04:59 -070081 try:
82 from tests.HA.dependencies.HA import HA
83 main.HA = HA()
84 from tests.HA.HAswapNodes.dependencies.Server import Server
85 main.Server = Server()
Devin Lim58046fa2017-07-05 16:55:00 -070086 # load some variables from the params file
87 cellName = main.params[ 'ENV' ][ 'cellName' ]
88 main.apps = main.params[ 'ENV' ][ 'appString' ]
Jon Hallab611372018-02-21 15:26:05 -080089 stepResult = main.testSetUp.envSetup( includeCaseDesc=False )
Jon Hall69b2b982016-05-11 12:04:59 -070090 except Exception as e:
Devin Lim58046fa2017-07-05 16:55:00 -070091 main.testSetUp.envSetupException( e )
92 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall69b2b982016-05-11 12:04:59 -070093
Jon Hallab611372018-02-21 15:26:05 -080094 applyFuncs = [ main.HA.setServerForCluster,
95 main.HA.swapNodeMetadata,
96 main.HA.copyBackupConfig,
97 main.HA.setMetadataUrl ]
98 applyArgs = [ None, None, None, None ]
99 try:
100 if main.params[ 'topology' ][ 'topoFile' ]:
101 main.log.info( 'Skipping start of Mininet in this case, make sure you start it elsewhere' )
102 else:
103 applyFuncs.append( main.HA.startingMininet )
104 applyArgs.append( None )
105 except (KeyError, IndexError):
106 applyFuncs.append( main.HA.startingMininet )
107 applyArgs.append( None )
108
You Wanga0f6ff62018-01-11 15:46:30 -0800109 main.testSetUp.ONOSSetUp( main.Cluster, cellName=cellName, removeLog=True,
Jon Hallab611372018-02-21 15:26:05 -0800110 extraApply=applyFuncs,
111 applyArgs=applyArgs,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700112 extraClean=main.HA.cleanUpOnosService,
Jon Hallab611372018-02-21 15:26:05 -0800113 installMax=True,
114 includeCaseDesc=False )
115 main.HA.initialSetUp( serviceClean=True )
116
117 main.step( 'Set logging levels' )
118 logging = True
119 try:
120 logs = main.params.get( 'ONOS_Logging', False )
121 if logs:
122 for namespace, level in logs.items():
123 for ctrl in main.Cluster.active():
124 ctrl.CLI.logSet( level, namespace )
125 except AttributeError:
126 logging = False
127 utilities.assert_equals( expect=True, actual=logging,
128 onpass="Set log levels",
129 onfail="Failed to set log levels" )
Jon Hall69b2b982016-05-11 12:04:59 -0700130
131 def CASE2( self, main ):
132 """
133 Assign devices to controllers
134 """
Devin Lim58046fa2017-07-05 16:55:00 -0700135 main.HA.assignDevices( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700136
Jon Hallab611372018-02-21 15:26:05 -0800137 def CASE102( self, main ):
138 """
139 Set up Spine-Leaf fabric topology in Mininet
140 """
141 main.HA.startTopology( main )
142
Jon Hall69b2b982016-05-11 12:04:59 -0700143 def CASE21( self, main ):
144 """
145 Assign mastership to controllers
146 """
Devin Lim58046fa2017-07-05 16:55:00 -0700147 main.HA.assignMastership( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700148
149 def CASE3( self, main ):
150 """
151 Assign intents
152 """
Devin Lim58046fa2017-07-05 16:55:00 -0700153 main.HA.assignIntents( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700154
155 def CASE4( self, main ):
156 """
157 Ping across added host intents
158 """
Jon Hallca319892017-06-15 15:25:22 -0700159 main.HA.pingAcrossHostIntent( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700160
Jon Hallab611372018-02-21 15:26:05 -0800161 def CASE104( self, main ):
162 """
163 Ping Hosts
164 """
165 main.case( "Check connectivity" )
166 main.step( "Ping between all hosts" )
167 pingResult = main.Mininet1.pingall()
168 utilities.assert_equals( expect=main.TRUE, actual=pingResult,
169 onpass="All Pings Passed",
170 onfail="Failed to ping between all hosts" )
171
Jon Hall69b2b982016-05-11 12:04:59 -0700172 def CASE5( self, main ):
173 """
174 Reading state of ONOS
175 """
Devin Lim58046fa2017-07-05 16:55:00 -0700176 main.HA.readingState( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700177
178 def CASE6( self, main ):
179 """
180 The Scaling case.
181 """
182 import time
Jon Hall69b2b982016-05-11 12:04:59 -0700183 assert main, "main not defined"
184 assert utilities.assert_equals, "utilities.assert_equals not defined"
Jon Hall69b2b982016-05-11 12:04:59 -0700185 try:
Devin Lim58046fa2017-07-05 16:55:00 -0700186 main.HAlabels
187 except ( NameError, AttributeError ):
188 main.log.error( "main.HAlabels not defined, setting to []" )
189 main.HAlabels = []
Jon Hall69b2b982016-05-11 12:04:59 -0700190 try:
Devin Lim58046fa2017-07-05 16:55:00 -0700191 main.HAdata
192 except ( NameError, AttributeError ):
193 main.log.error( "main.HAdata not defined, setting to []" )
194 main.HAdata = []
Jon Hall69b2b982016-05-11 12:04:59 -0700195
196 main.case( "Swap some of the ONOS nodes" )
197
198 main.step( "Checking ONOS Logs for errors" )
Devin Lim142b5342017-07-20 15:22:39 -0700199 for ctrl in main.Cluster.active():
200 main.log.debug( "Checking logs for errors on " + ctrl.name + ":" )
201 main.log.warn( main.ONOSbench.checkLogs( ctrl.ipAddress ) )
Jon Hall69b2b982016-05-11 12:04:59 -0700202
Devin Lim142b5342017-07-20 15:22:39 -0700203 activeNodes = main.Cluster.getRunningPos()
204 # Todo : this could be wrong. need to double check.
Jon Hall69b2b982016-05-11 12:04:59 -0700205 main.step( "Generate new metadata file" )
Devin Lim142b5342017-07-20 15:22:39 -0700206 old = [ activeNodes[ 1 ], activeNodes[ -2 ] ]
207 new = range( main.Cluster.maxCtrls )[ -2: ]
Jon Hall69b2b982016-05-11 12:04:59 -0700208 assert len( old ) == len( new ), "Length of nodes to swap don't match"
209 handle = main.ONOSbench.handle
210 for x, y in zip( old, new ):
211 handle.sendline( "export OC{}=$OC{}".format( x + 1, y + 1 ) )
212 handle.expect( "\$" ) # from the variable
213 ret = handle.before
214 handle.expect( "\$" ) # From the prompt
215 ret += handle.before
216 main.log.debug( ret )
Devin Lim142b5342017-07-20 15:22:39 -0700217 activeNodes.remove( x )
218 activeNodes.append( y )
Jon Hall69b2b982016-05-11 12:04:59 -0700219
Devin Lim142b5342017-07-20 15:22:39 -0700220 genResult = main.Server.generateFile( main.Cluster.numCtrls )
Jon Hall69b2b982016-05-11 12:04:59 -0700221 utilities.assert_equals( expect=main.TRUE, actual=genResult,
222 onpass="New cluster metadata file generated",
223 onfail="Failled to generate new metadata file" )
224 time.sleep( 5 ) # Give time for nodes to read new file
Devin Lim142b5342017-07-20 15:22:39 -0700225 main.Cluster.resetActive()
226 # Note : done up to this point.
Jon Hall69b2b982016-05-11 12:04:59 -0700227 main.step( "Start new nodes" ) # OR stop old nodes?
228 started = main.TRUE
229 for i in new:
Devin Lim142b5342017-07-20 15:22:39 -0700230 started = main.ONOSbench.onosStart( main.Cluster.controllers[ i ].ipAddress ) and main.TRUE
Jon Hall69b2b982016-05-11 12:04:59 -0700231 utilities.assert_equals( expect=main.TRUE, actual=started,
232 onpass="ONOS started",
233 onfail="ONOS start NOT successful" )
234
Devin Lim142b5342017-07-20 15:22:39 -0700235 main.Cluster.setRunningNode( activeNodes )
Jon Hall69b2b982016-05-11 12:04:59 -0700236
Devin Lim142b5342017-07-20 15:22:39 -0700237 main.testSetUp.setupSsh( main.Cluster )
238 main.testSetUp.checkOnosService( main.Cluster )
Jon Hall69b2b982016-05-11 12:04:59 -0700239
Devin Lim142b5342017-07-20 15:22:39 -0700240 main.testSetUp.startOnosClis( main.Cluster )
Jon Hall69b2b982016-05-11 12:04:59 -0700241
242 main.step( "Checking ONOS nodes" )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800243 nodeResults = utilities.retry( main.Cluster.nodesCheck,
Jon Hall69b2b982016-05-11 12:04:59 -0700244 False,
Jon Hall69b2b982016-05-11 12:04:59 -0700245 attempts=5 )
246 utilities.assert_equals( expect=True, actual=nodeResults,
247 onpass="Nodes check successful",
248 onfail="Nodes check NOT successful" )
249
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700250 ready = utilities.retry( main.Cluster.command,
Devin Lim142b5342017-07-20 15:22:39 -0700251 False,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700252 kwargs={ "function": "summary", "contentCheck": True },
Devin Lim142b5342017-07-20 15:22:39 -0700253 sleep=30,
254 attempts=10 )
Jon Hall69b2b982016-05-11 12:04:59 -0700255 utilities.assert_equals( expect=True, actual=ready,
256 onpass="ONOS summary command succeded",
257 onfail="ONOS summary command failed" )
258 if not ready:
Devin Lim44075962017-08-11 10:56:37 -0700259 main.cleanAndExit()
Jon Hall69b2b982016-05-11 12:04:59 -0700260
261 # Rerun for election on new nodes
262 runResults = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700263 for ctrl in main.Cluster.active():
264 run = ctrl.CLI.electionTestRun()
Jon Hall69b2b982016-05-11 12:04:59 -0700265 if run != main.TRUE:
Devin Lim142b5342017-07-20 15:22:39 -0700266 main.log.error( "Error running for election on " + ctrl.name )
Jon Hall69b2b982016-05-11 12:04:59 -0700267 runResults = runResults and run
268 utilities.assert_equals( expect=main.TRUE, actual=runResults,
269 onpass="Reran for election",
270 onfail="Failed to rerun for election" )
271
Devin Lim142b5342017-07-20 15:22:39 -0700272 main.HA.commonChecks()
273
Jon Hall69b2b982016-05-11 12:04:59 -0700274 def CASE7( self, main ):
275 """
276 Check state after ONOS scaling
277 """
Devin Lim142b5342017-07-20 15:22:39 -0700278 main.HA.checkStateAfterEvent( main, afterWhich=1 )
Jon Hall69b2b982016-05-11 12:04:59 -0700279
Jon Hall69b2b982016-05-11 12:04:59 -0700280 main.step( "Leadership Election is still functional" )
281 # Test of LeadershipElection
282 leaderList = []
283 leaderResult = main.TRUE
284
Devin Lim142b5342017-07-20 15:22:39 -0700285 for ctrl in main.Cluster.active():
286 leaderN = ctrl.CLI.electionTestLeader()
Jon Hall69b2b982016-05-11 12:04:59 -0700287 leaderList.append( leaderN )
288 if leaderN == main.FALSE:
289 # error in response
290 main.log.error( "Something is wrong with " +
291 "electionTestLeader function, check the" +
292 " error logs" )
293 leaderResult = main.FALSE
294 elif leaderN is None:
Devin Lim142b5342017-07-20 15:22:39 -0700295 main.log.error( ctrl.name +
Jon Hall69b2b982016-05-11 12:04:59 -0700296 " shows no leader for the election-app." )
297 leaderResult = main.FALSE
298 if len( set( leaderList ) ) != 1:
299 leaderResult = main.FALSE
300 main.log.error(
301 "Inconsistent view of leader for the election test app" )
Jon Hallab611372018-02-21 15:26:05 -0800302 main.log.debug( leaderList )
Jon Hall69b2b982016-05-11 12:04:59 -0700303 utilities.assert_equals(
304 expect=main.TRUE,
305 actual=leaderResult,
306 onpass="Leadership election passed",
307 onfail="Something went wrong with Leadership election" )
308
309 def CASE8( self, main ):
310 """
311 Compare topo
312 """
Devin Lim58046fa2017-07-05 16:55:00 -0700313 main.HA.compareTopo( main )
Jon Halld2871c22016-07-26 11:01:14 -0700314
Jon Hall69b2b982016-05-11 12:04:59 -0700315 def CASE9( self, main ):
316 """
Jon Hallab611372018-02-21 15:26:05 -0800317 Link down
Jon Hall69b2b982016-05-11 12:04:59 -0700318 """
Jon Hallab611372018-02-21 15:26:05 -0800319 src = main.params['kill']['linkSrc']
320 dst = main.params['kill']['linkDst']
321 main.HA.linkDown( main, src, dst )
Jon Hall69b2b982016-05-11 12:04:59 -0700322
323 def CASE10( self, main ):
324 """
Jon Hallab611372018-02-21 15:26:05 -0800325 Link up
Jon Hall69b2b982016-05-11 12:04:59 -0700326 """
Jon Hallab611372018-02-21 15:26:05 -0800327 src = main.params['kill']['linkSrc']
328 dst = main.params['kill']['linkDst']
329 main.HA.linkUp( main, src, dst )
Jon Hall69b2b982016-05-11 12:04:59 -0700330
331 def CASE11( self, main ):
332 """
333 Switch Down
334 """
335 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700336 main.HA.switchDown( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700337
338 def CASE12( self, main ):
339 """
340 Switch Up
341 """
342 # NOTE: You should probably run a topology check after this
Devin Lim58046fa2017-07-05 16:55:00 -0700343 main.HA.switchUp( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700344
345 def CASE13( self, main ):
346 """
347 Clean up
348 """
Devin Lim58046fa2017-07-05 16:55:00 -0700349 main.HA.cleanUp( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700350
351 main.step( "Stopping webserver" )
Jon Hallf37d44d2017-05-24 10:37:30 -0700352 status = main.Server.stop()
Jon Hall69b2b982016-05-11 12:04:59 -0700353 utilities.assert_equals( expect=main.TRUE, actual=status,
354 onpass="Stop Server",
355 onfail="Failled to stop SimpleHTTPServer" )
356 del main.Server
357
358 def CASE14( self, main ):
359 """
Jon Hallab611372018-02-21 15:26:05 -0800360 Start election app on all onos nodes
Jon Hall69b2b982016-05-11 12:04:59 -0700361 """
Devin Lim58046fa2017-07-05 16:55:00 -0700362 main.HA.startElectionApp( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700363
364 def CASE15( self, main ):
365 """
366 Check that Leadership Election is still functional
367 15.1 Run election on each node
368 15.2 Check that each node has the same leaders and candidates
369 15.3 Find current leader and withdraw
370 15.4 Check that a new node was elected leader
371 15.5 Check that that new leader was the candidate of old leader
372 15.6 Run for election on old leader
373 15.7 Check that oldLeader is a candidate, and leader if only 1 node
374 15.8 Make sure that the old leader was added to the candidate list
375
376 old and new variable prefixes refer to data from before vs after
377 withdrawl and later before withdrawl vs after re-election
378 """
Devin Lim58046fa2017-07-05 16:55:00 -0700379 main.HA.isElectionFunctional( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700380
381 def CASE16( self, main ):
382 """
383 Install Distributed Primitives app
384 """
Devin Lim58046fa2017-07-05 16:55:00 -0700385 main.HA.installDistributedPrimitiveApp( main )
Jon Hall69b2b982016-05-11 12:04:59 -0700386
387 def CASE17( self, main ):
388 """
389 Check for basic functionality with distributed primitives
390 """
Devin Lim58046fa2017-07-05 16:55:00 -0700391 main.HA.checkDistPrimitivesFunc( main )