blob: aa63714ea82f425c68036eceef347b158cabf1ea [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
Jon Hall214f88b2020-09-21 10:21:42 -0700608 def startONOSDockerNode( self, node ):
609 """
610 Description:
611 Installing onos via docker container on a specific node.
612 Required:
613 * node - the node to install ONOS on, given in index of runningNodes
614 Returns:
615 Returns main.TRUE if it successfully installed
616 """
617 ctrl = self.runningNodes[ node ]
618 result = ctrl.server.dockerRun( self.dockerImageTag,
619 ctrl.name,
620 options=self.dockerOptions )
621 return result
622
Jon Hall3c0114c2020-08-11 15:07:42 -0700623 def startAtomixDocker( self, installParallel=True ):
624 """
625 Description:
626 Installing atomix via docker containers.
627 Required:
628 * installParallel - True for installing atomix in parallel.
629 Returns:
630 Returns main.TRUE if it successfully installed
631 """
632 result = main.TRUE
633 threads = []
634 for ctrl in self.atomixNodes:
635 if installParallel:
636 t = main.Thread( target=ctrl.server.dockerRun,
637 name="atomix-run-docker-" + ctrl.name,
638 args=[ self.atomixImageTag, "atomix-" + ctrl.name ],
639 kwargs={ "options" : main.params['CLUSTER']['atomixOptions'],
640 "imageArgs": " --config /opt/atomix/conf/atomix.json --ignore-resources"} )
641 threads.append( t )
642 t.start()
643 else:
644 result = result and \
645 ctrl.server.dockerRun( self.atomixImageTag,
646 "atomix-" + ctrl.name,
647 options=main.params['CLUSTER']['atomixOptions'] )
648 if installParallel:
649 for t in threads:
650 t.join()
651 result = result and t.result
652 return result
653
654 def stopAtomixDocker( self, killMax=True, installParallel=True ):
655 """
656 Description:
657 Stoping all atomix containers
658 Required:
659 * killMax - True for stoping max number of nodes
660 False for stoping current running nodes only.
661 Returns:
662 Returns main.TRUE if it successfully stoped
663 """
664 result = main.TRUE
665 threads = []
666 for ctrl in self.controllers if killMax else self.atomixNodes:
667 if installParallel:
668 t = main.Thread( target=ctrl.server.dockerStop,
669 name="atomix-stop-docker-" + ctrl.name,
670 args=[ "atomix-" + ctrl.name ] )
671 threads.append( t )
672 t.start()
673 else:
674 result = result and \
675 ctrl.server.dockerStop( "atomix-" + ctrl.name )
676 if installParallel:
677 for t in threads:
678 t.join()
679 result = result and t.result
680 return result
681
682 def genPartitions( self, path="/tmp/cluster.json" ):
683 """
684 Description:
685 Create cluster config and move to each onos server
686 Required:
687 * installMax - True for installing max number of nodes
688 False for installing current running nodes only.
689 Returns:
690 Returns main.TRUE if it successfully installed
691 """
692 result = main.TRUE
693 # move files to onos servers
694 for ctrl in self.atomixNodes:
695 localAtomixFile = ctrl.ip_address + "-atomix.json"
696 result = result and main.ONOSbench.generateAtomixConfig( ctrl.server.ip_address, path=localAtomixFile )
697 result = result and main.ONOSbench.scp( ctrl.server,
698 localAtomixFile,
699 "/tmp/atomix.json",
700 direction="to" )
701 for ctrl in self.controllers:
702 localOnosFile = ctrl.ip_address + "-cluster.json"
703 result = result and main.ONOSbench.generateOnosConfig( ctrl.server.ip_address, path=localOnosFile )
704 result = result and main.ONOSbench.scp( ctrl.server,
705 localOnosFile,
706 path,
707 direction="to" )
708 return result
709
Jon Hallca319892017-06-15 15:25:22 -0700710 def startCLIs( self ):
711 """
Devin Lim142b5342017-07-20 15:22:39 -0700712 Description:
713 starting Onos using onosCli driver
714 Required:
715 Returns:
716 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700717 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700718 getFrom = "running"
Devin Lim40a19092017-08-15 14:54:22 -0700719 result = main.TRUE
720 cliResults = self.command( "startOnosCli",
721 args=[ "ipAddress" ],
Jon Hall9b0de1f2020-08-24 15:38:04 -0700722 kwargs= { "karafTimeout": "karafTimeout" },
Devin Lim40a19092017-08-15 14:54:22 -0700723 specificDriver=2,
Jon Hall3e6edb32018-08-21 16:20:30 -0700724 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700725 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700726 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700727 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700728 result = result and cliResults[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700729 ctrlList[ i ].active = True
Devin Lim40a19092017-08-15 14:54:22 -0700730 return result
Jon Hallca319892017-06-15 15:25:22 -0700731
Devin Lim3ebd5e72017-11-14 10:38:00 -0800732 def nodesCheck( self ):
You Wang0d9f2c02018-08-10 14:56:32 -0700733 """
734 Description:
735 Checking if all the onos nodes are in READY state
736 Required:
737 Returns:
738 Returns True if it successfully checked
739 """
Devin Lim3ebd5e72017-11-14 10:38:00 -0800740 results = True
741 nodesOutput = self.command( "nodes", specificDriver=2 )
742 ips = sorted( self.getIps( activeOnly=True ) )
743 for i in nodesOutput:
744 try:
745 current = json.loads( i )
746 activeIps = []
747 currentResult = False
748 for node in current:
749 if node[ 'state' ] == 'READY':
750 activeIps.append( node[ 'ip' ] )
751 activeIps.sort()
752 if ips == activeIps:
753 currentResult = True
Jon Hall3e6edb32018-08-21 16:20:30 -0700754 else:
Jon Hall627b1572020-12-01 12:01:15 -0800755 main.log.warn( "Expected {} != found {}".format( ips, activeIps ) )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800756 except ( ValueError, TypeError ):
757 main.log.error( "Error parsing nodes output" )
758 main.log.warn( repr( i ) )
759 currentResult = False
760 results = results and currentResult
Jon Hall3c0114c2020-08-11 15:07:42 -0700761 # Check to make sure all bundles are started
762 bundleOutput = self.command( "sendline", args=[ "bundle:list" ] )
763 for i in bundleOutput:
764 if "START LEVEL 100" in i:
765 currentResult = True
766 else:
767 currentResult = False
768 main.log.warn( "Node's bundles not fully started" )
769 main.log.debug( i )
770 results = results and currentResult
Devin Lim3ebd5e72017-11-14 10:38:00 -0800771 return results
772
You Wang0d9f2c02018-08-10 14:56:32 -0700773 def appsCheck( self, apps ):
774 """
775 Description:
776 Checking if all the applications are activated
777 Required:
778 apps: list of applications that are expected to be activated
779 Returns:
780 Returns True if it successfully checked
781 """
782 results = True
783 for app in apps:
784 states = self.command( "appStatus",
785 args=[ app ],
786 specificDriver=2 )
787 for i in range( len( states ) ):
788 ctrl = self.controllers[ i ]
789 if states[ i ] == "ACTIVE":
790 results = results and True
791 main.log.info( "{}: {} is activated".format( ctrl.name, app ) )
792 else:
793 results = False
794 main.log.warn( "{}: {} is in {} state".format( ctrl.name, app, states[ i ] ) )
795 return results
796
Jon Hall3c0114c2020-08-11 15:07:42 -0700797 def attachToONOSDocker( self ):
798 """
799 Description:
800 connect to onos docker using onosCli driver
801 Required:
802 Returns:
803 Returns main.TRUE if it successfully started.
804 """
805 getFrom = "running"
806 result = main.TRUE
807 execResults = self.command( "dockerExec",
808 args=[ "name" ],
809 kwargs={ "dockerPrompt": "dockerPrompt" },
810 specificDriver=2,
811 getFrom=getFrom,
812 funcFromCtrl=True )
813 ctrlList = self.fromNode( getFrom )
814 for i in range( len( execResults ) ):
815 result = result and execResults[ i ]
816 ctrlList[ i ].active = True
817 return result
818
819 def prepareForCLI( self ):
820 """
821 Description:
822 prepare docker to connect to the onos cli
823 Required:
824 Returns:
825 Returns main.TRUE if it successfully started.
826 """
827 getFrom = "running"
828 for ctrl in self.getRunningNodes():
829 ctrl.CLI.inDocker = True
830 result = main.TRUE
831 execResults = self.command( "prepareForCLI",
832 specificDriver=2,
833 getFrom=getFrom,
834 funcFromCtrl=True )
835 ctrlList = self.fromNode( getFrom )
836 for i in range( len( execResults ) ):
837 result = result and execResults[ i ]
838 ctrlList[ i ].active = True
839 return result
840
Devin Lim142b5342017-07-20 15:22:39 -0700841 def printResult( self, results, activeList, logLevel="debug" ):
842 """
843 Description:
844 Print the value of the list.
845 Required:
846 * results - list of the result
847 * activeList - list of the acitve nodes.
848 * logLevel - Type of log level you want it to be printed.
849 Returns:
850 """
851 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700852 for i in range( len( results ) ):
853 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700854
855 def allTrueResultCheck( self, results, activeList ):
856 """
857 Description:
858 check if all the result has main.TRUE.
859 Required:
860 * results - list of the result
861 * activeList - list of the acitve nodes.
862 Returns:
863 Returns True if all == main.TRUE else
864 returns False
865 """
866 self.printResult( results, activeList )
867 return all( result == main.TRUE for result in results )
868
869 def notEmptyResultCheck( self, results, activeList ):
870 """
871 Description:
872 check if all the result has any contents
873 Required:
874 * results - list of the result
875 * activeList - list of the acitve nodes.
876 Returns:
877 Returns True if all the results has
878 something else returns False
879 """
880 self.printResult( results, activeList )
881 return all( result for result in results )
882
883 def identicalResultsCheck( self, results, activeList ):
884 """
885 Description:
886 check if all the results has same output.
887 Required:
888 * results - list of the result
889 * activeList - list of the acitve nodes.
890 Returns:
891 Returns True if all the results has
892 same result else returns False
893 """
894 self.printResult( results, activeList )
895 resultOne = results[ 0 ]
896 return all( resultOne == result for result in results )
897
Devin Lime9f0ccf2017-08-11 17:25:12 -0700898 def command( self, function, args=(), kwargs={}, returnBool=False,
Jon Hall3e6edb32018-08-21 16:20:30 -0700899 specificDriver=0, contentCheck=False, getFrom="active",
Devin Lim40a19092017-08-15 14:54:22 -0700900 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700901 """
902 Description:
903 execute some function of the active nodes.
904 Required:
905 * function - name of the function
906 * args - argument of the function
907 * kwargs - kwargs of the funciton
908 * returnBool - True if wish to check all the result has main.TRUE
909 * specificDriver - specific driver to execute the function. Since
910 some of the function can be used in different drivers, it is important
911 to specify which driver it will be executed from.
912 0 - any type of driver
913 1 - from bench
914 2 - from cli
915 3 - from rest
Jon Hall3c0114c2020-08-11 15:07:42 -0700916 4 - from server
Devin Lim142b5342017-07-20 15:22:39 -0700917 * contentCheck - If this is True, it will check if the result has some
918 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700919 * getFrom - from which nodes
Jon Hall3e6edb32018-08-21 16:20:30 -0700920 2 or "active" - active nodes
921 1 or "running" - current running nodes
922 0 or "all" - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700923 * funcFromCtrl - specific function of the args/kwargs
924 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700925 Returns:
926 Returns results if not returnBool and not contentCheck
927 Returns checkTruthValue of the result if returnBool
928 Returns resultContent of the result if contentCheck
929 """
Jon Hallca319892017-06-15 15:25:22 -0700930 threads = []
Jon Hall3c0114c2020-08-11 15:07:42 -0700931 drivers = [ None, "Bench", "CLI", "REST", "server" ]
Jon Hallca319892017-06-15 15:25:22 -0700932 results = []
Jon Hall3e6edb32018-08-21 16:20:30 -0700933 for ctrl in self.fromNode( getFrom ):
Jon Hall3c0114c2020-08-11 15:07:42 -0700934 funcArgs = []
935 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700936 try:
937 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700938 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim142b5342017-07-20 15:22:39 -0700939 except AttributeError:
940 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700941 main.cleanAndExit()
Jon Hall3c0114c2020-08-11 15:07:42 -0700942 if funcFromCtrl:
943 if args:
944 try:
945 for i in range( len( args ) ):
946 funcArgs.append( getattr( ctrl, args[ i ] ) )
947 except AttributeError:
948 main.log.error( "Argument " + str( args[ i ] ) + " for " + str( f ) + " not found. Exiting the Test." )
949 main.cleanAndExit()
950 if kwargs:
951 try:
952 for k in kwargs:
953 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
954 except AttributeError as e:
955 main.log.exception("")
956 main.log.error( "Keyword Argument " + str( k ) + " for " + str( f ) + " not found. Exiting the Test." )
957 main.log.debug( "Passed kwargs: %s; dir(ctrl): %s" % ( repr( kwargs ), dir( ctrl ) ) )
958 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700959 t = main.Thread( target=f,
960 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700961 args=funcArgs if funcFromCtrl else args,
962 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700963 threads.append( t )
964 t.start()
965
966 for t in threads:
967 t.join()
968 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700969 if returnBool:
Jon Hall3e6edb32018-08-21 16:20:30 -0700970 return self.allTrueResultCheck( results, self.fromNode( getFrom ) )
Devin Lim142b5342017-07-20 15:22:39 -0700971 elif contentCheck:
Jon Hall3e6edb32018-08-21 16:20:30 -0700972 return self.notEmptyResultCheck( results, self.fromNode( getFrom ) )
Jon Hall4173b242017-09-12 17:04:38 -0700973 return results
974
975 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
976 # max segment size in bytes: 1024 * 1024 * 64
977 # multiplier is somewhat arbitrary, but the idea is the logs would have
978 # been compacted before this many segments are written
979
Jon Hall43060f62020-06-23 13:13:33 -0700980 try:
981 maxSize = float( segmentSize ) * float( multiplier )
982 ret = True
983 for n in self.runningNodes:
984 # Partition logs
985 ret = ret and n.server.folderSize( "/opt/atomix/data/raft/partitions/*/*.log",
986 size=maxSize, unit=units, ignoreRoot=False )
987 return ret
988 except Exception as e:
989 main.log.error( e )
990 main.log.error( repr( e ) )