blob: e8aa79519ecd12d4940d1f7caac32e9c0f74fedf [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" ],
Jon Hall9b0de1f2020-08-24 15:38:04 -0700707 kwargs= { "karafTimeout": "karafTimeout" },
Devin Lim40a19092017-08-15 14:54:22 -0700708 specificDriver=2,
Jon Hall3e6edb32018-08-21 16:20:30 -0700709 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700710 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700711 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700712 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700713 result = result and cliResults[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700714 ctrlList[ i ].active = True
Devin Lim40a19092017-08-15 14:54:22 -0700715 return result
Jon Hallca319892017-06-15 15:25:22 -0700716
Devin Lim3ebd5e72017-11-14 10:38:00 -0800717 def nodesCheck( self ):
You Wang0d9f2c02018-08-10 14:56:32 -0700718 """
719 Description:
720 Checking if all the onos nodes are in READY state
721 Required:
722 Returns:
723 Returns True if it successfully checked
724 """
Devin Lim3ebd5e72017-11-14 10:38:00 -0800725 results = True
726 nodesOutput = self.command( "nodes", specificDriver=2 )
727 ips = sorted( self.getIps( activeOnly=True ) )
728 for i in nodesOutput:
729 try:
730 current = json.loads( i )
731 activeIps = []
732 currentResult = False
733 for node in current:
734 if node[ 'state' ] == 'READY':
735 activeIps.append( node[ 'ip' ] )
736 activeIps.sort()
737 if ips == activeIps:
738 currentResult = True
Jon Hall3e6edb32018-08-21 16:20:30 -0700739 else:
You Wang68568b12019-03-04 11:49:57 -0800740 main.log.warn( "{} != {}".format( ips, activeIps ) )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800741 except ( ValueError, TypeError ):
742 main.log.error( "Error parsing nodes output" )
743 main.log.warn( repr( i ) )
744 currentResult = False
745 results = results and currentResult
Jon Hall3c0114c2020-08-11 15:07:42 -0700746 # Check to make sure all bundles are started
747 bundleOutput = self.command( "sendline", args=[ "bundle:list" ] )
748 for i in bundleOutput:
749 if "START LEVEL 100" in i:
750 currentResult = True
751 else:
752 currentResult = False
753 main.log.warn( "Node's bundles not fully started" )
754 main.log.debug( i )
755 results = results and currentResult
Devin Lim3ebd5e72017-11-14 10:38:00 -0800756 return results
757
You Wang0d9f2c02018-08-10 14:56:32 -0700758 def appsCheck( self, apps ):
759 """
760 Description:
761 Checking if all the applications are activated
762 Required:
763 apps: list of applications that are expected to be activated
764 Returns:
765 Returns True if it successfully checked
766 """
767 results = True
768 for app in apps:
769 states = self.command( "appStatus",
770 args=[ app ],
771 specificDriver=2 )
772 for i in range( len( states ) ):
773 ctrl = self.controllers[ i ]
774 if states[ i ] == "ACTIVE":
775 results = results and True
776 main.log.info( "{}: {} is activated".format( ctrl.name, app ) )
777 else:
778 results = False
779 main.log.warn( "{}: {} is in {} state".format( ctrl.name, app, states[ i ] ) )
780 return results
781
Jon Hall3c0114c2020-08-11 15:07:42 -0700782 def attachToONOSDocker( self ):
783 """
784 Description:
785 connect to onos docker using onosCli driver
786 Required:
787 Returns:
788 Returns main.TRUE if it successfully started.
789 """
790 getFrom = "running"
791 result = main.TRUE
792 execResults = self.command( "dockerExec",
793 args=[ "name" ],
794 kwargs={ "dockerPrompt": "dockerPrompt" },
795 specificDriver=2,
796 getFrom=getFrom,
797 funcFromCtrl=True )
798 ctrlList = self.fromNode( getFrom )
799 for i in range( len( execResults ) ):
800 result = result and execResults[ i ]
801 ctrlList[ i ].active = True
802 return result
803
804 def prepareForCLI( self ):
805 """
806 Description:
807 prepare docker to connect to the onos cli
808 Required:
809 Returns:
810 Returns main.TRUE if it successfully started.
811 """
812 getFrom = "running"
813 for ctrl in self.getRunningNodes():
814 ctrl.CLI.inDocker = True
815 result = main.TRUE
816 execResults = self.command( "prepareForCLI",
817 specificDriver=2,
818 getFrom=getFrom,
819 funcFromCtrl=True )
820 ctrlList = self.fromNode( getFrom )
821 for i in range( len( execResults ) ):
822 result = result and execResults[ i ]
823 ctrlList[ i ].active = True
824 return result
825
Devin Lim142b5342017-07-20 15:22:39 -0700826 def printResult( self, results, activeList, logLevel="debug" ):
827 """
828 Description:
829 Print the value of the list.
830 Required:
831 * results - list of the result
832 * activeList - list of the acitve nodes.
833 * logLevel - Type of log level you want it to be printed.
834 Returns:
835 """
836 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700837 for i in range( len( results ) ):
838 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700839
840 def allTrueResultCheck( self, results, activeList ):
841 """
842 Description:
843 check if all the result has main.TRUE.
844 Required:
845 * results - list of the result
846 * activeList - list of the acitve nodes.
847 Returns:
848 Returns True if all == main.TRUE else
849 returns False
850 """
851 self.printResult( results, activeList )
852 return all( result == main.TRUE for result in results )
853
854 def notEmptyResultCheck( self, results, activeList ):
855 """
856 Description:
857 check if all the result has any contents
858 Required:
859 * results - list of the result
860 * activeList - list of the acitve nodes.
861 Returns:
862 Returns True if all the results has
863 something else returns False
864 """
865 self.printResult( results, activeList )
866 return all( result for result in results )
867
868 def identicalResultsCheck( self, results, activeList ):
869 """
870 Description:
871 check if all the results has same output.
872 Required:
873 * results - list of the result
874 * activeList - list of the acitve nodes.
875 Returns:
876 Returns True if all the results has
877 same result else returns False
878 """
879 self.printResult( results, activeList )
880 resultOne = results[ 0 ]
881 return all( resultOne == result for result in results )
882
Devin Lime9f0ccf2017-08-11 17:25:12 -0700883 def command( self, function, args=(), kwargs={}, returnBool=False,
Jon Hall3e6edb32018-08-21 16:20:30 -0700884 specificDriver=0, contentCheck=False, getFrom="active",
Devin Lim40a19092017-08-15 14:54:22 -0700885 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700886 """
887 Description:
888 execute some function of the active nodes.
889 Required:
890 * function - name of the function
891 * args - argument of the function
892 * kwargs - kwargs of the funciton
893 * returnBool - True if wish to check all the result has main.TRUE
894 * specificDriver - specific driver to execute the function. Since
895 some of the function can be used in different drivers, it is important
896 to specify which driver it will be executed from.
897 0 - any type of driver
898 1 - from bench
899 2 - from cli
900 3 - from rest
Jon Hall3c0114c2020-08-11 15:07:42 -0700901 4 - from server
Devin Lim142b5342017-07-20 15:22:39 -0700902 * contentCheck - If this is True, it will check if the result has some
903 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700904 * getFrom - from which nodes
Jon Hall3e6edb32018-08-21 16:20:30 -0700905 2 or "active" - active nodes
906 1 or "running" - current running nodes
907 0 or "all" - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700908 * funcFromCtrl - specific function of the args/kwargs
909 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700910 Returns:
911 Returns results if not returnBool and not contentCheck
912 Returns checkTruthValue of the result if returnBool
913 Returns resultContent of the result if contentCheck
914 """
Jon Hallca319892017-06-15 15:25:22 -0700915 threads = []
Jon Hall3c0114c2020-08-11 15:07:42 -0700916 drivers = [ None, "Bench", "CLI", "REST", "server" ]
Jon Hallca319892017-06-15 15:25:22 -0700917 results = []
Jon Hall3e6edb32018-08-21 16:20:30 -0700918 for ctrl in self.fromNode( getFrom ):
Jon Hall3c0114c2020-08-11 15:07:42 -0700919 funcArgs = []
920 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700921 try:
922 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700923 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim142b5342017-07-20 15:22:39 -0700924 except AttributeError:
925 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700926 main.cleanAndExit()
Jon Hall3c0114c2020-08-11 15:07:42 -0700927 if funcFromCtrl:
928 if args:
929 try:
930 for i in range( len( args ) ):
931 funcArgs.append( getattr( ctrl, args[ i ] ) )
932 except AttributeError:
933 main.log.error( "Argument " + str( args[ i ] ) + " for " + str( f ) + " not found. Exiting the Test." )
934 main.cleanAndExit()
935 if kwargs:
936 try:
937 for k in kwargs:
938 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
939 except AttributeError as e:
940 main.log.exception("")
941 main.log.error( "Keyword Argument " + str( k ) + " for " + str( f ) + " not found. Exiting the Test." )
942 main.log.debug( "Passed kwargs: %s; dir(ctrl): %s" % ( repr( kwargs ), dir( ctrl ) ) )
943 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700944 t = main.Thread( target=f,
945 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700946 args=funcArgs if funcFromCtrl else args,
947 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700948 threads.append( t )
949 t.start()
950
951 for t in threads:
952 t.join()
953 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700954 if returnBool:
Jon Hall3e6edb32018-08-21 16:20:30 -0700955 return self.allTrueResultCheck( results, self.fromNode( getFrom ) )
Devin Lim142b5342017-07-20 15:22:39 -0700956 elif contentCheck:
Jon Hall3e6edb32018-08-21 16:20:30 -0700957 return self.notEmptyResultCheck( results, self.fromNode( getFrom ) )
Jon Hall4173b242017-09-12 17:04:38 -0700958 return results
959
960 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
961 # max segment size in bytes: 1024 * 1024 * 64
962 # multiplier is somewhat arbitrary, but the idea is the logs would have
963 # been compacted before this many segments are written
964
Jon Hall43060f62020-06-23 13:13:33 -0700965 try:
966 maxSize = float( segmentSize ) * float( multiplier )
967 ret = True
968 for n in self.runningNodes:
969 # Partition logs
970 ret = ret and n.server.folderSize( "/opt/atomix/data/raft/partitions/*/*.log",
971 size=maxSize, unit=units, ignoreRoot=False )
972 return ret
973 except Exception as e:
974 main.log.error( e )
975 main.log.error( repr( e ) )