blob: 34a373a3f7dbb45752d3a9d139d32412efc6237e [file] [log] [blame]
Jon Hallca319892017-06-15 15:25:22 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2017 Open Networking Foundation ( ONF )
Jon Hallca319892017-06-15 15:25:22 -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.
Jon Hallca319892017-06-15 15:25:22 -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"""
Devin Lim3ebd5e72017-11-14 10:38:00 -080021import json
Jon Hallca319892017-06-15 15:25:22 -070022class Cluster():
23
24 def __str__( self ):
25 return self.name
Jon Hall4173b242017-09-12 17:04:38 -070026
Jon Hallca319892017-06-15 15:25:22 -070027 def __repr__( self ):
Jon Hallca319892017-06-15 15:25:22 -070028 controllers = []
Devin Lim142b5342017-07-20 15:22:39 -070029 runningNodes = []
Jon Hallca319892017-06-15 15:25:22 -070030 for ctrl in self.controllers:
31 controllers.append( str( ctrl ) )
32 return "%s[%s]" % ( self.name, ", ".join( controllers ) )
33
Jon Hallca319892017-06-15 15:25:22 -070034 def __init__( self, ctrlList=[], name="Cluster" ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070035 """
Devin Lim142b5342017-07-20 15:22:39 -070036 controllers : All the nodes
37 runningNodes : Node that are specifically running from the test.
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070038 ie ) When the test is testing different number of nodes on each
Devin Lim142b5342017-07-20 15:22:39 -070039 run.
40 numCtrls : number of runningNodes
41 maxCtrls : number of controllers
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070042 """
Jon Hallca319892017-06-15 15:25:22 -070043 self.controllers = ctrlList
Devin Lim142b5342017-07-20 15:22:39 -070044 self.runningNodes = ctrlList
45 self.numCtrls = len( self.runningNodes )
46 self.maxCtrls = len( self.controllers )
Jon Hallca319892017-06-15 15:25:22 -070047 self.name = str( name )
48 self.iterator = iter( self.active() )
49
Devin Lim142b5342017-07-20 15:22:39 -070050 def getIps( self, activeOnly=False, allNode=False ):
51 """
52 Description:
53 get the list of the ip. Default to get ips of running nodes.
54 Required:
55 * activeOnly - True for getting ips of active nodes
56 * allNode - True for getting ips of all nodes
57 Returns:
58 Retruns ips of active nodes if activeOnly is True.
59 Returns ips of all nodes if allNode is True.
60 """
Jon Hallca319892017-06-15 15:25:22 -070061 ips = []
Devin Lim142b5342017-07-20 15:22:39 -070062 if allNode:
Jon Hallca319892017-06-15 15:25:22 -070063 nodeList = self.controllers
Devin Lim142b5342017-07-20 15:22:39 -070064 else:
65 if activeOnly:
66 nodeList = self.active()
67 else:
68 nodeList = self.runningNodes
69
Jon Hallca319892017-06-15 15:25:22 -070070 for ctrl in nodeList:
71 ips.append( ctrl.ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -070072
Jon Hallca319892017-06-15 15:25:22 -070073 return ips
74
Devin Lim142b5342017-07-20 15:22:39 -070075 def resetActive( self ):
Jon Hallca319892017-06-15 15:25:22 -070076 """
Devin Lim142b5342017-07-20 15:22:39 -070077 Description:
78 reset the activeness of the runningNodes to be false
79 Required:
80 Returns:
Jon Hallca319892017-06-15 15:25:22 -070081 """
Devin Lim142b5342017-07-20 15:22:39 -070082 for ctrl in self.runningNodes:
83 ctrl.active = False
84
85 def getRunningPos( self ):
86 """
87 Description:
88 get the position of the active running nodes.
89 Required:
90 Returns:
91 Retruns the list of the position of the active
92 running nodes.
93 """
94 return [ ctrl.pos for ctrl in self.runningNodes
95 if ctrl.active ]
96
97 def setRunningNode( self, numCtrls ):
98 """
99 Description:
100 Set running nodes of n number of nodes.
101 It will create new list of runningNodes.
102 If numCtrls is a list, it will add the nodes of the
103 list.
104 Required:
105 * numCtrls - number of nodes to be set.
106 Returns:
107 """
108 self.runningNodes = []
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700109 for i in numCtrls if isinstance( numCtrls, list ) else range( numCtrls ):
Devin Lim142b5342017-07-20 15:22:39 -0700110 self.runningNodes.append( self.controllers[ i ] )
111 self.numCtrls = len( numCtrls ) if isinstance( numCtrls, list ) else numCtrls
112
113 def active( self, node=None ):
114 """
115 Description:
116 get the list/controller of the active controller.
117 Required:
118 * node - position of the node to get from the active controller.
119 Returns:
120 Return a list of active controllers in the cluster if node is None
121 if not, it will return the nth controller.
122 """
123 result = [ ctrl for ctrl in self.runningNodes
Jon Hallca319892017-06-15 15:25:22 -0700124 if ctrl.active ]
Devin Lim142b5342017-07-20 15:22:39 -0700125 return result if node is None else result[ node % len( result ) ]
Jon Hallca319892017-06-15 15:25:22 -0700126
127 def next( self ):
128 """
129 An iterator for the cluster's controllers that
130 resets when there are no more elements.
131
132 Returns the next controller in the cluster
133 """
134 try:
135 return self.iterator.next()
136 except StopIteration:
137 self.reset()
138 try:
139 return self.iterator.next()
140 except StopIteration:
141 raise RuntimeError( "There are no active nodes in the cluster" )
142
143 def reset( self ):
144 """
145 Resets the cluster iterator.
146
147 This should be used whenever a node's active state is changed
148 and is also used internally when the iterator has been exhausted.
149 """
150 self.iterator = iter( self.active() )
151
You Wanga0f6ff62018-01-11 15:46:30 -0800152 def createCell( self, cellName, cellApps, mininetIp, useSSH, ips, installMax=False ):
Jon Hallca319892017-06-15 15:25:22 -0700153 """
Devin Lim142b5342017-07-20 15:22:39 -0700154 Description:
155 create a new cell
156 Required:
157 * cellName - The name of the cell.
You Wang09b596b2018-01-10 10:42:38 -0800158 * cellApps - The ONOS apps string.
You Wanga0f6ff62018-01-11 15:46:30 -0800159 * mininetIp - Mininet IP address.
Devin Lim142b5342017-07-20 15:22:39 -0700160 * useSSH - True for using ssh when creating a cell
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700161 * ips - ip( s ) of the node( s ).
Devin Lim142b5342017-07-20 15:22:39 -0700162 Returns:
163 """
You Wang09b596b2018-01-10 10:42:38 -0800164 try:
165 apps = main.apps
166 except ( NameError, AttributeError ):
167 apps = cellApps
Devin Lime9f0ccf2017-08-11 17:25:12 -0700168 self.command( "createCellFile",
169 args=[ main.ONOSbench.ip_address,
Devin Lim40a19092017-08-15 14:54:22 -0700170 cellName,
You Wanga0f6ff62018-01-11 15:46:30 -0800171 mininetIp,
You Wang09b596b2018-01-10 10:42:38 -0800172 apps,
Devin Lim40a19092017-08-15 14:54:22 -0700173 ips,
174 main.ONOScell.karafUser,
175 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700176 specificDriver=1,
177 getFrom=0 if installMax else 1 )
Devin Lim40a19092017-08-15 14:54:22 -0700178
Devin Lim142b5342017-07-20 15:22:39 -0700179 def uninstall( self, uninstallMax ):
180 """
181 Description:
182 uninstalling onos
183 Required:
184 * uninstallMax - True for uninstalling max number of nodes
185 False for uninstalling the current running nodes.
186 Returns:
187 Returns main.TRUE if it successfully uninstalled.
188 """
Devin Lim40a19092017-08-15 14:54:22 -0700189 result = main.TRUE
190 uninstallResult = self.command( "onosUninstall",
Jon Hall4173b242017-09-12 17:04:38 -0700191 kwargs={ "nodeIp": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700192 specificDriver=1,
193 getFrom=0 if uninstallMax else 1,
194 funcFromCtrl=True )
195 for uninstallR in uninstallResult:
196 result = result and uninstallR
197 return result
Devin Lim142b5342017-07-20 15:22:39 -0700198
Devin Lime9f0ccf2017-08-11 17:25:12 -0700199 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700200 """
201 Description:
202 apply the cell with cellName. It will also verify the
203 cell.
204 Required:
205 * cellName - The name of the cell.
206 Returns:
207 Returns main.TRUE if it successfully set and verify cell.
208 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700209 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700210 args=[ cellName ],
211 specificDriver=1,
212 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700213 verifyResult = self.command( "verifyCell",
Jon Hall4173b242017-09-12 17:04:38 -0700214 specificDriver=1,
215 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700216 result = main.TRUE
217 for i in range( len( setCellResult ) ):
218 result = result and setCellResult[ i ] and verifyResult[ i ]
219 return result
Devin Lim142b5342017-07-20 15:22:39 -0700220
221 def checkService( self ):
222 """
223 Description:
224 Checking if the onos service is up. If not, it will
225 start the onos service manually.
226 Required:
227 Returns:
228 Returns main.TRUE if it successfully checked
229 """
230 stopResult = main.TRUE
231 startResult = main.TRUE
232 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700233 onosUp = self.command( "isup",
234 args=[ "ipAddress" ],
235 specificDriver=1,
236 getFrom=1,
237 funcFromCtrl=True )
238 for i in range( len( onosUp ) ):
239 ctrl = self.controllers[ i ]
240 onosIsUp = onosIsUp and onosUp[ i ]
241 if onosUp[ i ] == main.TRUE:
242 main.log.report( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700243 else:
Devin Lim40a19092017-08-15 14:54:22 -0700244 main.log.report( ctrl.name + " may not be up, stop and " +
Devin Lim142b5342017-07-20 15:22:39 -0700245 "start ONOS again " )
246 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
247 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
248 if not startResult or stopResult:
Devin Lim40a19092017-08-15 14:54:22 -0700249 main.log.report( ctrl.name + " did not start correctly." )
Devin Lim142b5342017-07-20 15:22:39 -0700250 return onosIsUp and stopResult and startResult
251
252 def kill( self, killMax, stopOnos ):
253 """
254 Description:
255 killing the onos. It will either kill the current runningnodes or
256 max number of the nodes.
257 Required:
258 * killRemoveMax - The boolean that will decide either to kill
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700259 only running nodes ( False ) or max number of nodes ( True ).
Devin Lim142b5342017-07-20 15:22:39 -0700260 * stopOnos - If wish to stop onos before killing it. True for
261 enable stop , False for disable stop.
262 Returns:
263 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700264 """
265 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700266 killResult = self.command( "onosKill",
267 args=[ "ipAddress" ],
268 specificDriver=1,
269 getFrom=0 if killMax else 1,
270 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700271 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700272 result = result and killResult[ i ]
273 self.controllers[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700274 return result
275
276 def ssh( self ):
277 """
278 Description:
279 set up ssh to the onos
280 Required:
281 Returns:
282 Returns main.TRUE if it successfully setup the ssh to
283 the onos.
284 """
Devin Lim40a19092017-08-15 14:54:22 -0700285 result = main.TRUE
286 sshResult = self.command( "onosSecureSSH",
Jon Hall4173b242017-09-12 17:04:38 -0700287 kwargs={ "node": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700288 specificDriver=1,
289 getFrom=1,
290 funcFromCtrl=True )
291 for sshR in sshResult:
292 result = result and sshR
293 return result
Devin Lim142b5342017-07-20 15:22:39 -0700294
Devin Lime9f0ccf2017-08-11 17:25:12 -0700295 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700296 """
297 Description:
298 Installing onos.
299 Required:
300 * installMax - True for installing max number of nodes
301 False for installing current running nodes only.
302 Returns:
303 Returns main.TRUE if it successfully installed
304 """
305 result = main.TRUE
306 threads = []
307 i = 0
308 for ctrl in self.controllers if installMax else self.runningNodes:
309 options = "-f"
310 if installMax and i >= self.numCtrls:
311 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700312 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700313 t = main.Thread( target=ctrl.Bench.onosInstall,
314 name="install-" + ctrl.name,
315 kwargs={ "node" : ctrl.ipAddress,
316 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700317 threads.append( t )
318 t.start()
319 else:
320 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700321 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700322 if installParallel:
323 for t in threads:
324 t.join()
325 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700326 return result
327
328 def startCLIs( self ):
329 """
Devin Lim142b5342017-07-20 15:22:39 -0700330 Description:
331 starting Onos using onosCli driver
332 Required:
333 Returns:
334 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700335 """
Devin Lim40a19092017-08-15 14:54:22 -0700336 result = main.TRUE
337 cliResults = self.command( "startOnosCli",
338 args=[ "ipAddress" ],
339 specificDriver=2,
340 getFrom=1,
341 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700342 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700343 result = result and cliResults[ i ]
344 self.controllers[ i ].active = True
345 return result
Jon Hallca319892017-06-15 15:25:22 -0700346
Devin Lim3ebd5e72017-11-14 10:38:00 -0800347 def nodesCheck( self ):
348 results = True
349 nodesOutput = self.command( "nodes", specificDriver=2 )
350 ips = sorted( self.getIps( activeOnly=True ) )
351 for i in nodesOutput:
352 try:
353 current = json.loads( i )
354 activeIps = []
355 currentResult = False
356 for node in current:
357 if node[ 'state' ] == 'READY':
358 activeIps.append( node[ 'ip' ] )
359 activeIps.sort()
360 if ips == activeIps:
361 currentResult = True
362 except ( ValueError, TypeError ):
363 main.log.error( "Error parsing nodes output" )
364 main.log.warn( repr( i ) )
365 currentResult = False
366 results = results and currentResult
367 return results
368
Devin Lim142b5342017-07-20 15:22:39 -0700369 def printResult( self, results, activeList, logLevel="debug" ):
370 """
371 Description:
372 Print the value of the list.
373 Required:
374 * results - list of the result
375 * activeList - list of the acitve nodes.
376 * logLevel - Type of log level you want it to be printed.
377 Returns:
378 """
379 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700380 for i in range( len( results ) ):
381 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700382
383 def allTrueResultCheck( self, results, activeList ):
384 """
385 Description:
386 check if all the result has main.TRUE.
387 Required:
388 * results - list of the result
389 * activeList - list of the acitve nodes.
390 Returns:
391 Returns True if all == main.TRUE else
392 returns False
393 """
394 self.printResult( results, activeList )
395 return all( result == main.TRUE for result in results )
396
397 def notEmptyResultCheck( self, results, activeList ):
398 """
399 Description:
400 check if all the result has any contents
401 Required:
402 * results - list of the result
403 * activeList - list of the acitve nodes.
404 Returns:
405 Returns True if all the results has
406 something else returns False
407 """
408 self.printResult( results, activeList )
409 return all( result for result in results )
410
411 def identicalResultsCheck( self, results, activeList ):
412 """
413 Description:
414 check if all the results has same output.
415 Required:
416 * results - list of the result
417 * activeList - list of the acitve nodes.
418 Returns:
419 Returns True if all the results has
420 same result else returns False
421 """
422 self.printResult( results, activeList )
423 resultOne = results[ 0 ]
424 return all( resultOne == result for result in results )
425
Devin Lime9f0ccf2017-08-11 17:25:12 -0700426 def command( self, function, args=(), kwargs={}, returnBool=False,
Devin Lim40a19092017-08-15 14:54:22 -0700427 specificDriver=0, contentCheck=False, getFrom=2,
428 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700429 """
430 Description:
431 execute some function of the active nodes.
432 Required:
433 * function - name of the function
434 * args - argument of the function
435 * kwargs - kwargs of the funciton
436 * returnBool - True if wish to check all the result has main.TRUE
437 * specificDriver - specific driver to execute the function. Since
438 some of the function can be used in different drivers, it is important
439 to specify which driver it will be executed from.
440 0 - any type of driver
441 1 - from bench
442 2 - from cli
443 3 - from rest
444 * contentCheck - If this is True, it will check if the result has some
445 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700446 * getFrom - from which nodes
447 2 - active nodes
448 1 - current running nodes
449 0 - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700450 * funcFromCtrl - specific function of the args/kwargs
451 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700452 Returns:
453 Returns results if not returnBool and not contentCheck
454 Returns checkTruthValue of the result if returnBool
455 Returns resultContent of the result if contentCheck
456 """
Jon Hallca319892017-06-15 15:25:22 -0700457 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700458 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700459 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700460 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700461 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700462 try:
Devin Lim40a19092017-08-15 14:54:22 -0700463 funcArgs = []
464 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700465 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700466 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim40a19092017-08-15 14:54:22 -0700467 if funcFromCtrl:
468 if args:
469 for i in range( len( args ) ):
470 funcArgs.append( getattr( ctrl, args[ i ] ) )
471 if kwargs:
472 for k in kwargs:
Jon Hall4173b242017-09-12 17:04:38 -0700473 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
Devin Lim142b5342017-07-20 15:22:39 -0700474 except AttributeError:
475 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700476 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700477 t = main.Thread( target=f,
478 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700479 args=funcArgs if funcFromCtrl else args,
480 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700481 threads.append( t )
482 t.start()
483
484 for t in threads:
485 t.join()
486 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700487 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700488 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700489 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700490 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Jon Hall4173b242017-09-12 17:04:38 -0700491 return results
492
493 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
494 # max segment size in bytes: 1024 * 1024 * 64
495 # multiplier is somewhat arbitrary, but the idea is the logs would have
496 # been compacted before this many segments are written
497
498 maxSize = float( segmentSize ) * float( multiplier )
499 ret = True
500 for n in self.runningNodes:
Jon Hall5d5876e2017-11-30 09:33:16 -0800501 # Partition logs
502 ret = ret and n.server.folderSize( "/opt/onos/apache-karaf-*/data/db/partitions/*/*.log",
Jon Hall4173b242017-09-12 17:04:38 -0700503 size=maxSize, unit=units, ignoreRoot=False )
504 return ret