blob: 16dfd79e3591c08f40335d140db7be3bfd03c547 [file] [log] [blame]
Jon Hallca319892017-06-15 15:25:22 -07001"""
2Copyright 2017 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
23class Cluster():
24
25 def __str__( self ):
26 return self.name
Jon Hall4173b242017-09-12 17:04:38 -070027
Jon Hallca319892017-06-15 15:25:22 -070028 def __repr__( self ):
Jon Hallca319892017-06-15 15:25:22 -070029 controllers = []
Devin Lim142b5342017-07-20 15:22:39 -070030 runningNodes = []
Jon Hallca319892017-06-15 15:25:22 -070031 for ctrl in self.controllers:
32 controllers.append( str( ctrl ) )
33 return "%s[%s]" % ( self.name, ", ".join( controllers ) )
34
Jon Hallca319892017-06-15 15:25:22 -070035 def __init__( self, ctrlList=[], name="Cluster" ):
Devin Lim142b5342017-07-20 15:22:39 -070036 '''
37 controllers : All the nodes
38 runningNodes : Node that are specifically running from the test.
39 ie) When the test is testing different number of nodes on each
40 run.
41 numCtrls : number of runningNodes
42 maxCtrls : number of controllers
43 '''
Jon Hallca319892017-06-15 15:25:22 -070044 self.controllers = ctrlList
Devin Lim142b5342017-07-20 15:22:39 -070045 self.runningNodes = ctrlList
46 self.numCtrls = len( self.runningNodes )
47 self.maxCtrls = len( self.controllers )
Jon Hallca319892017-06-15 15:25:22 -070048 self.name = str( name )
49 self.iterator = iter( self.active() )
50
Devin Lim142b5342017-07-20 15:22:39 -070051 def getIps( self, activeOnly=False, allNode=False ):
52 """
53 Description:
54 get the list of the ip. Default to get ips of running nodes.
55 Required:
56 * activeOnly - True for getting ips of active nodes
57 * allNode - True for getting ips of all nodes
58 Returns:
59 Retruns ips of active nodes if activeOnly is True.
60 Returns ips of all nodes if allNode is True.
61 """
Jon Hallca319892017-06-15 15:25:22 -070062 ips = []
Devin Lim142b5342017-07-20 15:22:39 -070063 if allNode:
Jon Hallca319892017-06-15 15:25:22 -070064 nodeList = self.controllers
Devin Lim142b5342017-07-20 15:22:39 -070065 else:
66 if activeOnly:
67 nodeList = self.active()
68 else:
69 nodeList = self.runningNodes
70
Jon Hallca319892017-06-15 15:25:22 -070071 for ctrl in nodeList:
72 ips.append( ctrl.ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -070073
Jon Hallca319892017-06-15 15:25:22 -070074 return ips
75
Devin Lim142b5342017-07-20 15:22:39 -070076 def resetActive( self ):
Jon Hallca319892017-06-15 15:25:22 -070077 """
Devin Lim142b5342017-07-20 15:22:39 -070078 Description:
79 reset the activeness of the runningNodes to be false
80 Required:
81 Returns:
Jon Hallca319892017-06-15 15:25:22 -070082 """
Devin Lim142b5342017-07-20 15:22:39 -070083 for ctrl in self.runningNodes:
84 ctrl.active = False
85
86 def getRunningPos( self ):
87 """
88 Description:
89 get the position of the active running nodes.
90 Required:
91 Returns:
92 Retruns the list of the position of the active
93 running nodes.
94 """
95 return [ ctrl.pos for ctrl in self.runningNodes
96 if ctrl.active ]
97
98 def setRunningNode( self, numCtrls ):
99 """
100 Description:
101 Set running nodes of n number of nodes.
102 It will create new list of runningNodes.
103 If numCtrls is a list, it will add the nodes of the
104 list.
105 Required:
106 * numCtrls - number of nodes to be set.
107 Returns:
108 """
109 self.runningNodes = []
110 for i in numCtrls if isinstance( numCtrls, list ) else range( numCtrls ) :
111 self.runningNodes.append( self.controllers[ i ] )
112 self.numCtrls = len( numCtrls ) if isinstance( numCtrls, list ) else numCtrls
113
114 def active( self, node=None ):
115 """
116 Description:
117 get the list/controller of the active controller.
118 Required:
119 * node - position of the node to get from the active controller.
120 Returns:
121 Return a list of active controllers in the cluster if node is None
122 if not, it will return the nth controller.
123 """
124 result = [ ctrl for ctrl in self.runningNodes
Jon Hallca319892017-06-15 15:25:22 -0700125 if ctrl.active ]
Devin Lim142b5342017-07-20 15:22:39 -0700126 return result if node is None else result[ node % len( result ) ]
Jon Hallca319892017-06-15 15:25:22 -0700127
128 def next( self ):
129 """
130 An iterator for the cluster's controllers that
131 resets when there are no more elements.
132
133 Returns the next controller in the cluster
134 """
135 try:
136 return self.iterator.next()
137 except StopIteration:
138 self.reset()
139 try:
140 return self.iterator.next()
141 except StopIteration:
142 raise RuntimeError( "There are no active nodes in the cluster" )
143
144 def reset( self ):
145 """
146 Resets the cluster iterator.
147
148 This should be used whenever a node's active state is changed
149 and is also used internally when the iterator has been exhausted.
150 """
151 self.iterator = iter( self.active() )
152
Devin Lime9f0ccf2017-08-11 17:25:12 -0700153 def createCell( self, cellName, Mininet, useSSH, ips, installMax=False ):
Jon Hallca319892017-06-15 15:25:22 -0700154 """
Devin Lim142b5342017-07-20 15:22:39 -0700155 Description:
156 create a new cell
157 Required:
158 * cellName - The name of the cell.
159 * Mininet - a mininet driver that will be used.
160 * useSSH - True for using ssh when creating a cell
161 * ips - ip(s) of the node(s).
162 Returns:
163 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700164 self.command( "createCellFile",
165 args=[ main.ONOSbench.ip_address,
Devin Lim40a19092017-08-15 14:54:22 -0700166 cellName,
167 Mininet if isinstance(Mininet, str) else
168 Mininet.ip_address,
169 main.apps,
170 ips,
171 main.ONOScell.karafUser,
172 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700173 specificDriver=1,
174 getFrom=0 if installMax else 1 )
Devin Lim40a19092017-08-15 14:54:22 -0700175
Devin Lim142b5342017-07-20 15:22:39 -0700176 def uninstall( self, uninstallMax ):
177 """
178 Description:
179 uninstalling onos
180 Required:
181 * uninstallMax - True for uninstalling max number of nodes
182 False for uninstalling the current running nodes.
183 Returns:
184 Returns main.TRUE if it successfully uninstalled.
185 """
Devin Lim40a19092017-08-15 14:54:22 -0700186 result = main.TRUE
187 uninstallResult = self.command( "onosUninstall",
Jon Hall4173b242017-09-12 17:04:38 -0700188 kwargs={ "nodeIp": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700189 specificDriver=1,
190 getFrom=0 if uninstallMax else 1,
191 funcFromCtrl=True )
192 for uninstallR in uninstallResult:
193 result = result and uninstallR
194 return result
Devin Lim142b5342017-07-20 15:22:39 -0700195
Devin Lime9f0ccf2017-08-11 17:25:12 -0700196 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700197 """
198 Description:
199 apply the cell with cellName. It will also verify the
200 cell.
201 Required:
202 * cellName - The name of the cell.
203 Returns:
204 Returns main.TRUE if it successfully set and verify cell.
205 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700206
207 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700208 args=[ cellName ],
209 specificDriver=1,
210 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700211 verifyResult = self.command( "verifyCell",
Jon Hall4173b242017-09-12 17:04:38 -0700212 specificDriver=1,
213 getFrom=0 if installMax else 1 )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700214 result = main.TRUE
215 for i in range( len( setCellResult ) ):
216 result = result and setCellResult[ i ] and verifyResult[ i ]
217 return result
Devin Lim142b5342017-07-20 15:22:39 -0700218
219 def checkService( self ):
220 """
221 Description:
222 Checking if the onos service is up. If not, it will
223 start the onos service manually.
224 Required:
225 Returns:
226 Returns main.TRUE if it successfully checked
227 """
228 stopResult = main.TRUE
229 startResult = main.TRUE
230 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700231 onosUp = self.command( "isup",
232 args=[ "ipAddress" ],
233 specificDriver=1,
234 getFrom=1,
235 funcFromCtrl=True )
236 for i in range( len( onosUp ) ):
237 ctrl = self.controllers[ i ]
238 onosIsUp = onosIsUp and onosUp[ i ]
239 if onosUp[ i ] == main.TRUE:
240 main.log.report( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700241 else:
Devin Lim40a19092017-08-15 14:54:22 -0700242 main.log.report( ctrl.name + " may not be up, stop and " +
Devin Lim142b5342017-07-20 15:22:39 -0700243 "start ONOS again " )
244 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
245 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
246 if not startResult or stopResult:
Devin Lim40a19092017-08-15 14:54:22 -0700247 main.log.report( ctrl.name + " did not start correctly." )
Devin Lim142b5342017-07-20 15:22:39 -0700248 return onosIsUp and stopResult and startResult
249
250 def kill( self, killMax, stopOnos ):
251 """
252 Description:
253 killing the onos. It will either kill the current runningnodes or
254 max number of the nodes.
255 Required:
256 * killRemoveMax - The boolean that will decide either to kill
257 only running nodes (False) or max number of nodes (True).
258 * stopOnos - If wish to stop onos before killing it. True for
259 enable stop , False for disable stop.
260 Returns:
261 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700262 """
263 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700264 killResult = self.command( "onosKill",
265 args=[ "ipAddress" ],
266 specificDriver=1,
267 getFrom=0 if killMax else 1,
268 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700269 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700270 result = result and killResult[ i ]
271 self.controllers[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700272 return result
273
274 def ssh( self ):
275 """
276 Description:
277 set up ssh to the onos
278 Required:
279 Returns:
280 Returns main.TRUE if it successfully setup the ssh to
281 the onos.
282 """
Devin Lim40a19092017-08-15 14:54:22 -0700283 result = main.TRUE
284 sshResult = self.command( "onosSecureSSH",
Jon Hall4173b242017-09-12 17:04:38 -0700285 kwargs={ "node": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700286 specificDriver=1,
287 getFrom=1,
288 funcFromCtrl=True )
289 for sshR in sshResult:
290 result = result and sshR
291 return result
Devin Lim142b5342017-07-20 15:22:39 -0700292
Devin Lime9f0ccf2017-08-11 17:25:12 -0700293 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700294 """
295 Description:
296 Installing onos.
297 Required:
298 * installMax - True for installing max number of nodes
299 False for installing current running nodes only.
300 Returns:
301 Returns main.TRUE if it successfully installed
302 """
303 result = main.TRUE
304 threads = []
305 i = 0
306 for ctrl in self.controllers if installMax else self.runningNodes:
307 options = "-f"
308 if installMax and i >= self.numCtrls:
309 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700310 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700311 t = main.Thread( target=ctrl.Bench.onosInstall,
312 name="install-" + ctrl.name,
313 kwargs={ "node" : ctrl.ipAddress,
314 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700315 threads.append( t )
316 t.start()
317 else:
318 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700319 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700320 if installParallel:
321 for t in threads:
322 t.join()
323 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700324 return result
325
326 def startCLIs( self ):
327 """
Devin Lim142b5342017-07-20 15:22:39 -0700328 Description:
329 starting Onos using onosCli driver
330 Required:
331 Returns:
332 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700333 """
Devin Lim40a19092017-08-15 14:54:22 -0700334 result = main.TRUE
335 cliResults = self.command( "startOnosCli",
336 args=[ "ipAddress" ],
337 specificDriver=2,
338 getFrom=1,
339 funcFromCtrl=True )
Jon Hall4173b242017-09-12 17:04:38 -0700340 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700341 result = result and cliResults[ i ]
342 self.controllers[ i ].active = True
343 return result
Jon Hallca319892017-06-15 15:25:22 -0700344
Devin Lim142b5342017-07-20 15:22:39 -0700345 def printResult( self, results, activeList, logLevel="debug" ):
346 """
347 Description:
348 Print the value of the list.
349 Required:
350 * results - list of the result
351 * activeList - list of the acitve nodes.
352 * logLevel - Type of log level you want it to be printed.
353 Returns:
354 """
355 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700356 for i in range( len( results ) ):
357 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700358
359 def allTrueResultCheck( self, results, activeList ):
360 """
361 Description:
362 check if all the result has main.TRUE.
363 Required:
364 * results - list of the result
365 * activeList - list of the acitve nodes.
366 Returns:
367 Returns True if all == main.TRUE else
368 returns False
369 """
370 self.printResult( results, activeList )
371 return all( result == main.TRUE for result in results )
372
373 def notEmptyResultCheck( self, results, activeList ):
374 """
375 Description:
376 check if all the result has any contents
377 Required:
378 * results - list of the result
379 * activeList - list of the acitve nodes.
380 Returns:
381 Returns True if all the results has
382 something else returns False
383 """
384 self.printResult( results, activeList )
385 return all( result for result in results )
386
387 def identicalResultsCheck( self, results, activeList ):
388 """
389 Description:
390 check if all the results has same output.
391 Required:
392 * results - list of the result
393 * activeList - list of the acitve nodes.
394 Returns:
395 Returns True if all the results has
396 same result else returns False
397 """
398 self.printResult( results, activeList )
399 resultOne = results[ 0 ]
400 return all( resultOne == result for result in results )
401
Devin Lime9f0ccf2017-08-11 17:25:12 -0700402 def command( self, function, args=(), kwargs={}, returnBool=False,
Devin Lim40a19092017-08-15 14:54:22 -0700403 specificDriver=0, contentCheck=False, getFrom=2,
404 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700405 """
406 Description:
407 execute some function of the active nodes.
408 Required:
409 * function - name of the function
410 * args - argument of the function
411 * kwargs - kwargs of the funciton
412 * returnBool - True if wish to check all the result has main.TRUE
413 * specificDriver - specific driver to execute the function. Since
414 some of the function can be used in different drivers, it is important
415 to specify which driver it will be executed from.
416 0 - any type of driver
417 1 - from bench
418 2 - from cli
419 3 - from rest
420 * contentCheck - If this is True, it will check if the result has some
421 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700422 * getFrom - from which nodes
423 2 - active nodes
424 1 - current running nodes
425 0 - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700426 * funcFromCtrl - specific function of the args/kwargs
427 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700428 Returns:
429 Returns results if not returnBool and not contentCheck
430 Returns checkTruthValue of the result if returnBool
431 Returns resultContent of the result if contentCheck
432 """
Jon Hallca319892017-06-15 15:25:22 -0700433 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700434 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700435 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700436 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700437 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700438 try:
Devin Lim40a19092017-08-15 14:54:22 -0700439 funcArgs = []
440 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700441 f = getattr( ( ctrl if not specificDriver else
442 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim40a19092017-08-15 14:54:22 -0700443 if funcFromCtrl:
444 if args:
445 for i in range( len( args ) ):
446 funcArgs.append( getattr( ctrl, args[ i ] ) )
447 if kwargs:
448 for k in kwargs:
Jon Hall4173b242017-09-12 17:04:38 -0700449 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
Devin Lim142b5342017-07-20 15:22:39 -0700450 except AttributeError:
451 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700452 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700453 t = main.Thread( target=f,
454 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700455 args=funcArgs if funcFromCtrl else args,
456 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700457 threads.append( t )
458 t.start()
459
460 for t in threads:
461 t.join()
462 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700463 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700464 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700465 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700466 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Jon Hall4173b242017-09-12 17:04:38 -0700467 return results
468
469 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
470 # max segment size in bytes: 1024 * 1024 * 64
471 # multiplier is somewhat arbitrary, but the idea is the logs would have
472 # been compacted before this many segments are written
473
474 maxSize = float( segmentSize ) * float( multiplier )
475 ret = True
476 for n in self.runningNodes:
477 ret = ret and n.server.folderSize( "/opt/onos/apache-karaf-*/data/partitions/*/*.log",
478 size=maxSize, unit=units, ignoreRoot=False )
479 return ret