blob: 5c6e679cc13c69f6686bbfd43000c4d7a302050d [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
27 def __repr__( self ):
28 #TODO use repr of cli's?
29 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
35
36 def __init__( self, ctrlList=[], name="Cluster" ):
Devin Lim142b5342017-07-20 15:22:39 -070037 '''
38 controllers : All the nodes
39 runningNodes : Node that are specifically running from the test.
40 ie) When the test is testing different number of nodes on each
41 run.
42 numCtrls : number of runningNodes
43 maxCtrls : number of controllers
44 '''
Jon Hallca319892017-06-15 15:25:22 -070045 self.controllers = ctrlList
Devin Lim142b5342017-07-20 15:22:39 -070046 self.runningNodes = ctrlList
47 self.numCtrls = len( self.runningNodes )
48 self.maxCtrls = len( self.controllers )
Jon Hallca319892017-06-15 15:25:22 -070049 self.name = str( name )
50 self.iterator = iter( self.active() )
51
Devin Lim142b5342017-07-20 15:22:39 -070052 def getIps( self, activeOnly=False, allNode=False ):
53 """
54 Description:
55 get the list of the ip. Default to get ips of running nodes.
56 Required:
57 * activeOnly - True for getting ips of active nodes
58 * allNode - True for getting ips of all nodes
59 Returns:
60 Retruns ips of active nodes if activeOnly is True.
61 Returns ips of all nodes if allNode is True.
62 """
Jon Hallca319892017-06-15 15:25:22 -070063 ips = []
Devin Lim142b5342017-07-20 15:22:39 -070064 if allNode:
Jon Hallca319892017-06-15 15:25:22 -070065 nodeList = self.controllers
Devin Lim142b5342017-07-20 15:22:39 -070066 else:
67 if activeOnly:
68 nodeList = self.active()
69 else:
70 nodeList = self.runningNodes
71
Jon Hallca319892017-06-15 15:25:22 -070072 for ctrl in nodeList:
73 ips.append( ctrl.ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -070074
Jon Hallca319892017-06-15 15:25:22 -070075 return ips
76
Devin Lim142b5342017-07-20 15:22:39 -070077 def resetActive( self ):
Jon Hallca319892017-06-15 15:25:22 -070078 """
Devin Lim142b5342017-07-20 15:22:39 -070079 Description:
80 reset the activeness of the runningNodes to be false
81 Required:
82 Returns:
Jon Hallca319892017-06-15 15:25:22 -070083 """
Devin Lim142b5342017-07-20 15:22:39 -070084 for ctrl in self.runningNodes:
85 ctrl.active = False
86
87 def getRunningPos( self ):
88 """
89 Description:
90 get the position of the active running nodes.
91 Required:
92 Returns:
93 Retruns the list of the position of the active
94 running nodes.
95 """
96 return [ ctrl.pos for ctrl in self.runningNodes
97 if ctrl.active ]
98
99 def setRunningNode( self, numCtrls ):
100 """
101 Description:
102 Set running nodes of n number of nodes.
103 It will create new list of runningNodes.
104 If numCtrls is a list, it will add the nodes of the
105 list.
106 Required:
107 * numCtrls - number of nodes to be set.
108 Returns:
109 """
110 self.runningNodes = []
111 for i in numCtrls if isinstance( numCtrls, list ) else range( numCtrls ) :
112 self.runningNodes.append( self.controllers[ i ] )
113 self.numCtrls = len( numCtrls ) if isinstance( numCtrls, list ) else numCtrls
114
115 def active( self, node=None ):
116 """
117 Description:
118 get the list/controller of the active controller.
119 Required:
120 * node - position of the node to get from the active controller.
121 Returns:
122 Return a list of active controllers in the cluster if node is None
123 if not, it will return the nth controller.
124 """
125 result = [ ctrl for ctrl in self.runningNodes
Jon Hallca319892017-06-15 15:25:22 -0700126 if ctrl.active ]
Devin Lim142b5342017-07-20 15:22:39 -0700127 return result if node is None else result[ node % len( result ) ]
Jon Hallca319892017-06-15 15:25:22 -0700128
129 def next( self ):
130 """
131 An iterator for the cluster's controllers that
132 resets when there are no more elements.
133
134 Returns the next controller in the cluster
135 """
136 try:
137 return self.iterator.next()
138 except StopIteration:
139 self.reset()
140 try:
141 return self.iterator.next()
142 except StopIteration:
143 raise RuntimeError( "There are no active nodes in the cluster" )
144
145 def reset( self ):
146 """
147 Resets the cluster iterator.
148
149 This should be used whenever a node's active state is changed
150 and is also used internally when the iterator has been exhausted.
151 """
152 self.iterator = iter( self.active() )
153
Devin Lime9f0ccf2017-08-11 17:25:12 -0700154 def createCell( self, cellName, Mininet, useSSH, ips, installMax=False ):
Jon Hallca319892017-06-15 15:25:22 -0700155 """
Devin Lim142b5342017-07-20 15:22:39 -0700156 Description:
157 create a new cell
158 Required:
159 * cellName - The name of the cell.
160 * Mininet - a mininet driver that will be used.
161 * useSSH - True for using ssh when creating a cell
162 * ips - ip(s) of the node(s).
163 Returns:
164 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700165 self.command( "createCellFile",
166 args=[ main.ONOSbench.ip_address,
Devin Lim40a19092017-08-15 14:54:22 -0700167 cellName,
168 Mininet if isinstance(Mininet, str) else
169 Mininet.ip_address,
170 main.apps,
171 ips,
172 main.ONOScell.karafUser,
173 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700174 specificDriver=1,
175 getFrom=0 if installMax else 1 )
Devin Lim40a19092017-08-15 14:54:22 -0700176
Devin Lim142b5342017-07-20 15:22:39 -0700177 def uninstall( self, uninstallMax ):
178 """
179 Description:
180 uninstalling onos
181 Required:
182 * uninstallMax - True for uninstalling max number of nodes
183 False for uninstalling the current running nodes.
184 Returns:
185 Returns main.TRUE if it successfully uninstalled.
186 """
Devin Lim40a19092017-08-15 14:54:22 -0700187 result = main.TRUE
188 uninstallResult = self.command( "onosUninstall",
189 kwargs={ "nodeIp":"ipAddress" },
190 specificDriver=1,
191 getFrom=0 if uninstallMax else 1,
192 funcFromCtrl=True )
193 for uninstallR in uninstallResult:
194 result = result and uninstallR
195 return result
Devin Lim142b5342017-07-20 15:22:39 -0700196
Devin Lime9f0ccf2017-08-11 17:25:12 -0700197 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700198 """
199 Description:
200 apply the cell with cellName. It will also verify the
201 cell.
202 Required:
203 * cellName - The name of the cell.
204 Returns:
205 Returns main.TRUE if it successfully set and verify cell.
206 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700207
208 setCellResult = self.command( "setCell",
209 args=[ cellName ],
210 specificDriver=1,
211 getFrom=0 if installMax else 1 )
212 verifyResult = self.command( "verifyCell",
213 specificDriver=1,
214 getFrom=0 if installMax else 1 )
215 result = main.TRUE
216 for i in range( len( setCellResult ) ):
217 result = result and setCellResult[ i ] and verifyResult[ i ]
218 return result
Devin Lim142b5342017-07-20 15:22:39 -0700219
220 def checkService( self ):
221 """
222 Description:
223 Checking if the onos service is up. If not, it will
224 start the onos service manually.
225 Required:
226 Returns:
227 Returns main.TRUE if it successfully checked
228 """
229 stopResult = main.TRUE
230 startResult = main.TRUE
231 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700232 onosUp = self.command( "isup",
233 args=[ "ipAddress" ],
234 specificDriver=1,
235 getFrom=1,
236 funcFromCtrl=True )
237 for i in range( len( onosUp ) ):
238 ctrl = self.controllers[ i ]
239 onosIsUp = onosIsUp and onosUp[ i ]
240 if onosUp[ i ] == main.TRUE:
241 main.log.report( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700242 else:
Devin Lim40a19092017-08-15 14:54:22 -0700243 main.log.report( ctrl.name + " may not be up, stop and " +
Devin Lim142b5342017-07-20 15:22:39 -0700244 "start ONOS again " )
245 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
246 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
247 if not startResult or stopResult:
Devin Lim40a19092017-08-15 14:54:22 -0700248 main.log.report( ctrl.name + " did not start correctly." )
Devin Lim142b5342017-07-20 15:22:39 -0700249 return onosIsUp and stopResult and startResult
250
251 def kill( self, killMax, stopOnos ):
252 """
253 Description:
254 killing the onos. It will either kill the current runningnodes or
255 max number of the nodes.
256 Required:
257 * killRemoveMax - The boolean that will decide either to kill
258 only running nodes (False) or max number of nodes (True).
259 * stopOnos - If wish to stop onos before killing it. True for
260 enable stop , False for disable stop.
261 Returns:
262 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700263 """
264 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700265 killResult = self.command( "onosKill",
266 args=[ "ipAddress" ],
267 specificDriver=1,
268 getFrom=0 if killMax else 1,
269 funcFromCtrl=True )
270 for i in range( len ( killResult ) ):
271 result = result and killResult[ i ]
272 self.controllers[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700273 return result
274
275 def ssh( self ):
276 """
277 Description:
278 set up ssh to the onos
279 Required:
280 Returns:
281 Returns main.TRUE if it successfully setup the ssh to
282 the onos.
283 """
Devin Lim40a19092017-08-15 14:54:22 -0700284 result = main.TRUE
285 sshResult = self.command( "onosSecureSSH",
286 kwargs={ "node":"ipAddress" },
287 specificDriver=1,
288 getFrom=1,
289 funcFromCtrl=True )
290 for sshR in sshResult:
291 result = result and sshR
292 return result
Devin Lim142b5342017-07-20 15:22:39 -0700293
Devin Lime9f0ccf2017-08-11 17:25:12 -0700294 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700295 """
296 Description:
297 Installing onos.
298 Required:
299 * installMax - True for installing max number of nodes
300 False for installing current running nodes only.
301 Returns:
302 Returns main.TRUE if it successfully installed
303 """
304 result = main.TRUE
305 threads = []
306 i = 0
307 for ctrl in self.controllers if installMax else self.runningNodes:
308 options = "-f"
309 if installMax and i >= self.numCtrls:
310 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700311 if installParallel:
312 t= main.Thread( target=ctrl.Bench.onosInstall,
Devin Lim40a19092017-08-15 14:54:22 -0700313 name="install-" + ctrl.name,
314 kwargs={ "node" : ctrl.ipAddress,
315 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700316 threads.append( t )
317 t.start()
318 else:
319 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700320 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700321 if installParallel:
322 for t in threads:
323 t.join()
324 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700325 return result
326
327 def startCLIs( self ):
328 """
Devin Lim142b5342017-07-20 15:22:39 -0700329 Description:
330 starting Onos using onosCli driver
331 Required:
332 Returns:
333 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700334 """
Devin Lim40a19092017-08-15 14:54:22 -0700335 result = main.TRUE
336 cliResults = self.command( "startOnosCli",
337 args=[ "ipAddress" ],
338 specificDriver=2,
339 getFrom=1,
340 funcFromCtrl=True )
341 for i in range ( len( cliResults ) ):
342 result = result and cliResults[ i ]
343 self.controllers[ i ].active = True
344 return result
Jon Hallca319892017-06-15 15:25:22 -0700345
Devin Lim142b5342017-07-20 15:22:39 -0700346 def printResult( self, results, activeList, logLevel="debug" ):
347 """
348 Description:
349 Print the value of the list.
350 Required:
351 * results - list of the result
352 * activeList - list of the acitve nodes.
353 * logLevel - Type of log level you want it to be printed.
354 Returns:
355 """
356 f = getattr( main.log, logLevel )
357 for i in range ( len ( results ) ):
358 f( activeList[ i ].name + "'s result : " + str ( results[ i ] ) )
359
360 def allTrueResultCheck( self, results, activeList ):
361 """
362 Description:
363 check if all the result has main.TRUE.
364 Required:
365 * results - list of the result
366 * activeList - list of the acitve nodes.
367 Returns:
368 Returns True if all == main.TRUE else
369 returns False
370 """
371 self.printResult( results, activeList )
372 return all( result == main.TRUE for result in results )
373
374 def notEmptyResultCheck( self, results, activeList ):
375 """
376 Description:
377 check if all the result has any contents
378 Required:
379 * results - list of the result
380 * activeList - list of the acitve nodes.
381 Returns:
382 Returns True if all the results has
383 something else returns False
384 """
385 self.printResult( results, activeList )
386 return all( result for result in results )
387
388 def identicalResultsCheck( self, results, activeList ):
389 """
390 Description:
391 check if all the results has same output.
392 Required:
393 * results - list of the result
394 * activeList - list of the acitve nodes.
395 Returns:
396 Returns True if all the results has
397 same result else returns False
398 """
399 self.printResult( results, activeList )
400 resultOne = results[ 0 ]
401 return all( resultOne == result for result in results )
402
Devin Lime9f0ccf2017-08-11 17:25:12 -0700403 def command( self, function, args=(), kwargs={}, returnBool=False,
Devin Lim40a19092017-08-15 14:54:22 -0700404 specificDriver=0, contentCheck=False, getFrom=2,
405 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700406 """
407 Description:
408 execute some function of the active nodes.
409 Required:
410 * function - name of the function
411 * args - argument of the function
412 * kwargs - kwargs of the funciton
413 * returnBool - True if wish to check all the result has main.TRUE
414 * specificDriver - specific driver to execute the function. Since
415 some of the function can be used in different drivers, it is important
416 to specify which driver it will be executed from.
417 0 - any type of driver
418 1 - from bench
419 2 - from cli
420 3 - from rest
421 * contentCheck - If this is True, it will check if the result has some
422 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700423 * getFrom - from which nodes
424 2 - active nodes
425 1 - current running nodes
426 0 - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700427 * funcFromCtrl - specific function of the args/kwargs
428 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700429 Returns:
430 Returns results if not returnBool and not contentCheck
431 Returns checkTruthValue of the result if returnBool
432 Returns resultContent of the result if contentCheck
433 """
Jon Hallca319892017-06-15 15:25:22 -0700434 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700435 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700436 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700437 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700438 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700439 try:
Devin Lim40a19092017-08-15 14:54:22 -0700440 funcArgs = []
441 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700442 f = getattr( ( ctrl if not specificDriver else
443 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim40a19092017-08-15 14:54:22 -0700444 if funcFromCtrl:
445 if args:
446 for i in range( len( args ) ):
447 funcArgs.append( getattr( ctrl, args[ i ] ) )
448 if kwargs:
449 for k in kwargs:
450 funcKwargs.update( { k:getattr( ctrl, kwargs[ k ] ) } )
Devin Lim142b5342017-07-20 15:22:39 -0700451 except AttributeError:
452 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700453 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700454 t = main.Thread( target=f,
455 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700456 args=funcArgs if funcFromCtrl else args,
457 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700458 threads.append( t )
459 t.start()
460
461 for t in threads:
462 t.join()
463 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700464 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700465 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700466 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700467 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700468 return results