blob: af17ab58824c1de320c16587b835976482ddb214 [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 Wang09b596b2018-01-10 10:42:38 -0800152 def createCell( self, cellName, cellApps, 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.
You Wang09b596b2018-01-10 10:42:38 -0800158 * cellApps - The ONOS apps string.
Devin Lim142b5342017-07-20 15:22:39 -0700159 * Mininet - a mininet driver that will be used.
160 * 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,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700171 Mininet if isinstance( Mininet, str ) else
Devin Lim40a19092017-08-15 14:54:22 -0700172 Mininet.ip_address,
You Wang09b596b2018-01-10 10:42:38 -0800173 apps,
Devin Lim40a19092017-08-15 14:54:22 -0700174 ips,
175 main.ONOScell.karafUser,
176 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700177 specificDriver=1,
178 getFrom=0 if installMax else 1 )
Devin Lim40a19092017-08-15 14:54:22 -0700179
Devin Lim142b5342017-07-20 15:22:39 -0700180 def uninstall( self, uninstallMax ):
181 """
182 Description:
183 uninstalling onos
184 Required:
185 * uninstallMax - True for uninstalling max number of nodes
186 False for uninstalling the current running nodes.
187 Returns:
188 Returns main.TRUE if it successfully uninstalled.
189 """
Devin Lim40a19092017-08-15 14:54:22 -0700190 result = main.TRUE
191 uninstallResult = self.command( "onosUninstall",
Jon Hall4173b242017-09-12 17:04:38 -0700192 kwargs={ "nodeIp": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700193 specificDriver=1,
194 getFrom=0 if uninstallMax else 1,
195 funcFromCtrl=True )
196 for uninstallR in uninstallResult:
197 result = result and uninstallR
198 return result
Devin Lim142b5342017-07-20 15:22:39 -0700199
Devin Lime9f0ccf2017-08-11 17:25:12 -0700200 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700201 """
202 Description:
203 apply the cell with cellName. It will also verify the
204 cell.
205 Required:
206 * cellName - The name of the cell.
207 Returns:
208 Returns main.TRUE if it successfully set and verify cell.
209 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700210 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700211 args=[ cellName ],
212 specificDriver=1,
213 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700214 verifyResult = self.command( "verifyCell",
Jon Hall4173b242017-09-12 17:04:38 -0700215 specificDriver=1,
216 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700217 result = main.TRUE
218 for i in range( len( setCellResult ) ):
219 result = result and setCellResult[ i ] and verifyResult[ i ]
220 return result
Devin Lim142b5342017-07-20 15:22:39 -0700221
222 def checkService( self ):
223 """
224 Description:
225 Checking if the onos service is up. If not, it will
226 start the onos service manually.
227 Required:
228 Returns:
229 Returns main.TRUE if it successfully checked
230 """
231 stopResult = main.TRUE
232 startResult = main.TRUE
233 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700234 onosUp = self.command( "isup",
235 args=[ "ipAddress" ],
236 specificDriver=1,
237 getFrom=1,
238 funcFromCtrl=True )
239 for i in range( len( onosUp ) ):
240 ctrl = self.controllers[ i ]
241 onosIsUp = onosIsUp and onosUp[ i ]
242 if onosUp[ i ] == main.TRUE:
243 main.log.report( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700244 else:
Devin Lim40a19092017-08-15 14:54:22 -0700245 main.log.report( ctrl.name + " may not be up, stop and " +
Devin Lim142b5342017-07-20 15:22:39 -0700246 "start ONOS again " )
247 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
248 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
249 if not startResult or stopResult:
Devin Lim40a19092017-08-15 14:54:22 -0700250 main.log.report( ctrl.name + " did not start correctly." )
Devin Lim142b5342017-07-20 15:22:39 -0700251 return onosIsUp and stopResult and startResult
252
253 def kill( self, killMax, stopOnos ):
254 """
255 Description:
256 killing the onos. It will either kill the current runningnodes or
257 max number of the nodes.
258 Required:
259 * killRemoveMax - The boolean that will decide either to kill
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700260 only running nodes ( False ) or max number of nodes ( True ).
Devin Lim142b5342017-07-20 15:22:39 -0700261 * stopOnos - If wish to stop onos before killing it. True for
262 enable stop , False for disable stop.
263 Returns:
264 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700265 """
266 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700267 killResult = self.command( "onosKill",
268 args=[ "ipAddress" ],
269 specificDriver=1,
270 getFrom=0 if killMax else 1,
271 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700272 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700273 result = result and killResult[ i ]
274 self.controllers[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700275 return result
276
277 def ssh( self ):
278 """
279 Description:
280 set up ssh to the onos
281 Required:
282 Returns:
283 Returns main.TRUE if it successfully setup the ssh to
284 the onos.
285 """
Devin Lim40a19092017-08-15 14:54:22 -0700286 result = main.TRUE
287 sshResult = self.command( "onosSecureSSH",
Jon Hall4173b242017-09-12 17:04:38 -0700288 kwargs={ "node": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700289 specificDriver=1,
290 getFrom=1,
291 funcFromCtrl=True )
292 for sshR in sshResult:
293 result = result and sshR
294 return result
Devin Lim142b5342017-07-20 15:22:39 -0700295
Devin Lime9f0ccf2017-08-11 17:25:12 -0700296 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700297 """
298 Description:
299 Installing onos.
300 Required:
301 * installMax - True for installing max number of nodes
302 False for installing current running nodes only.
303 Returns:
304 Returns main.TRUE if it successfully installed
305 """
306 result = main.TRUE
307 threads = []
308 i = 0
309 for ctrl in self.controllers if installMax else self.runningNodes:
310 options = "-f"
311 if installMax and i >= self.numCtrls:
312 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700313 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700314 t = main.Thread( target=ctrl.Bench.onosInstall,
315 name="install-" + ctrl.name,
316 kwargs={ "node" : ctrl.ipAddress,
317 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700318 threads.append( t )
319 t.start()
320 else:
321 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700322 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700323 if installParallel:
324 for t in threads:
325 t.join()
326 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700327 return result
328
329 def startCLIs( self ):
330 """
Devin Lim142b5342017-07-20 15:22:39 -0700331 Description:
332 starting Onos using onosCli driver
333 Required:
334 Returns:
335 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700336 """
Devin Lim40a19092017-08-15 14:54:22 -0700337 result = main.TRUE
338 cliResults = self.command( "startOnosCli",
339 args=[ "ipAddress" ],
340 specificDriver=2,
341 getFrom=1,
342 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700343 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700344 result = result and cliResults[ i ]
345 self.controllers[ i ].active = True
346 return result
Jon Hallca319892017-06-15 15:25:22 -0700347
Devin Lim3ebd5e72017-11-14 10:38:00 -0800348 def nodesCheck( self ):
349 results = True
350 nodesOutput = self.command( "nodes", specificDriver=2 )
351 ips = sorted( self.getIps( activeOnly=True ) )
352 for i in nodesOutput:
353 try:
354 current = json.loads( i )
355 activeIps = []
356 currentResult = False
357 for node in current:
358 if node[ 'state' ] == 'READY':
359 activeIps.append( node[ 'ip' ] )
360 activeIps.sort()
361 if ips == activeIps:
362 currentResult = True
363 except ( ValueError, TypeError ):
364 main.log.error( "Error parsing nodes output" )
365 main.log.warn( repr( i ) )
366 currentResult = False
367 results = results and currentResult
368 return results
369
Devin Lim142b5342017-07-20 15:22:39 -0700370 def printResult( self, results, activeList, logLevel="debug" ):
371 """
372 Description:
373 Print the value of the list.
374 Required:
375 * results - list of the result
376 * activeList - list of the acitve nodes.
377 * logLevel - Type of log level you want it to be printed.
378 Returns:
379 """
380 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700381 for i in range( len( results ) ):
382 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700383
384 def allTrueResultCheck( self, results, activeList ):
385 """
386 Description:
387 check if all the result has main.TRUE.
388 Required:
389 * results - list of the result
390 * activeList - list of the acitve nodes.
391 Returns:
392 Returns True if all == main.TRUE else
393 returns False
394 """
395 self.printResult( results, activeList )
396 return all( result == main.TRUE for result in results )
397
398 def notEmptyResultCheck( self, results, activeList ):
399 """
400 Description:
401 check if all the result has any contents
402 Required:
403 * results - list of the result
404 * activeList - list of the acitve nodes.
405 Returns:
406 Returns True if all the results has
407 something else returns False
408 """
409 self.printResult( results, activeList )
410 return all( result for result in results )
411
412 def identicalResultsCheck( self, results, activeList ):
413 """
414 Description:
415 check if all the results has same output.
416 Required:
417 * results - list of the result
418 * activeList - list of the acitve nodes.
419 Returns:
420 Returns True if all the results has
421 same result else returns False
422 """
423 self.printResult( results, activeList )
424 resultOne = results[ 0 ]
425 return all( resultOne == result for result in results )
426
Devin Lime9f0ccf2017-08-11 17:25:12 -0700427 def command( self, function, args=(), kwargs={}, returnBool=False,
Devin Lim40a19092017-08-15 14:54:22 -0700428 specificDriver=0, contentCheck=False, getFrom=2,
429 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700430 """
431 Description:
432 execute some function of the active nodes.
433 Required:
434 * function - name of the function
435 * args - argument of the function
436 * kwargs - kwargs of the funciton
437 * returnBool - True if wish to check all the result has main.TRUE
438 * specificDriver - specific driver to execute the function. Since
439 some of the function can be used in different drivers, it is important
440 to specify which driver it will be executed from.
441 0 - any type of driver
442 1 - from bench
443 2 - from cli
444 3 - from rest
445 * contentCheck - If this is True, it will check if the result has some
446 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700447 * getFrom - from which nodes
448 2 - active nodes
449 1 - current running nodes
450 0 - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700451 * funcFromCtrl - specific function of the args/kwargs
452 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700453 Returns:
454 Returns results if not returnBool and not contentCheck
455 Returns checkTruthValue of the result if returnBool
456 Returns resultContent of the result if contentCheck
457 """
Jon Hallca319892017-06-15 15:25:22 -0700458 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700459 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700460 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700461 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700462 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700463 try:
Devin Lim40a19092017-08-15 14:54:22 -0700464 funcArgs = []
465 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700466 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700467 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim40a19092017-08-15 14:54:22 -0700468 if funcFromCtrl:
469 if args:
470 for i in range( len( args ) ):
471 funcArgs.append( getattr( ctrl, args[ i ] ) )
472 if kwargs:
473 for k in kwargs:
Jon Hall4173b242017-09-12 17:04:38 -0700474 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
Devin Lim142b5342017-07-20 15:22:39 -0700475 except AttributeError:
476 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700477 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700478 t = main.Thread( target=f,
479 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700480 args=funcArgs if funcFromCtrl else args,
481 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700482 threads.append( t )
483 t.start()
484
485 for t in threads:
486 t.join()
487 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700488 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700489 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700490 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700491 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Jon Hall4173b242017-09-12 17:04:38 -0700492 return results
493
494 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
495 # max segment size in bytes: 1024 * 1024 * 64
496 # multiplier is somewhat arbitrary, but the idea is the logs would have
497 # been compacted before this many segments are written
498
499 maxSize = float( segmentSize ) * float( multiplier )
500 ret = True
501 for n in self.runningNodes:
Jon Hall5d5876e2017-11-30 09:33:16 -0800502 # Partition logs
503 ret = ret and n.server.folderSize( "/opt/onos/apache-karaf-*/data/db/partitions/*/*.log",
Jon Hall4173b242017-09-12 17:04:38 -0700504 size=maxSize, unit=units, ignoreRoot=False )
505 return ret