blob: c3df068ced40106e30aea1998cec6a002bb09997 [file] [log] [blame]
Jon Halla478b852017-12-04 15:00:15 -08001"""
2Copyright 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"""
23Description: This test is to determine if ONOS can handle
24 a minority of it's nodes restarting
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
Jon Hallab611372018-02-21 15:26:05 -080033CASE60: Initialize the upgrade.
34CASE61: Upgrade a minority of nodes PHASE 1
35CASE62: Transfer to new version. PHASE 2
36CASE63: Upgrade the rest of the nodes
37CASE64: Commit to the upgrade.
Jon Halla478b852017-12-04 15:00:15 -080038CASE7: Check state after control plane failure
39CASE8: Compare topo
40CASE9: Link s3-s28 down
41CASE10: Link s3-s28 up
42CASE11: Switch down
43CASE12: Switch up
44CASE13: Clean up
45CASE14: start election app on all onos nodes
46CASE15: Check that Leadership Election is still functional
47CASE16: Install Distributed Primitives app
48CASE17: Check for basic functionality with distributed primitives
49"""
50class HAupgrade:
51
52 def __init__( self ):
53 self.default = ''
54
55 def CASE1( self, main ):
56 """
57 CASE1 is to compile ONOS and push it to the test machines
58
59 Startup sequence:
60 cell <name>
61 onos-verify-cell
62 NOTE: temporary - onos-remove-raft-logs
63 onos-uninstall
64 start mininet
65 git pull
66 mvn clean install
67 onos-package
68 onos-install -f
69 onos-wait-for-start
70 start cli sessions
71 start tcpdump
72 """
73 main.log.info( "ONOS HA test: Stop a minority of ONOS nodes - " +
74 "initialization" )
75 # These are for csv plotting in jenkins
76 main.HAlabels = []
77 main.HAdata = []
78 try:
79 from tests.dependencies.ONOSSetup import ONOSSetup
80 main.testSetUp = ONOSSetup()
81 except ImportError:
82 main.log.error( "ONOSSetup not found. exiting the test" )
83 main.cleanAndExit()
84 main.testSetUp.envSetupDescription()
85 try:
86 from tests.HA.dependencies.HA import HA
87 main.HA = HA()
88 cellName = main.params[ 'ENV' ][ 'cellName' ]
89 main.apps = main.params[ 'ENV' ][ 'appString' ]
Jon Hallab611372018-02-21 15:26:05 -080090 stepResult = main.testSetUp.envSetup( includeCaseDesc=False )
Jon Halla478b852017-12-04 15:00:15 -080091 except Exception as e:
92 main.testSetUp.envSetupException( e )
Jon Hallaa1d9b82020-07-30 13:49:42 -070093 main.testSetUp.envSetupConclusion( stepResult )
Jon Hallab611372018-02-21 15:26:05 -080094
Jon Hall5a5c8432018-11-28 11:39:57 -080095 applyFuncs = [ main.HA.removeKarafConsoleLogging, main.HA.copyBackupConfig ]
96 applyArgs = [ None, None ]
Jon Hallab611372018-02-21 15:26:05 -080097 try:
98 if main.params[ 'topology' ][ 'topoFile' ]:
99 main.log.info( 'Skipping start of Mininet in this case, make sure you start it elsewhere' )
100 else:
101 applyFuncs.append( main.HA.startingMininet )
102 applyArgs.append( None )
103 except (KeyError, IndexError):
104 applyFuncs.append( main.HA.startingMininet )
105 applyArgs.append( None )
Jon Halla478b852017-12-04 15:00:15 -0800106
Jon Hall3e6edb32018-08-21 16:20:30 -0700107 main.testSetUp.ONOSSetUp( main.Cluster, cellName=cellName,
Jon Hallab611372018-02-21 15:26:05 -0800108 extraApply=applyFuncs,
109 applyArgs=applyArgs,
110 extraClean=main.HA.cleanUpGenPartition,
111 includeCaseDesc=False )
Jon Halla478b852017-12-04 15:00:15 -0800112
113 main.HA.initialSetUp( serviceClean=True )
114
Jon Hallab611372018-02-21 15:26:05 -0800115 main.step( 'Set logging levels' )
116 logging = True
117 try:
118 logs = main.params.get( 'ONOS_Logging', False )
119 if logs:
120 for namespace, level in logs.items():
121 for ctrl in main.Cluster.active():
122 ctrl.CLI.logSet( level, namespace )
123 except AttributeError:
124 logging = False
125 utilities.assert_equals( expect=True, actual=logging,
126 onpass="Set log levels",
127 onfail="Failed to set log levels" )
128
Jon Halla478b852017-12-04 15:00:15 -0800129 def CASE2( self, main ):
130 """
131 Assign devices to controllers
132 """
133 main.HA.assignDevices( main )
134
Jon Hallab611372018-02-21 15:26:05 -0800135 def CASE102( self, main ):
136 """
137 Set up Spine-Leaf fabric topology in Mininet
138 """
139 main.HA.startTopology( main )
140
Jon Halla478b852017-12-04 15:00:15 -0800141 def CASE21( self, main ):
142 """
143 Assign mastership to controllers
144 """
145 main.HA.assignMastership( main )
146
147 def CASE3( self, main ):
148 """
149 Assign intents
150 """
151 main.HA.assignIntents( main )
152
153 def CASE4( self, main ):
154 """
155 Ping across added host intents
156 """
157 main.HA.pingAcrossHostIntent( main )
158
Jon Hallab611372018-02-21 15:26:05 -0800159 def CASE104( self, main ):
160 """
161 Ping Hosts
162 """
163 main.case( "Check connectivity" )
164 main.step( "Ping between all hosts" )
165 pingResult = main.Mininet1.pingall()
166 utilities.assert_equals( expect=main.TRUE, actual=pingResult,
167 onpass="All Pings Passed",
168 onfail="Failed to ping between all hosts" )
169
Jon Halla478b852017-12-04 15:00:15 -0800170 def CASE5( self, main ):
171 """
172 Reading state of ONOS
173 """
174 main.HA.readingState( main )
175
176 def CASE60( self, main ):
177 """
178 Initialize the upgrade.
179 """
180 assert main, "main not defined"
181 assert utilities.assert_equals, "utilities.assert_equals not defined"
182 main.case( "Initialize upgrade" )
183 main.HA.upgradeInit( main )
184
185 def CASE61( self, main ):
186 """
187 Upgrade a minority of nodes PHASE 1
188 """
189 assert main, "main not defined"
190 assert utilities.assert_equals, "utilities.assert_equals not defined"
191 main.case( "Upgrade minority of ONOS nodes" )
192
193 main.step( "Checking ONOS Logs for errors" )
194 for ctrl in main.Cluster.active():
195 main.log.debug( "Checking logs for errors on " + ctrl.name + ":" )
196 main.log.warn( ctrl.checkLogs( ctrl.ipAddress ) )
197
198 main.kill = []
199 n = len( main.Cluster.runningNodes ) # Number of nodes
200 p = n / 2 # Number of nodes in the minority
201 for i in range( p ):
202 main.kill.append( main.Cluster.runningNodes[ i ] ) # ONOS node to kill, listed by index in main.nodes
203 main.HA.upgradeNodes( main )
204
Jon Hall30668ff2019-02-27 17:43:09 -0800205 main.testSetUp.checkOnosNodes( main.Cluster )
Jon Halla478b852017-12-04 15:00:15 -0800206
207 def CASE62( self, main ):
208 """
209 Transfer to new version. PHASE 2
210 """
211 assert main, "main not defined"
212 assert utilities.assert_equals, "utilities.assert_equals not defined"
213 main.case( "Start the upgrade" )
214
215 main.step( "Send the command to switch to new version" )
216 ctrl = main.Cluster.next().CLI
217 upgraded = ctrl.issuUpgrade()
218 utilities.assert_equals( expect=main.TRUE, actual=upgraded,
219 onpass="Cluster has moved to the upgraded nodes",
220 onfail="Error transitioning to the upgraded nodes" )
221
222 main.step( "Check the status of the upgrade" )
223 ctrl = main.Cluster.next().CLI
224 status = ctrl.issu()
225 main.log.debug( status )
226 # TODO: check things here?
227
Jon Hall30668ff2019-02-27 17:43:09 -0800228 main.testSetUp.checkOnosNodes( main.Cluster )
Jon Halla478b852017-12-04 15:00:15 -0800229
230 def CASE63( self, main ):
231 """
232 Upgrade the rest of the nodes
233 """
234 main.case( "Upgrade remaining nodes" )
235 upgraded = main.kill
236 main.kill = []
237 for node in main.Cluster.runningNodes:
238 if node not in upgraded:
239 main.kill.append( node )
240
241 main.HA.upgradeNodes( main )
Jon Hall30668ff2019-02-27 17:43:09 -0800242 main.testSetUp.checkOnosNodes( main.Cluster )
Jon Halla478b852017-12-04 15:00:15 -0800243
244 def CASE64( self, main ):
245 """
246 Commit to the upgrade.
247 """
248 assert main, "main not defined"
249 assert utilities.assert_equals, "utilities.assert_equals not defined"
250 main.case( "Commit upgrade" )
251
252 main.step( "Send the command to commit the upgrade" )
Jon Hall0e240372018-05-02 11:21:57 -0700253 for ctrl in main.Cluster.active():
254 status = ctrl.issu()
255 main.log.debug( status )
Jon Halla478b852017-12-04 15:00:15 -0800256 ctrl = main.Cluster.next().CLI
257 committed = ctrl.issuCommit()
258 utilities.assert_equals( expect=main.TRUE, actual=committed,
259 onpass="Upgrade has been committed",
260 onfail="Error committing the upgrade" )
Jon Hall0e240372018-05-02 11:21:57 -0700261 for ctrl in main.Cluster.active():
262 status = ctrl.issu()
263 main.log.debug( status )
Jon Halla478b852017-12-04 15:00:15 -0800264
265 main.step( "Check the status of the upgrade" )
266 ctrl = main.Cluster.next().CLI
267 status = ctrl.issu()
268 main.log.debug( status )
269 # TODO: check things here?
270
Jon Hallab611372018-02-21 15:26:05 -0800271 nodeResults = utilities.retry( main.Cluster.nodesCheck,
272 False,
273 sleep=15,
274 attempts=5 )
275 utilities.assert_equals( expect=True, actual=nodeResults,
276 onpass="Nodes check successful",
277 onfail="Nodes check NOT successful" )
278
Jon Halla478b852017-12-04 15:00:15 -0800279 def CASE7( self, main ):
280 """
281 Check state after ONOS failure
282 """
283 try:
284 main.kill
285 except AttributeError:
286 main.kill = []
287
288 main.HA.checkStateAfterEvent( main, afterWhich=0 )
289 main.step( "Leadership Election is still functional" )
290 # Test of LeadershipElection
291 leaderList = []
292
293 restarted = []
294 for ctrl in main.kill:
295 restarted.append( ctrl.ipAddress )
296 leaderResult = main.TRUE
297
298 for ctrl in main.Cluster.active():
299 leaderN = ctrl.electionTestLeader()
300 leaderList.append( leaderN )
301 if leaderN == main.FALSE:
302 # error in response
303 main.log.error( "Something is wrong with " +
304 "electionTestLeader function, check the" +
305 " error logs" )
306 leaderResult = main.FALSE
307 elif leaderN is None:
308 main.log.error( ctrl.name +
309 " shows no leader for the election-app was" +
310 " elected after the old one died" )
311 leaderResult = main.FALSE
312 elif leaderN in restarted:
313 main.log.error( ctrl.name + " shows " + str( leaderN ) +
314 " as leader for the election-app, but it " +
315 "was restarted" )
316 leaderResult = main.FALSE
317 if len( set( leaderList ) ) != 1:
318 leaderResult = main.FALSE
319 main.log.error(
320 "Inconsistent view of leader for the election test app" )
Jon Hallab611372018-02-21 15:26:05 -0800321 main.log.debug( leaderList )
Jon Halla478b852017-12-04 15:00:15 -0800322 utilities.assert_equals(
323 expect=main.TRUE,
324 actual=leaderResult,
325 onpass="Leadership election passed",
326 onfail="Something went wrong with Leadership election" )
327
328 def CASE8( self, main ):
329 """
330 Compare topo
331 """
332 main.HA.compareTopo( main )
333
334 def CASE9( self, main ):
335 """
Jon Hallab611372018-02-21 15:26:05 -0800336 Link down
Jon Halla478b852017-12-04 15:00:15 -0800337 """
Jon Hallab611372018-02-21 15:26:05 -0800338 src = main.params['kill']['linkSrc']
339 dst = main.params['kill']['linkDst']
340 main.HA.linkDown( main, src, dst )
Jon Halla478b852017-12-04 15:00:15 -0800341
342 def CASE10( self, main ):
343 """
Jon Hallab611372018-02-21 15:26:05 -0800344 Link up
Jon Halla478b852017-12-04 15:00:15 -0800345 """
Jon Hallab611372018-02-21 15:26:05 -0800346 src = main.params['kill']['linkSrc']
347 dst = main.params['kill']['linkDst']
348 main.HA.linkUp( main, src, dst )
Jon Halla478b852017-12-04 15:00:15 -0800349
350 def CASE11( self, main ):
351 """
352 Switch Down
353 """
354 # NOTE: You should probably run a topology check after this
355 main.HA.switchDown( main )
356
357 def CASE12( self, main ):
358 """
359 Switch Up
360 """
361 # NOTE: You should probably run a topology check after this
362 main.HA.switchUp( main )
363
364 def CASE13( self, main ):
365 """
366 Clean up
367 """
368 main.HAlabels.append( "Restart" )
369 main.HAdata.append( str( main.restartTime ) )
370 main.HA.cleanUp( main )
371
372 def CASE14( self, main ):
373 """
Jon Hallab611372018-02-21 15:26:05 -0800374 Start election app on all onos nodes
Jon Halla478b852017-12-04 15:00:15 -0800375 """
376 main.HA.startElectionApp( main )
377
378 def CASE15( self, main ):
379 """
380 Check that Leadership Election is still functional
381 15.1 Run election on each node
382 15.2 Check that each node has the same leaders and candidates
383 15.3 Find current leader and withdraw
384 15.4 Check that a new node was elected leader
385 15.5 Check that that new leader was the candidate of old leader
386 15.6 Run for election on old leader
387 15.7 Check that oldLeader is a candidate, and leader if only 1 node
388 15.8 Make sure that the old leader was added to the candidate list
389
390 old and new variable prefixes refer to data from before vs after
391 withdrawl and later before withdrawl vs after re-election
392 """
393 main.HA.isElectionFunctional( main )
394
395 def CASE16( self, main ):
396 """
397 Install Distributed Primitives app
398 """
399 main.HA.installDistributedPrimitiveApp( main )
400
401 def CASE17( self, main ):
402 """
403 Check for basic functionality with distributed primitives
404 """
405 main.HA.checkDistPrimitivesFunc( main )