blob: 6b18b8bae6127897140e57d55f481ac1853225e6 [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 Lim142b5342017-07-20 15:22:39 -0700154 def createCell( self, cellName, Mininet, useSSH, ips ):
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 """
165 main.ONOSbench.createCellFile( main.ONOSbench.ip_address,
166 cellName,
167 Mininet if isinstance( Mininet, str ) else
168 Mininet.ip_address,
169 main.apps,
170 ips,
171 main.ONOScell.karafUser,
172 useSSH=useSSH )
173
174 def uninstall( self, uninstallMax ):
175 """
176 Description:
177 uninstalling onos
178 Required:
179 * uninstallMax - True for uninstalling max number of nodes
180 False for uninstalling the current running nodes.
181 Returns:
182 Returns main.TRUE if it successfully uninstalled.
183 """
184 onosUninstallResult = main.TRUE
185 for ctrl in self.controllers if uninstallMax else self.runningNodes:
186 onosUninstallResult = onosUninstallResult and \
187 main.ONOSbench.onosUninstall( nodeIp=ctrl.ipAddress )
188 return onosUninstallResult
189
190 def applyCell( self, cellName ):
191 """
192 Description:
193 apply the cell with cellName. It will also verify the
194 cell.
195 Required:
196 * cellName - The name of the cell.
197 Returns:
198 Returns main.TRUE if it successfully set and verify cell.
199 """
200 cellResult = main.ONOSbench.setCell( cellName )
201 verifyResult = main.ONOSbench.verifyCell()
202 return cellResult and verifyResult
203
204 def checkService( self ):
205 """
206 Description:
207 Checking if the onos service is up. If not, it will
208 start the onos service manually.
209 Required:
210 Returns:
211 Returns main.TRUE if it successfully checked
212 """
213 stopResult = main.TRUE
214 startResult = main.TRUE
215 onosIsUp = main.TRUE
216 i = 0
217 for ctrl in self.runningNodes:
218 onosIsUp = onosIsUp and main.ONOSbench.isup( ctrl.ipAddress )
219 if onosIsUp == main.TRUE:
220 main.log.report( "ONOS instance {0} is up and ready".format( i + 1 ) )
221 else:
222 main.log.report( "ONOS instance {0} may not be up, stop and ".format( i + 1 ) +
223 "start ONOS again " )
224 stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
225 startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
226 if not startResult or stopResult:
227 main.log.report( "ONOS instance {0} did not start correctly.".format( i + 1 ) )
228 i += 1
229 return onosIsUp and stopResult and startResult
230
231 def kill( self, killMax, stopOnos ):
232 """
233 Description:
234 killing the onos. It will either kill the current runningnodes or
235 max number of the nodes.
236 Required:
237 * killRemoveMax - The boolean that will decide either to kill
238 only running nodes (False) or max number of nodes (True).
239 * stopOnos - If wish to stop onos before killing it. True for
240 enable stop , False for disable stop.
241 Returns:
242 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700243 """
244 result = main.TRUE
Devin Lim142b5342017-07-20 15:22:39 -0700245 for ctrl in self.controllers if killMax else self.runningNodes:
246 if stopOnos:
247 result = result and main.ONOSbench.onosStop( ctrl.ipAddress )
248 result = result and main.ONOSbench.onosKill( ctrl.ipAddress )
249 ctrl.active = False
250 return result
251
252 def ssh( self ):
253 """
254 Description:
255 set up ssh to the onos
256 Required:
257 Returns:
258 Returns main.TRUE if it successfully setup the ssh to
259 the onos.
260 """
261 secureSshResult = main.TRUE
262 for ctrl in self.runningNodes:
263 secureSshResult = secureSshResult and main.ONOSbench.onosSecureSSH( node=ctrl.ipAddress )
264 return secureSshResult
265
266 def install( self, installMax=True ):
267 """
268 Description:
269 Installing onos.
270 Required:
271 * installMax - True for installing max number of nodes
272 False for installing current running nodes only.
273 Returns:
274 Returns main.TRUE if it successfully installed
275 """
276 result = main.TRUE
277 threads = []
278 i = 0
279 for ctrl in self.controllers if installMax else self.runningNodes:
280 options = "-f"
281 if installMax and i >= self.numCtrls:
282 options = "-nf"
283 result = result and \
284 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
285
Jon Hallca319892017-06-15 15:25:22 -0700286 return result
287
288 def startCLIs( self ):
289 """
Devin Lim142b5342017-07-20 15:22:39 -0700290 Description:
291 starting Onos using onosCli driver
292 Required:
293 Returns:
294 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700295 """
296 cliResults = main.TRUE
297 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700298 for ctrl in self.runningNodes:
Jon Hallca319892017-06-15 15:25:22 -0700299 t = main.Thread( target=ctrl.CLI.startOnosCli,
300 name="startCli-" + ctrl.name,
301 args=[ ctrl.ipAddress ] )
302 threads.append( t )
303 t.start()
304 ctrl.active = True
305
306 for t in threads:
307 t.join()
308 cliResults = cliResults and t.result
309 return cliResults
310
Devin Lim142b5342017-07-20 15:22:39 -0700311 def printResult( self, results, activeList, logLevel="debug" ):
312 """
313 Description:
314 Print the value of the list.
315 Required:
316 * results - list of the result
317 * activeList - list of the acitve nodes.
318 * logLevel - Type of log level you want it to be printed.
319 Returns:
320 """
321 f = getattr( main.log, logLevel )
322 for i in range ( len ( results ) ):
323 f( activeList[ i ].name + "'s result : " + str ( results[ i ] ) )
324
325 def allTrueResultCheck( self, results, activeList ):
326 """
327 Description:
328 check if all the result has main.TRUE.
329 Required:
330 * results - list of the result
331 * activeList - list of the acitve nodes.
332 Returns:
333 Returns True if all == main.TRUE else
334 returns False
335 """
336 self.printResult( results, activeList )
337 return all( result == main.TRUE for result in results )
338
339 def notEmptyResultCheck( self, results, activeList ):
340 """
341 Description:
342 check if all the result has any contents
343 Required:
344 * results - list of the result
345 * activeList - list of the acitve nodes.
346 Returns:
347 Returns True if all the results has
348 something else returns False
349 """
350 self.printResult( results, activeList )
351 return all( result for result in results )
352
353 def identicalResultsCheck( self, results, activeList ):
354 """
355 Description:
356 check if all the results has same output.
357 Required:
358 * results - list of the result
359 * activeList - list of the acitve nodes.
360 Returns:
361 Returns True if all the results has
362 same result else returns False
363 """
364 self.printResult( results, activeList )
365 resultOne = results[ 0 ]
366 return all( resultOne == result for result in results )
367
368 def command( self, function, args=(), kwargs={}, returnBool=False, specificDriver=0, contentCheck=False ):
369 """
370 Description:
371 execute some function of the active nodes.
372 Required:
373 * function - name of the function
374 * args - argument of the function
375 * kwargs - kwargs of the funciton
376 * returnBool - True if wish to check all the result has main.TRUE
377 * specificDriver - specific driver to execute the function. Since
378 some of the function can be used in different drivers, it is important
379 to specify which driver it will be executed from.
380 0 - any type of driver
381 1 - from bench
382 2 - from cli
383 3 - from rest
384 * contentCheck - If this is True, it will check if the result has some
385 contents.
386 Returns:
387 Returns results if not returnBool and not contentCheck
388 Returns checkTruthValue of the result if returnBool
389 Returns resultContent of the result if contentCheck
390 """
Jon Hallca319892017-06-15 15:25:22 -0700391 """
392 Send a command to all ONOS nodes and return the results as a list
Devin Lim142b5342017-07-20 15:22:39 -0700393 specificDriver:
394 0 - any type of driver
395 1 - from bench
396 2 - from cli
397 3 - from rest
Jon Hallca319892017-06-15 15:25:22 -0700398 """
399 threads = []
Devin Lim142b5342017-07-20 15:22:39 -0700400 drivers = [ None, "Bench", "CLI", "REST" ]
Jon Hallca319892017-06-15 15:25:22 -0700401 results = []
402 for ctrl in self.active():
Devin Lim142b5342017-07-20 15:22:39 -0700403 try:
404 f = getattr( ( ctrl if not specificDriver else
405 getattr( ctrl, drivers[ specificDriver ] ) ), function )
406 except AttributeError:
407 main.log.error( "Function " + function + " not found. Exiting the Test." )
408 main.cleanup()
409 main.exit()
410
Jon Hallca319892017-06-15 15:25:22 -0700411 t = main.Thread( target=f,
412 name=function + "-" + ctrl.name,
413 args=args,
414 kwargs=kwargs )
415 threads.append( t )
416 t.start()
417
418 for t in threads:
419 t.join()
420 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700421 if returnBool:
422 return self.allTrueResultCheck( results, self.active() )
423 elif contentCheck:
424 return self.notEmptyResultCheck( results, self.active() )
425 return results