blob: b0af55ebc246fcdf28be8caea9a08f7f83d63c03 [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
Devin Lime9f0ccf2017-08-11 17:25:12 -0700152 def createCell( self, cellName, Mininet, 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.
158 * Mininet - a mininet driver that will be used.
159 * useSSH - True for using ssh when creating a cell
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700160 * ips - ip( s ) of the node( s ).
Devin Lim142b5342017-07-20 15:22:39 -0700161 Returns:
162 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700163 self.command( "createCellFile",
164 args=[ main.ONOSbench.ip_address,
Devin Lim40a19092017-08-15 14:54:22 -0700165 cellName,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700166 Mininet if isinstance( Mininet, str ) else
Devin Lim40a19092017-08-15 14:54:22 -0700167 Mininet.ip_address,
168 main.apps,
169 ips,
170 main.ONOScell.karafUser,
171 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700172 specificDriver=1,
173 getFrom=0 if installMax else 1 )
Devin Lim40a19092017-08-15 14:54:22 -0700174
Devin Lim142b5342017-07-20 15:22:39 -0700175 def uninstall( self, uninstallMax ):
176 """
177 Description:
178 uninstalling onos
179 Required:
180 * uninstallMax - True for uninstalling max number of nodes
181 False for uninstalling the current running nodes.
182 Returns:
183 Returns main.TRUE if it successfully uninstalled.
184 """
Devin Lim40a19092017-08-15 14:54:22 -0700185 result = main.TRUE
186 uninstallResult = self.command( "onosUninstall",
Jon Hall4173b242017-09-12 17:04:38 -0700187 kwargs={ "nodeIp": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700188 specificDriver=1,
189 getFrom=0 if uninstallMax else 1,
190 funcFromCtrl=True )
191 for uninstallR in uninstallResult:
192 result = result and uninstallR
193 return result
Devin Lim142b5342017-07-20 15:22:39 -0700194
Devin Lime9f0ccf2017-08-11 17:25:12 -0700195 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700196 """
197 Description:
198 apply the cell with cellName. It will also verify the
199 cell.
200 Required:
201 * cellName - The name of the cell.
202 Returns:
203 Returns main.TRUE if it successfully set and verify cell.
204 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700205 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700206 args=[ cellName ],
207 specificDriver=1,
208 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700209 verifyResult = self.command( "verifyCell",
Jon Hall4173b242017-09-12 17:04:38 -0700210 specificDriver=1,
211 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700212 result = main.TRUE
213 for i in range( len( setCellResult ) ):
214 result = result and setCellResult[ i ] and verifyResult[ i ]
215 return result
Devin Lim142b5342017-07-20 15:22:39 -0700216
217 def checkService( self ):
218 """
219 Description:
220 Checking if the onos service is up. If not, it will
221 start the onos service manually.
222 Required:
223 Returns:
224 Returns main.TRUE if it successfully checked
225 """
226 stopResult = main.TRUE
227 startResult = main.TRUE
228 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700229 onosUp = self.command( "isup",
230 args=[ "ipAddress" ],
231 specificDriver=1,
232 getFrom=1,
233 funcFromCtrl=True )
234 for i in range( len( onosUp ) ):
235 ctrl = self.controllers[ i ]
236 onosIsUp = onosIsUp and onosUp[ i ]
237 if onosUp[ i ] == main.TRUE:
238 main.log.report( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700239 else:
Devin Lim40a19092017-08-15 14:54:22 -0700240 main.log.report( ctrl.name + " may not be up, stop and " +
Devin Lim142b5342017-07-20 15:22:39 -0700241 "start ONOS again " )
242 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
243 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
244 if not startResult or stopResult:
Devin Lim40a19092017-08-15 14:54:22 -0700245 main.log.report( ctrl.name + " did not start correctly." )
Devin Lim142b5342017-07-20 15:22:39 -0700246 return onosIsUp and stopResult and startResult
247
248 def kill( self, killMax, stopOnos ):
249 """
250 Description:
251 killing the onos. It will either kill the current runningnodes or
252 max number of the nodes.
253 Required:
254 * killRemoveMax - The boolean that will decide either to kill
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700255 only running nodes ( False ) or max number of nodes ( True ).
Devin Lim142b5342017-07-20 15:22:39 -0700256 * stopOnos - If wish to stop onos before killing it. True for
257 enable stop , False for disable stop.
258 Returns:
259 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700260 """
261 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700262 killResult = self.command( "onosKill",
263 args=[ "ipAddress" ],
264 specificDriver=1,
265 getFrom=0 if killMax else 1,
266 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700267 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700268 result = result and killResult[ i ]
269 self.controllers[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700270 return result
271
272 def ssh( self ):
273 """
274 Description:
275 set up ssh to the onos
276 Required:
277 Returns:
278 Returns main.TRUE if it successfully setup the ssh to
279 the onos.
280 """
Devin Lim40a19092017-08-15 14:54:22 -0700281 result = main.TRUE
282 sshResult = self.command( "onosSecureSSH",
Jon Hall4173b242017-09-12 17:04:38 -0700283 kwargs={ "node": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700284 specificDriver=1,
285 getFrom=1,
286 funcFromCtrl=True )
287 for sshR in sshResult:
288 result = result and sshR
289 return result
Devin Lim142b5342017-07-20 15:22:39 -0700290
Devin Lime9f0ccf2017-08-11 17:25:12 -0700291 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700292 """
293 Description:
294 Installing onos.
295 Required:
296 * installMax - True for installing max number of nodes
297 False for installing current running nodes only.
298 Returns:
299 Returns main.TRUE if it successfully installed
300 """
301 result = main.TRUE
302 threads = []
303 i = 0
304 for ctrl in self.controllers if installMax else self.runningNodes:
305 options = "-f"
306 if installMax and i >= self.numCtrls:
307 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700308 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700309 t = main.Thread( target=ctrl.Bench.onosInstall,
310 name="install-" + ctrl.name,
311 kwargs={ "node" : ctrl.ipAddress,
312 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700313 threads.append( t )
314 t.start()
315 else:
316 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700317 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700318 if installParallel:
319 for t in threads:
320 t.join()
321 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700322 return result
323
324 def startCLIs( self ):
325 """
Devin Lim142b5342017-07-20 15:22:39 -0700326 Description:
327 starting Onos using onosCli driver
328 Required:
329 Returns:
330 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700331 """
Devin Lim40a19092017-08-15 14:54:22 -0700332 result = main.TRUE
333 cliResults = self.command( "startOnosCli",
334 args=[ "ipAddress" ],
335 specificDriver=2,
336 getFrom=1,
337 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700338 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700339 result = result and cliResults[ i ]
340 self.controllers[ i ].active = True
341 return result
Jon Hallca319892017-06-15 15:25:22 -0700342
Devin Lim3ebd5e72017-11-14 10:38:00 -0800343 def nodesCheck( self ):
344 results = True
345 nodesOutput = self.command( "nodes", specificDriver=2 )
346 ips = sorted( self.getIps( activeOnly=True ) )
347 for i in nodesOutput:
348 try:
349 current = json.loads( i )
350 activeIps = []
351 currentResult = False
352 for node in current:
353 if node[ 'state' ] == 'READY':
354 activeIps.append( node[ 'ip' ] )
355 activeIps.sort()
356 if ips == activeIps:
357 currentResult = True
358 except ( ValueError, TypeError ):
359 main.log.error( "Error parsing nodes output" )
360 main.log.warn( repr( i ) )
361 currentResult = False
362 results = results and currentResult
363 return results
364
Devin Lim142b5342017-07-20 15:22:39 -0700365 def printResult( self, results, activeList, logLevel="debug" ):
366 """
367 Description:
368 Print the value of the list.
369 Required:
370 * results - list of the result
371 * activeList - list of the acitve nodes.
372 * logLevel - Type of log level you want it to be printed.
373 Returns:
374 """
375 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700376 for i in range( len( results ) ):
377 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700378
379 def allTrueResultCheck( self, results, activeList ):
380 """
381 Description:
382 check if all the result has main.TRUE.
383 Required:
384 * results - list of the result
385 * activeList - list of the acitve nodes.
386 Returns:
387 Returns True if all == main.TRUE else
388 returns False
389 """
390 self.printResult( results, activeList )
391 return all( result == main.TRUE for result in results )
392
393 def notEmptyResultCheck( self, results, activeList ):
394 """
395 Description:
396 check if all the result has any contents
397 Required:
398 * results - list of the result
399 * activeList - list of the acitve nodes.
400 Returns:
401 Returns True if all the results has
402 something else returns False
403 """
404 self.printResult( results, activeList )
405 return all( result for result in results )
406
407 def identicalResultsCheck( self, results, activeList ):
408 """
409 Description:
410 check if all the results has same output.
411 Required:
412 * results - list of the result
413 * activeList - list of the acitve nodes.
414 Returns:
415 Returns True if all the results has
416 same result else returns False
417 """
418 self.printResult( results, activeList )
419 resultOne = results[ 0 ]
420 return all( resultOne == result for result in results )
421
Devin Lime9f0ccf2017-08-11 17:25:12 -0700422 def command( self, function, args=(), kwargs={}, returnBool=False,
Devin Lim40a19092017-08-15 14:54:22 -0700423 specificDriver=0, contentCheck=False, getFrom=2,
424 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700425 """
426 Description:
427 execute some function of the active nodes.
428 Required:
429 * function - name of the function
430 * args - argument of the function
431 * kwargs - kwargs of the funciton
432 * returnBool - True if wish to check all the result has main.TRUE
433 * specificDriver - specific driver to execute the function. Since
434 some of the function can be used in different drivers, it is important
435 to specify which driver it will be executed from.
436 0 - any type of driver
437 1 - from bench
438 2 - from cli
439 3 - from rest
440 * contentCheck - If this is True, it will check if the result has some
441 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700442 * getFrom - from which nodes
443 2 - active nodes
444 1 - current running nodes
445 0 - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700446 * funcFromCtrl - specific function of the args/kwargs
447 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700448 Returns:
449 Returns results if not returnBool and not contentCheck
450 Returns checkTruthValue of the result if returnBool
451 Returns resultContent of the result if contentCheck
452 """
Jon Hallca319892017-06-15 15:25:22 -0700453 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700454 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700455 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700456 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700457 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700458 try:
Devin Lim40a19092017-08-15 14:54:22 -0700459 funcArgs = []
460 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700461 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700462 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim40a19092017-08-15 14:54:22 -0700463 if funcFromCtrl:
464 if args:
465 for i in range( len( args ) ):
466 funcArgs.append( getattr( ctrl, args[ i ] ) )
467 if kwargs:
468 for k in kwargs:
Jon Hall4173b242017-09-12 17:04:38 -0700469 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
Devin Lim142b5342017-07-20 15:22:39 -0700470 except AttributeError:
471 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700472 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700473 t = main.Thread( target=f,
474 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700475 args=funcArgs if funcFromCtrl else args,
476 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700477 threads.append( t )
478 t.start()
479
480 for t in threads:
481 t.join()
482 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700483 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700484 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700485 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700486 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Jon Hall4173b242017-09-12 17:04:38 -0700487 return results
488
489 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
490 # max segment size in bytes: 1024 * 1024 * 64
491 # multiplier is somewhat arbitrary, but the idea is the logs would have
492 # been compacted before this many segments are written
493
494 maxSize = float( segmentSize ) * float( multiplier )
495 ret = True
496 for n in self.runningNodes:
497 ret = ret and n.server.folderSize( "/opt/onos/apache-karaf-*/data/partitions/*/*.log",
498 size=maxSize, unit=units, ignoreRoot=False )
499 return ret