blob: 825f368afb730f6594329af788e3293fb0a43b2f [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,
167 cellName,
168 Mininet if isinstance(Mininet, str) else
169 Mininet.ip_address,
170 main.apps,
171 ips,
172 main.ONOScell.karafUser,
173 useSSH ],
174 specificDriver=1,
175 getFrom=0 if installMax else 1 )
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 """
186 onosUninstallResult = main.TRUE
187 for ctrl in self.controllers if uninstallMax else self.runningNodes:
188 onosUninstallResult = onosUninstallResult and \
189 main.ONOSbench.onosUninstall( nodeIp=ctrl.ipAddress )
190 return onosUninstallResult
191
Devin Lime9f0ccf2017-08-11 17:25:12 -0700192 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700193 """
194 Description:
195 apply the cell with cellName. It will also verify the
196 cell.
197 Required:
198 * cellName - The name of the cell.
199 Returns:
200 Returns main.TRUE if it successfully set and verify cell.
201 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700202
203 setCellResult = self.command( "setCell",
204 args=[ cellName ],
205 specificDriver=1,
206 getFrom=0 if installMax else 1 )
207 verifyResult = self.command( "verifyCell",
208 specificDriver=1,
209 getFrom=0 if installMax else 1 )
210 result = main.TRUE
211 for i in range( len( setCellResult ) ):
212 result = result and setCellResult[ i ] and verifyResult[ i ]
213 return result
Devin Lim142b5342017-07-20 15:22:39 -0700214
215 def checkService( self ):
216 """
217 Description:
218 Checking if the onos service is up. If not, it will
219 start the onos service manually.
220 Required:
221 Returns:
222 Returns main.TRUE if it successfully checked
223 """
224 stopResult = main.TRUE
225 startResult = main.TRUE
226 onosIsUp = main.TRUE
227 i = 0
228 for ctrl in self.runningNodes:
229 onosIsUp = onosIsUp and main.ONOSbench.isup( ctrl.ipAddress )
230 if onosIsUp == main.TRUE:
231 main.log.report( "ONOS instance {0} is up and ready".format( i + 1 ) )
232 else:
233 main.log.report( "ONOS instance {0} may not be up, stop and ".format( i + 1 ) +
234 "start ONOS again " )
235 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
236 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
237 if not startResult or stopResult:
238 main.log.report( "ONOS instance {0} did not start correctly.".format( i + 1 ) )
239 i += 1
240 return onosIsUp and stopResult and startResult
241
242 def kill( self, killMax, stopOnos ):
243 """
244 Description:
245 killing the onos. It will either kill the current runningnodes or
246 max number of the nodes.
247 Required:
248 * killRemoveMax - The boolean that will decide either to kill
249 only running nodes (False) or max number of nodes (True).
250 * stopOnos - If wish to stop onos before killing it. True for
251 enable stop , False for disable stop.
252 Returns:
253 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700254 """
255 result = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700256 for ctrl in self.controllers if killMax else self.runningNodes:
257 if stopOnos:
258 result = result and main.ONOSbench.onosStop( ctrl.ipAddress )
259 result = result and main.ONOSbench.onosKill( ctrl.ipAddress )
260 ctrl.active = False
261 return result
262
263 def ssh( self ):
264 """
265 Description:
266 set up ssh to the onos
267 Required:
268 Returns:
269 Returns main.TRUE if it successfully setup the ssh to
270 the onos.
271 """
272 secureSshResult = main.TRUE
273 for ctrl in self.runningNodes:
274 secureSshResult = secureSshResult and main.ONOSbench.onosSecureSSH( node=ctrl.ipAddress )
275 return secureSshResult
276
Devin Lime9f0ccf2017-08-11 17:25:12 -0700277 def install( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700278 """
279 Description:
280 Installing onos.
281 Required:
282 * installMax - True for installing max number of nodes
283 False for installing current running nodes only.
284 Returns:
285 Returns main.TRUE if it successfully installed
286 """
287 result = main.TRUE
288 threads = []
289 i = 0
290 for ctrl in self.controllers if installMax else self.runningNodes:
291 options = "-f"
292 if installMax and i >= self.numCtrls:
293 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700294 if installParallel:
295 t= main.Thread( target=ctrl.Bench.onosInstall,
296 name="install-" + ctrl.name,
297 kwargs={ "node" : ctrl.ipAddress,
298 "options" : options } )
299 threads.append( t )
300 t.start()
301 else:
302 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700303 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700304 if installParallel:
305 for t in threads:
306 t.join()
307 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700308 return result
309
310 def startCLIs( self ):
311 """
Devin Lim142b5342017-07-20 15:22:39 -0700312 Description:
313 starting Onos using onosCli driver
314 Required:
315 Returns:
316 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700317 """
318 cliResults = main.TRUE
319 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700320 for ctrl in self.runningNodes:
Jon Hallca319892017-06-15 15:25:22 -0700321 t = main.Thread( target=ctrl.CLI.startOnosCli,
322 name="startCli-" + ctrl.name,
323 args=[ ctrl.ipAddress ] )
324 threads.append( t )
325 t.start()
326 ctrl.active = True
327
328 for t in threads:
329 t.join()
330 cliResults = cliResults and t.result
331 return cliResults
332
Devin Lim142b5342017-07-20 15:22:39 -0700333 def printResult( self, results, activeList, logLevel="debug" ):
334 """
335 Description:
336 Print the value of the list.
337 Required:
338 * results - list of the result
339 * activeList - list of the acitve nodes.
340 * logLevel - Type of log level you want it to be printed.
341 Returns:
342 """
343 f = getattr( main.log, logLevel )
344 for i in range ( len ( results ) ):
345 f( activeList[ i ].name + "'s result : " + str ( results[ i ] ) )
346
347 def allTrueResultCheck( self, results, activeList ):
348 """
349 Description:
350 check if all the result has main.TRUE.
351 Required:
352 * results - list of the result
353 * activeList - list of the acitve nodes.
354 Returns:
355 Returns True if all == main.TRUE else
356 returns False
357 """
358 self.printResult( results, activeList )
359 return all( result == main.TRUE for result in results )
360
361 def notEmptyResultCheck( self, results, activeList ):
362 """
363 Description:
364 check if all the result has any contents
365 Required:
366 * results - list of the result
367 * activeList - list of the acitve nodes.
368 Returns:
369 Returns True if all the results has
370 something else returns False
371 """
372 self.printResult( results, activeList )
373 return all( result for result in results )
374
375 def identicalResultsCheck( self, results, activeList ):
376 """
377 Description:
378 check if all the results has same output.
379 Required:
380 * results - list of the result
381 * activeList - list of the acitve nodes.
382 Returns:
383 Returns True if all the results has
384 same result else returns False
385 """
386 self.printResult( results, activeList )
387 resultOne = results[ 0 ]
388 return all( resultOne == result for result in results )
389
Devin Lime9f0ccf2017-08-11 17:25:12 -0700390 def command( self, function, args=(), kwargs={}, returnBool=False,
391 specificDriver=0, contentCheck=False, getFrom=2 ):
Devin Lim142b5342017-07-20 15:22:39 -0700392 """
393 Description:
394 execute some function of the active nodes.
395 Required:
396 * function - name of the function
397 * args - argument of the function
398 * kwargs - kwargs of the funciton
399 * returnBool - True if wish to check all the result has main.TRUE
400 * specificDriver - specific driver to execute the function. Since
401 some of the function can be used in different drivers, it is important
402 to specify which driver it will be executed from.
403 0 - any type of driver
404 1 - from bench
405 2 - from cli
406 3 - from rest
407 * contentCheck - If this is True, it will check if the result has some
408 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700409 * getFrom - from which nodes
410 2 - active nodes
411 1 - current running nodes
412 0 - all nodes
Devin Lim142b5342017-07-20 15:22:39 -0700413 Returns:
414 Returns results if not returnBool and not contentCheck
415 Returns checkTruthValue of the result if returnBool
416 Returns resultContent of the result if contentCheck
417 """
Jon Hallca319892017-06-15 15:25:22 -0700418 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700419 drivers = [ None, "Bench", "CLI", "REST" ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700420 fromNode = [ self.controllers, self.runningNodes, self.active() ]
Jon Hallca319892017-06-15 15:25:22 -0700421 results = []
Devin Lime9f0ccf2017-08-11 17:25:12 -0700422 for ctrl in fromNode[ getFrom ]:
Devin Lim142b5342017-07-20 15:22:39 -0700423 try:
424 f = getattr( ( ctrl if not specificDriver else
425 getattr( ctrl, drivers[ specificDriver ] ) ), function )
426 except AttributeError:
427 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700428 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700429
Jon Hallca319892017-06-15 15:25:22 -0700430 t = main.Thread( target=f,
431 name=function + "-" + ctrl.name,
432 args=args,
433 kwargs=kwargs )
434 threads.append( t )
435 t.start()
436
437 for t in threads:
438 t.join()
439 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700440 if returnBool:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700441 return self.allTrueResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700442 elif contentCheck:
Devin Lime9f0ccf2017-08-11 17:25:12 -0700443 return self.notEmptyResultCheck( results, fromNode[ getFrom ] )
Devin Lim142b5342017-07-20 15:22:39 -0700444 return results