blob: ae08de965050334abc7315c0813decbc035b0647 [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 = []
Jon Hall3e6edb32018-08-21 16:20:30 -070029 runningNodes = self.getRunningNodes()
30 atomixNodes = []
Jon Hallca319892017-06-15 15:25:22 -070031 for ctrl in self.controllers:
Jon Hall3e6edb32018-08-21 16:20:30 -070032 controllers.append( "{%s:%s, %s - %s}" % ( ctrl.name,
33 ctrl.ipAddress,
34 "Configured" if ctrl in runningNodes else "Not Configured",
35 "Active" if ctrl.active else "Inactive" ) )
36 for node in self.atomixNodes:
37 atomixNodes.append( "{%s:%s}" % ( node.name, node.ipAddress ) )
38 return "%s[%s; Atomix Nodes:%s]" % ( self.name, ", ".join( controllers ), ", ".join( atomixNodes ) )
Jon Hallca319892017-06-15 15:25:22 -070039
Jon Hall3c0114c2020-08-11 15:07:42 -070040 def __init__( self, ctrlList=[], name="Cluster", useDocker=False ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070041 """
Devin Lim142b5342017-07-20 15:22:39 -070042 controllers : All the nodes
43 runningNodes : Node that are specifically running from the test.
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070044 ie ) When the test is testing different number of nodes on each
Devin Lim142b5342017-07-20 15:22:39 -070045 run.
46 numCtrls : number of runningNodes
47 maxCtrls : number of controllers
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070048 """
Jon Hallca319892017-06-15 15:25:22 -070049 self.controllers = ctrlList
Devin Lim142b5342017-07-20 15:22:39 -070050 self.runningNodes = ctrlList
51 self.numCtrls = len( self.runningNodes )
52 self.maxCtrls = len( self.controllers )
Jon Hallca319892017-06-15 15:25:22 -070053 self.name = str( name )
Jon Hall3e6edb32018-08-21 16:20:30 -070054 self.atomixNodes = ctrlList
Jon Hallca319892017-06-15 15:25:22 -070055 self.iterator = iter( self.active() )
Jon Hall3c0114c2020-08-11 15:07:42 -070056 self.useDocker = useDocker
57 clusterParams = main.params.get( "CLUSTER", {} )
58 self.dockerSkipBuild = clusterParams.get( "dockerSkipBuild", False )
59 self.dockerBuildCmd = clusterParams.get( "dockerBuildCmd", None )
60 self.dockerBuildTimeout = int( clusterParams.get( "dockerBuildTimeout", 600 ) )
61 self.dockerFilePath = clusterParams.get( "dockerFilePath", None )
62 self.dockerImageTag = clusterParams.get( "dockerImageTag", None )
63 self.dockerOptions = clusterParams.get( "dockerOptions", "" )
64 self.atomixImageTag = clusterParams.get( "atomixImageTag", None )
65 self.atomixOptions = clusterParams.get( "atomixOptions", "" )
Jon Hallca319892017-06-15 15:25:22 -070066
Jon Hall3e6edb32018-08-21 16:20:30 -070067 def fromNode( self, ctrlList ):
68 """
69 Helper function to get a specific list of controllers
70 Required Arguments:
71 * ctrlList - The list of controllers to return. This can be either an index or a keyword
72 Index | Keyword | List returned
73 0 | "all" | self.controllers
74 1 | "running" | self.runningNodes
75 2 | "active | self.active()
76
77 Throws a ValueError exception if ctrlList value is not recognized
78 """
79 # TODO: Add Atomix Nodes?
80 if isinstance( ctrlList, str ):
81 ctrlList = ctrlList.lower()
82 if ctrlList == 0 or ctrlList == "all":
83 return self.controllers
84 elif ctrlList == 1 or ctrlList == "running":
85 return self.runningNodes
86 elif ctrlList == 2 or ctrlList == "active":
87 return self.active()
88 else:
89 raise ValueError( "Unknown argument: {}".format( ctrlList ) )
90
Devin Lim142b5342017-07-20 15:22:39 -070091 def getIps( self, activeOnly=False, allNode=False ):
92 """
93 Description:
94 get the list of the ip. Default to get ips of running nodes.
95 Required:
96 * activeOnly - True for getting ips of active nodes
97 * allNode - True for getting ips of all nodes
98 Returns:
99 Retruns ips of active nodes if activeOnly is True.
100 Returns ips of all nodes if allNode is True.
101 """
Jon Hallca319892017-06-15 15:25:22 -0700102 ips = []
Devin Lim142b5342017-07-20 15:22:39 -0700103 if allNode:
Jon Hallca319892017-06-15 15:25:22 -0700104 nodeList = self.controllers
Devin Lim142b5342017-07-20 15:22:39 -0700105 else:
106 if activeOnly:
107 nodeList = self.active()
108 else:
109 nodeList = self.runningNodes
110
Jon Hallca319892017-06-15 15:25:22 -0700111 for ctrl in nodeList:
112 ips.append( ctrl.ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -0700113
Jon Hallca319892017-06-15 15:25:22 -0700114 return ips
115
Jon Halla1e8e512018-05-11 13:30:57 -0700116 def clearActive( self ):
Jon Hallca319892017-06-15 15:25:22 -0700117 """
Devin Lim142b5342017-07-20 15:22:39 -0700118 Description:
Jon Halla1e8e512018-05-11 13:30:57 -0700119 Sets the activeness of each cluster node to be False
Jon Hallca319892017-06-15 15:25:22 -0700120 """
Jon Hallab611372018-02-21 15:26:05 -0800121 for ctrl in self.controllers:
Devin Lim142b5342017-07-20 15:22:39 -0700122 ctrl.active = False
123
124 def getRunningPos( self ):
125 """
126 Description:
127 get the position of the active running nodes.
128 Required:
129 Returns:
130 Retruns the list of the position of the active
131 running nodes.
132 """
133 return [ ctrl.pos for ctrl in self.runningNodes
134 if ctrl.active ]
135
136 def setRunningNode( self, numCtrls ):
137 """
138 Description:
139 Set running nodes of n number of nodes.
140 It will create new list of runningNodes.
141 If numCtrls is a list, it will add the nodes of the
142 list.
143 Required:
144 * numCtrls - number of nodes to be set.
145 Returns:
146 """
147 self.runningNodes = []
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700148 for i in numCtrls if isinstance( numCtrls, list ) else range( numCtrls ):
Devin Lim142b5342017-07-20 15:22:39 -0700149 self.runningNodes.append( self.controllers[ i ] )
150 self.numCtrls = len( numCtrls ) if isinstance( numCtrls, list ) else numCtrls
151
Jon Hall3e6edb32018-08-21 16:20:30 -0700152 def setAtomixNodes( self, nodes ):
153 """
154 Description:
155 Sets the list of Atomix nodes for the cluster
156 If nodes is a list, it will add the nodes of the list.
157 If nodes is an int, the function will set the Atomix nodes
158 to be the first n in the list of controllers.
159 Required:
160 * nodes - number of nodes to be set, or a list of nodes to set
161 Returns:
162 """
163 self.atomixNodes = []
164 for i in nodes if isinstance( nodes, list ) else range( nodes ):
165 self.atomixNodes.append( self.controllers[ i ] )
166
167 def getControllers( self, node=None ):
168 """
169 Description:
170 Get the list of all controllers in a cluster or a controller at an index in the list
171 Optional Arguments:
172 * node - position of the node to get from the list of controllers.
173 Returns:
174 Return a list of controllers in the cluster if node is None
175 if not, it will return the controller at the given index.
176 """
177 result = self.controllers
178 return result if node is None else result[ node % len( result ) ]
179
180 def getRunningNodes( self, node=None ):
181 """
182 Description:
183 Get the list of all controllers in a cluster that should be running or
184 a controller at an index in the list
185 Optional Arguments:
186 * node - position of the node to get from the list of controllers.
187 Returns:
188 Return a list of controllers in the cluster if node is None
189 if not, it will return the controller at the given index.
190 """
191 result = self.runningNodes
192 return result if node is None else result[ node % len( result ) ]
193
Devin Lim142b5342017-07-20 15:22:39 -0700194 def active( self, node=None ):
195 """
196 Description:
Jon Hall3e6edb32018-08-21 16:20:30 -0700197 Get the list of all active controllers in a cluster or
198 a controller at an index in the list
199 Optional Arguments:
200 * node - position of the node to get from the list of controllers.
Devin Lim142b5342017-07-20 15:22:39 -0700201 Returns:
Jon Hall3e6edb32018-08-21 16:20:30 -0700202 Return a list of controllers in the cluster if node is None
203 if not, it will return the controller at the given index.
Devin Lim142b5342017-07-20 15:22:39 -0700204 """
205 result = [ ctrl for ctrl in self.runningNodes
Jon Hallca319892017-06-15 15:25:22 -0700206 if ctrl.active ]
Devin Lim142b5342017-07-20 15:22:39 -0700207 return result if node is None else result[ node % len( result ) ]
Jon Hallca319892017-06-15 15:25:22 -0700208
209 def next( self ):
210 """
Jon Halla1e8e512018-05-11 13:30:57 -0700211 An iterator for the cluster's active controllers that
Jon Hallca319892017-06-15 15:25:22 -0700212 resets when there are no more elements.
213
214 Returns the next controller in the cluster
215 """
216 try:
Jon Halla1e8e512018-05-11 13:30:57 -0700217 node = self.iterator.next()
218 assert node.active
219 return node
220 except ( StopIteration, AssertionError ):
Jon Hallca319892017-06-15 15:25:22 -0700221 self.reset()
222 try:
223 return self.iterator.next()
224 except StopIteration:
225 raise RuntimeError( "There are no active nodes in the cluster" )
226
227 def reset( self ):
228 """
229 Resets the cluster iterator.
230
231 This should be used whenever a node's active state is changed
232 and is also used internally when the iterator has been exhausted.
233 """
234 self.iterator = iter( self.active() )
235
Jon Hall3e6edb32018-08-21 16:20:30 -0700236 def createCell( self, cellName, cellApps, mininetIp, useSSH, onosIps,
237 atomixIps, installMax=False ):
Jon Hallca319892017-06-15 15:25:22 -0700238 """
Devin Lim142b5342017-07-20 15:22:39 -0700239 Description:
240 create a new cell
241 Required:
242 * cellName - The name of the cell.
You Wang09b596b2018-01-10 10:42:38 -0800243 * cellApps - The ONOS apps string.
You Wanga0f6ff62018-01-11 15:46:30 -0800244 * mininetIp - Mininet IP address.
Devin Lim142b5342017-07-20 15:22:39 -0700245 * useSSH - True for using ssh when creating a cell
Jon Hall3e6edb32018-08-21 16:20:30 -0700246 * onosIps - ip( s ) of the ONOS node( s ).
247 * atomixIps - ip( s ) of the Atomix node( s ).
248
Devin Lim142b5342017-07-20 15:22:39 -0700249 Returns:
250 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700251 self.command( "createCellFile",
252 args=[ main.ONOSbench.ip_address,
Devin Lim40a19092017-08-15 14:54:22 -0700253 cellName,
You Wanga0f6ff62018-01-11 15:46:30 -0800254 mininetIp,
You Wang0d9f2c02018-08-10 14:56:32 -0700255 cellApps,
Jon Hall3e6edb32018-08-21 16:20:30 -0700256 onosIps,
257 atomixIps,
Devin Lim40a19092017-08-15 14:54:22 -0700258 main.ONOScell.karafUser,
259 useSSH ],
Devin Lime9f0ccf2017-08-11 17:25:12 -0700260 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700261 getFrom="all" if installMax else "running" )
Devin Lim40a19092017-08-15 14:54:22 -0700262
You Wangf9d95be2018-08-01 14:35:37 -0700263 def uninstallAtomix( self, uninstallMax ):
264 """
265 Description:
266 uninstalling atomix
267 Required:
268 * uninstallMax - True for uninstalling max number of nodes
269 False for uninstalling the current running nodes.
270 Returns:
271 Returns main.TRUE if it successfully uninstalled.
272 """
273 result = main.TRUE
274 uninstallResult = self.command( "atomixUninstall",
275 kwargs={ "nodeIp": "ipAddress" },
276 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700277 getFrom="all" if uninstallMax else "running",
You Wangf9d95be2018-08-01 14:35:37 -0700278 funcFromCtrl=True )
279 for uninstallR in uninstallResult:
280 result = result and uninstallR
281 return result
282
283 def uninstallOnos( self, uninstallMax ):
Devin Lim142b5342017-07-20 15:22:39 -0700284 """
285 Description:
286 uninstalling onos
287 Required:
288 * uninstallMax - True for uninstalling max number of nodes
289 False for uninstalling the current running nodes.
290 Returns:
291 Returns main.TRUE if it successfully uninstalled.
292 """
Devin Lim40a19092017-08-15 14:54:22 -0700293 result = main.TRUE
294 uninstallResult = self.command( "onosUninstall",
Jon Hall4173b242017-09-12 17:04:38 -0700295 kwargs={ "nodeIp": "ipAddress" },
Devin Lim40a19092017-08-15 14:54:22 -0700296 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700297 getFrom="all" if uninstallMax else "running",
Devin Lim40a19092017-08-15 14:54:22 -0700298 funcFromCtrl=True )
299 for uninstallR in uninstallResult:
300 result = result and uninstallR
301 return result
Devin Lim142b5342017-07-20 15:22:39 -0700302
Devin Lime9f0ccf2017-08-11 17:25:12 -0700303 def applyCell( self, cellName, installMax=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700304 """
305 Description:
306 apply the cell with cellName. It will also verify the
307 cell.
308 Required:
309 * cellName - The name of the cell.
310 Returns:
311 Returns main.TRUE if it successfully set and verify cell.
312 """
Devin Lime9f0ccf2017-08-11 17:25:12 -0700313 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700314 args=[ cellName ],
315 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700316 getFrom="all" )
317 benchCellResult = main.ONOSbench.setCell( cellName )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700318 verifyResult = self.command( "verifyCell",
Jon Hall4173b242017-09-12 17:04:38 -0700319 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700320 getFrom="all" )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700321 result = main.TRUE
322 for i in range( len( setCellResult ) ):
323 result = result and setCellResult[ i ] and verifyResult[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700324 result = result and benchCellResult
Devin Lime9f0ccf2017-08-11 17:25:12 -0700325 return result
Devin Lim142b5342017-07-20 15:22:39 -0700326
327 def checkService( self ):
328 """
329 Description:
330 Checking if the onos service is up. If not, it will
331 start the onos service manually.
332 Required:
333 Returns:
334 Returns main.TRUE if it successfully checked
335 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700336 getFrom = "running"
Devin Lim142b5342017-07-20 15:22:39 -0700337 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700338 onosUp = self.command( "isup",
339 args=[ "ipAddress" ],
340 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700341 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700342 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700343 ctrlList = self.fromNode( getFrom )
Devin Lim40a19092017-08-15 14:54:22 -0700344 for i in range( len( onosUp ) ):
Jon Hall3e6edb32018-08-21 16:20:30 -0700345 ctrl = ctrlList[ i ]
Devin Lim40a19092017-08-15 14:54:22 -0700346 onosIsUp = onosIsUp and onosUp[ i ]
347 if onosUp[ i ] == main.TRUE:
Jon Hall9655dcb2018-02-02 11:19:06 -0800348 main.log.info( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700349 else:
Jon Hall9655dcb2018-02-02 11:19:06 -0800350 main.log.warn( ctrl.name + " may not be up." )
351 return onosIsUp
Devin Lim142b5342017-07-20 15:22:39 -0700352
You Wangf9d95be2018-08-01 14:35:37 -0700353 def killAtomix( self, killMax, stopAtomix ):
354 """
355 Description:
356 killing atomix. It will either kill the current runningnodes or
357 max number of the nodes.
358 Required:
359 * killRemoveMax - The boolean that will decide either to kill
360 only running nodes ( False ) or max number of nodes ( True ).
361 * stopAtomix - If wish to atomix onos before killing it. True for
362 enable stop, False for disable stop.
363 Returns:
364 Returns main.TRUE if successfully killing it.
365 """
366 result = main.TRUE
367 killResult = self.command( "atomixKill",
368 args=[ "ipAddress" ],
369 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700370 getFrom="all" if killMax else "running",
You Wangf9d95be2018-08-01 14:35:37 -0700371 funcFromCtrl=True )
372 for i in range( len( killResult ) ):
373 result = result and killResult[ i ]
You Wangf9d95be2018-08-01 14:35:37 -0700374 return result
375
376 def killOnos( self, killMax, stopOnos ):
Devin Lim142b5342017-07-20 15:22:39 -0700377 """
378 Description:
379 killing the onos. It will either kill the current runningnodes or
380 max number of the nodes.
381 Required:
382 * killRemoveMax - The boolean that will decide either to kill
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700383 only running nodes ( False ) or max number of nodes ( True ).
Devin Lim142b5342017-07-20 15:22:39 -0700384 * stopOnos - If wish to stop onos before killing it. True for
385 enable stop , False for disable stop.
386 Returns:
387 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700388 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700389 getFrom = "all" if killMax else "running"
Jon Hallca319892017-06-15 15:25:22 -0700390 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700391 killResult = self.command( "onosKill",
392 args=[ "ipAddress" ],
393 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700394 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700395 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700396 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700397 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700398 result = result and killResult[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700399 ctrlList[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700400 return result
401
Jon Hall3c0114c2020-08-11 15:07:42 -0700402 def dockerStop( self, killMax, atomix=True ):
403 """
404 Description:
405 killing the onos docker containers. It will either kill the
406 current runningnodes or max number of the nodes.
407 Required:
408 * killRemoveMax - The boolean that will decide either to kill
409 only running nodes ( False ) or max number of nodes ( True ).
410 Returns:
411 Returns main.TRUE if successfully killing it.
412 """
413 getFrom = "all" if killMax else "running"
414 result = main.TRUE
415 stopResult = self.command( "dockerStop",
416 args=[ "name" ],
417 specificDriver=4,
418 getFrom=getFrom,
419 funcFromCtrl=True )
420 ctrlList = self.fromNode( getFrom )
421 for i in range( len( stopResult ) ):
422 result = result and stopResult[ i ]
423 ctrlList[ i ].active = False
424 atomixResult = main.TRUE
425 if atomix:
426 atomixResult = self.stopAtomixDocker( killMax )
427 return result and atomixResult
428
429 def dockerBuild( self, pull=True ):
430 """
431 Description:
432 Build ONOS docker image
433 Optional:
434 * pull - Try to pull latest image before building
435 Returns:
436 Returns main.TRUE if successfully killing it.
437 """
438 getFrom = "all"
439 result = main.TRUE
440 atomixResult = []
441 buildResult = []
442 if self.atomixImageTag:
443 atomixResult = self.command( "dockerPull",
444 args=[ self.atomixImageTag ],
445 specificDriver=4,
446 getFrom=getFrom,
447 funcFromCtrl=False )
448 if not self.dockerImageTag:
449 main.log.error( "No image given, exiting test" )
450 return main.FALSE
451 if pull and self.dockerImageTag:
452 buildResult = self.command( "dockerPull",
453 args=[ self.dockerImageTag ],
454 specificDriver=4,
455 getFrom=getFrom,
456 funcFromCtrl=False )
457 for i in range( len( buildResult ) ):
458 result = result and buildResult[ i ]
459 if self.dockerSkipBuild:
460 return main.TRUE
461 if not result and self.dockerBuildCmd:
462 buildResult = self.command( "makeDocker",
463 args=[ self.dockerFilePath, self.dockerBuildCmd ],
464 kwargs={ "timeout": self.dockerBuildTimeout,
465 "prompt": "Successfully tagged %s" % self.dockerImageTag },
466 specificDriver=4,
467 getFrom=getFrom,
468 funcFromCtrl=False )
469
470 elif not result:
471 buildResult = self.command( "dockerBuild",
472 args=[ self.dockerFilePath, self.dockerImageTag ],
473 kwargs={ "timeout": self.dockerBuildTimeout,
474 "pull": pull },
475 specificDriver=4,
476 getFrom=getFrom,
477 funcFromCtrl=False )
478 for i in range( len( atomixResult ) ):
479 result = result and atomixResult[ i ]
480 for i in range( len( buildResult ) ):
481 result = result and buildResult[ i ]
482 return result
483
Devin Lim142b5342017-07-20 15:22:39 -0700484 def ssh( self ):
485 """
486 Description:
487 set up ssh to the onos
488 Required:
489 Returns:
490 Returns main.TRUE if it successfully setup the ssh to
491 the onos.
492 """
Devin Lim40a19092017-08-15 14:54:22 -0700493 result = main.TRUE
Jon Hall3c0114c2020-08-11 15:07:42 -0700494 if self.useDocker:
495 driver = 2
496 kwargs = { "userName": "karafUser",
497 "userPWD": "karafPass" }
498 else:
499 driver = 1
500 kwargs = { "node": "ipAddress" }
Devin Lim40a19092017-08-15 14:54:22 -0700501 sshResult = self.command( "onosSecureSSH",
Jon Hall3c0114c2020-08-11 15:07:42 -0700502 kwargs=kwargs,
503 specificDriver=driver,
Jon Hall3e6edb32018-08-21 16:20:30 -0700504 getFrom="running",
Devin Lim40a19092017-08-15 14:54:22 -0700505 funcFromCtrl=True )
506 for sshR in sshResult:
507 result = result and sshR
508 return result
Devin Lim142b5342017-07-20 15:22:39 -0700509
Jon Hall3e6edb32018-08-21 16:20:30 -0700510 def installAtomix( self, installParallel=True ):
You Wangf9d95be2018-08-01 14:35:37 -0700511 """
512 Description:
Jon Hall3e6edb32018-08-21 16:20:30 -0700513 Installing Atomix.
You Wangf9d95be2018-08-01 14:35:37 -0700514 Required:
You Wangf9d95be2018-08-01 14:35:37 -0700515 Returns:
516 Returns main.TRUE if it successfully installed
517 """
518 result = main.TRUE
Jon Hall3c0114c2020-08-11 15:07:42 -0700519 if self.useDocker:
520 # We will do this as part of startDocker
521 return result
You Wangf9d95be2018-08-01 14:35:37 -0700522 threads = []
523 i = 0
Jon Hall3e6edb32018-08-21 16:20:30 -0700524 for ctrl in self.atomixNodes:
525 options = "-f"
You Wangf9d95be2018-08-01 14:35:37 -0700526 if installParallel:
527 t = main.Thread( target=ctrl.Bench.atomixInstall,
528 name="atomix-install-" + ctrl.name,
529 kwargs={ "node" : ctrl.ipAddress,
530 "options" : options } )
531 threads.append( t )
532 t.start()
533 else:
534 result = result and \
535 main.ONOSbench.atomixInstall( node=ctrl.ipAddress, options=options )
536 i += 1
537 if installParallel:
538 for t in threads:
539 t.join()
540 result = result and t.result
541 return result
542
543 def installOnos( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700544 """
545 Description:
546 Installing onos.
547 Required:
548 * installMax - True for installing max number of nodes
549 False for installing current running nodes only.
550 Returns:
551 Returns main.TRUE if it successfully installed
552 """
553 result = main.TRUE
554 threads = []
555 i = 0
556 for ctrl in self.controllers if installMax else self.runningNodes:
557 options = "-f"
558 if installMax and i >= self.numCtrls:
559 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700560 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700561 t = main.Thread( target=ctrl.Bench.onosInstall,
You Wangf9d95be2018-08-01 14:35:37 -0700562 name="onos-install-" + ctrl.name,
Jon Hall4173b242017-09-12 17:04:38 -0700563 kwargs={ "node" : ctrl.ipAddress,
564 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700565 threads.append( t )
566 t.start()
567 else:
568 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700569 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Jon Halla6771b32018-01-26 16:07:28 -0800570 i += 1
Devin Lime9f0ccf2017-08-11 17:25:12 -0700571 if installParallel:
572 for t in threads:
573 t.join()
574 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700575 return result
576
Jon Hall3c0114c2020-08-11 15:07:42 -0700577 def startONOSDocker( self, installMax=True, installParallel=True ):
578 """
579 Description:
580 Installing onos via docker containers.
581 Required:
582 * installMax - True for installing max number of nodes
583 False for installing current running nodes only.
584 Returns:
585 Returns main.TRUE if it successfully installed
586 """
587 result = main.TRUE
588 threads = []
589 for ctrl in self.controllers if installMax else self.runningNodes:
590 if installParallel:
591 t = main.Thread( target=ctrl.server.dockerRun,
592 name="onos-run-docker-" + ctrl.name,
593 args=[ self.dockerImageTag, ctrl.name ],
594 kwargs={ "options" : self.dockerOptions } )
595 threads.append( t )
596 t.start()
597 else:
598 result = result and \
599 ctrl.server.dockerRun( self.dockerImageTag,
600 ctrl.name,
601 options=self.dockerOptions )
602 if installParallel:
603 for t in threads:
604 t.join()
605 result = result and t.result
606 return result
607
608 def startAtomixDocker( self, installParallel=True ):
609 """
610 Description:
611 Installing atomix via docker containers.
612 Required:
613 * installParallel - True for installing atomix in parallel.
614 Returns:
615 Returns main.TRUE if it successfully installed
616 """
617 result = main.TRUE
618 threads = []
619 for ctrl in self.atomixNodes:
620 if installParallel:
621 t = main.Thread( target=ctrl.server.dockerRun,
622 name="atomix-run-docker-" + ctrl.name,
623 args=[ self.atomixImageTag, "atomix-" + ctrl.name ],
624 kwargs={ "options" : main.params['CLUSTER']['atomixOptions'],
625 "imageArgs": " --config /opt/atomix/conf/atomix.json --ignore-resources"} )
626 threads.append( t )
627 t.start()
628 else:
629 result = result and \
630 ctrl.server.dockerRun( self.atomixImageTag,
631 "atomix-" + ctrl.name,
632 options=main.params['CLUSTER']['atomixOptions'] )
633 if installParallel:
634 for t in threads:
635 t.join()
636 result = result and t.result
637 return result
638
639 def stopAtomixDocker( self, killMax=True, installParallel=True ):
640 """
641 Description:
642 Stoping all atomix containers
643 Required:
644 * killMax - True for stoping max number of nodes
645 False for stoping current running nodes only.
646 Returns:
647 Returns main.TRUE if it successfully stoped
648 """
649 result = main.TRUE
650 threads = []
651 for ctrl in self.controllers if killMax else self.atomixNodes:
652 if installParallel:
653 t = main.Thread( target=ctrl.server.dockerStop,
654 name="atomix-stop-docker-" + ctrl.name,
655 args=[ "atomix-" + ctrl.name ] )
656 threads.append( t )
657 t.start()
658 else:
659 result = result and \
660 ctrl.server.dockerStop( "atomix-" + ctrl.name )
661 if installParallel:
662 for t in threads:
663 t.join()
664 result = result and t.result
665 return result
666
667 def genPartitions( self, path="/tmp/cluster.json" ):
668 """
669 Description:
670 Create cluster config and move to each onos server
671 Required:
672 * installMax - True for installing max number of nodes
673 False for installing current running nodes only.
674 Returns:
675 Returns main.TRUE if it successfully installed
676 """
677 result = main.TRUE
678 # move files to onos servers
679 for ctrl in self.atomixNodes:
680 localAtomixFile = ctrl.ip_address + "-atomix.json"
681 result = result and main.ONOSbench.generateAtomixConfig( ctrl.server.ip_address, path=localAtomixFile )
682 result = result and main.ONOSbench.scp( ctrl.server,
683 localAtomixFile,
684 "/tmp/atomix.json",
685 direction="to" )
686 for ctrl in self.controllers:
687 localOnosFile = ctrl.ip_address + "-cluster.json"
688 result = result and main.ONOSbench.generateOnosConfig( ctrl.server.ip_address, path=localOnosFile )
689 result = result and main.ONOSbench.scp( ctrl.server,
690 localOnosFile,
691 path,
692 direction="to" )
693 return result
694
Jon Hallca319892017-06-15 15:25:22 -0700695 def startCLIs( self ):
696 """
Devin Lim142b5342017-07-20 15:22:39 -0700697 Description:
698 starting Onos using onosCli driver
699 Required:
700 Returns:
701 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700702 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700703 getFrom = "running"
Devin Lim40a19092017-08-15 14:54:22 -0700704 result = main.TRUE
705 cliResults = self.command( "startOnosCli",
706 args=[ "ipAddress" ],
707 specificDriver=2,
Jon Hall3e6edb32018-08-21 16:20:30 -0700708 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700709 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700710 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700711 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700712 result = result and cliResults[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700713 ctrlList[ i ].active = True
Devin Lim40a19092017-08-15 14:54:22 -0700714 return result
Jon Hallca319892017-06-15 15:25:22 -0700715
Devin Lim3ebd5e72017-11-14 10:38:00 -0800716 def nodesCheck( self ):
You Wang0d9f2c02018-08-10 14:56:32 -0700717 """
718 Description:
719 Checking if all the onos nodes are in READY state
720 Required:
721 Returns:
722 Returns True if it successfully checked
723 """
Devin Lim3ebd5e72017-11-14 10:38:00 -0800724 results = True
725 nodesOutput = self.command( "nodes", specificDriver=2 )
726 ips = sorted( self.getIps( activeOnly=True ) )
727 for i in nodesOutput:
728 try:
729 current = json.loads( i )
730 activeIps = []
731 currentResult = False
732 for node in current:
733 if node[ 'state' ] == 'READY':
734 activeIps.append( node[ 'ip' ] )
735 activeIps.sort()
736 if ips == activeIps:
737 currentResult = True
Jon Hall3e6edb32018-08-21 16:20:30 -0700738 else:
You Wang68568b12019-03-04 11:49:57 -0800739 main.log.warn( "{} != {}".format( ips, activeIps ) )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800740 except ( ValueError, TypeError ):
741 main.log.error( "Error parsing nodes output" )
742 main.log.warn( repr( i ) )
743 currentResult = False
744 results = results and currentResult
Jon Hall3c0114c2020-08-11 15:07:42 -0700745 # Check to make sure all bundles are started
746 bundleOutput = self.command( "sendline", args=[ "bundle:list" ] )
747 for i in bundleOutput:
748 if "START LEVEL 100" in i:
749 currentResult = True
750 else:
751 currentResult = False
752 main.log.warn( "Node's bundles not fully started" )
753 main.log.debug( i )
754 results = results and currentResult
Devin Lim3ebd5e72017-11-14 10:38:00 -0800755 return results
756
You Wang0d9f2c02018-08-10 14:56:32 -0700757 def appsCheck( self, apps ):
758 """
759 Description:
760 Checking if all the applications are activated
761 Required:
762 apps: list of applications that are expected to be activated
763 Returns:
764 Returns True if it successfully checked
765 """
766 results = True
767 for app in apps:
768 states = self.command( "appStatus",
769 args=[ app ],
770 specificDriver=2 )
771 for i in range( len( states ) ):
772 ctrl = self.controllers[ i ]
773 if states[ i ] == "ACTIVE":
774 results = results and True
775 main.log.info( "{}: {} is activated".format( ctrl.name, app ) )
776 else:
777 results = False
778 main.log.warn( "{}: {} is in {} state".format( ctrl.name, app, states[ i ] ) )
779 return results
780
Jon Hall3c0114c2020-08-11 15:07:42 -0700781 def attachToONOSDocker( self ):
782 """
783 Description:
784 connect to onos docker using onosCli driver
785 Required:
786 Returns:
787 Returns main.TRUE if it successfully started.
788 """
789 getFrom = "running"
790 result = main.TRUE
791 execResults = self.command( "dockerExec",
792 args=[ "name" ],
793 kwargs={ "dockerPrompt": "dockerPrompt" },
794 specificDriver=2,
795 getFrom=getFrom,
796 funcFromCtrl=True )
797 ctrlList = self.fromNode( getFrom )
798 for i in range( len( execResults ) ):
799 result = result and execResults[ i ]
800 ctrlList[ i ].active = True
801 return result
802
803 def prepareForCLI( self ):
804 """
805 Description:
806 prepare docker to connect to the onos cli
807 Required:
808 Returns:
809 Returns main.TRUE if it successfully started.
810 """
811 getFrom = "running"
812 for ctrl in self.getRunningNodes():
813 ctrl.CLI.inDocker = True
814 result = main.TRUE
815 execResults = self.command( "prepareForCLI",
816 specificDriver=2,
817 getFrom=getFrom,
818 funcFromCtrl=True )
819 ctrlList = self.fromNode( getFrom )
820 for i in range( len( execResults ) ):
821 result = result and execResults[ i ]
822 ctrlList[ i ].active = True
823 return result
824
Devin Lim142b5342017-07-20 15:22:39 -0700825 def printResult( self, results, activeList, logLevel="debug" ):
826 """
827 Description:
828 Print the value of the list.
829 Required:
830 * results - list of the result
831 * activeList - list of the acitve nodes.
832 * logLevel - Type of log level you want it to be printed.
833 Returns:
834 """
835 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700836 for i in range( len( results ) ):
837 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700838
839 def allTrueResultCheck( self, results, activeList ):
840 """
841 Description:
842 check if all the result has main.TRUE.
843 Required:
844 * results - list of the result
845 * activeList - list of the acitve nodes.
846 Returns:
847 Returns True if all == main.TRUE else
848 returns False
849 """
850 self.printResult( results, activeList )
851 return all( result == main.TRUE for result in results )
852
853 def notEmptyResultCheck( self, results, activeList ):
854 """
855 Description:
856 check if all the result has any contents
857 Required:
858 * results - list of the result
859 * activeList - list of the acitve nodes.
860 Returns:
861 Returns True if all the results has
862 something else returns False
863 """
864 self.printResult( results, activeList )
865 return all( result for result in results )
866
867 def identicalResultsCheck( self, results, activeList ):
868 """
869 Description:
870 check if all the results has same output.
871 Required:
872 * results - list of the result
873 * activeList - list of the acitve nodes.
874 Returns:
875 Returns True if all the results has
876 same result else returns False
877 """
878 self.printResult( results, activeList )
879 resultOne = results[ 0 ]
880 return all( resultOne == result for result in results )
881
Devin Lime9f0ccf2017-08-11 17:25:12 -0700882 def command( self, function, args=(), kwargs={}, returnBool=False,
Jon Hall3e6edb32018-08-21 16:20:30 -0700883 specificDriver=0, contentCheck=False, getFrom="active",
Devin Lim40a19092017-08-15 14:54:22 -0700884 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700885 """
886 Description:
887 execute some function of the active nodes.
888 Required:
889 * function - name of the function
890 * args - argument of the function
891 * kwargs - kwargs of the funciton
892 * returnBool - True if wish to check all the result has main.TRUE
893 * specificDriver - specific driver to execute the function. Since
894 some of the function can be used in different drivers, it is important
895 to specify which driver it will be executed from.
896 0 - any type of driver
897 1 - from bench
898 2 - from cli
899 3 - from rest
Jon Hall3c0114c2020-08-11 15:07:42 -0700900 4 - from server
Devin Lim142b5342017-07-20 15:22:39 -0700901 * contentCheck - If this is True, it will check if the result has some
902 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700903 * getFrom - from which nodes
Jon Hall3e6edb32018-08-21 16:20:30 -0700904 2 or "active" - active nodes
905 1 or "running" - current running nodes
906 0 or "all" - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700907 * funcFromCtrl - specific function of the args/kwargs
908 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700909 Returns:
910 Returns results if not returnBool and not contentCheck
911 Returns checkTruthValue of the result if returnBool
912 Returns resultContent of the result if contentCheck
913 """
Jon Hallca319892017-06-15 15:25:22 -0700914 threads = []
Jon Hall3c0114c2020-08-11 15:07:42 -0700915 drivers = [ None, "Bench", "CLI", "REST", "server" ]
Jon Hallca319892017-06-15 15:25:22 -0700916 results = []
Jon Hall3e6edb32018-08-21 16:20:30 -0700917 for ctrl in self.fromNode( getFrom ):
Jon Hall3c0114c2020-08-11 15:07:42 -0700918 funcArgs = []
919 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700920 try:
921 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700922 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim142b5342017-07-20 15:22:39 -0700923 except AttributeError:
924 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700925 main.cleanAndExit()
Jon Hall3c0114c2020-08-11 15:07:42 -0700926 if funcFromCtrl:
927 if args:
928 try:
929 for i in range( len( args ) ):
930 funcArgs.append( getattr( ctrl, args[ i ] ) )
931 except AttributeError:
932 main.log.error( "Argument " + str( args[ i ] ) + " for " + str( f ) + " not found. Exiting the Test." )
933 main.cleanAndExit()
934 if kwargs:
935 try:
936 for k in kwargs:
937 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
938 except AttributeError as e:
939 main.log.exception("")
940 main.log.error( "Keyword Argument " + str( k ) + " for " + str( f ) + " not found. Exiting the Test." )
941 main.log.debug( "Passed kwargs: %s; dir(ctrl): %s" % ( repr( kwargs ), dir( ctrl ) ) )
942 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700943 t = main.Thread( target=f,
944 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700945 args=funcArgs if funcFromCtrl else args,
946 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700947 threads.append( t )
948 t.start()
949
950 for t in threads:
951 t.join()
952 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700953 if returnBool:
Jon Hall3e6edb32018-08-21 16:20:30 -0700954 return self.allTrueResultCheck( results, self.fromNode( getFrom ) )
Devin Lim142b5342017-07-20 15:22:39 -0700955 elif contentCheck:
Jon Hall3e6edb32018-08-21 16:20:30 -0700956 return self.notEmptyResultCheck( results, self.fromNode( getFrom ) )
Jon Hall4173b242017-09-12 17:04:38 -0700957 return results
958
959 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
960 # max segment size in bytes: 1024 * 1024 * 64
961 # multiplier is somewhat arbitrary, but the idea is the logs would have
962 # been compacted before this many segments are written
963
Jon Hall43060f62020-06-23 13:13:33 -0700964 try:
965 maxSize = float( segmentSize ) * float( multiplier )
966 ret = True
967 for n in self.runningNodes:
968 # Partition logs
969 ret = ret and n.server.folderSize( "/opt/atomix/data/raft/partitions/*/*.log",
970 size=maxSize, unit=units, ignoreRoot=False )
971 return ret
972 except Exception as e:
973 main.log.error( e )
974 main.log.error( repr( e ) )