blob: 2e79481d79c67439ef4a65558062714655cdea10 [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:
Jon Hall06fd0df2021-01-25 15:50:06 -0800112 ips.append( ctrl.ipAddress if ctrl.ipAddress is not 'localhost' else ctrl.address )
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 """
Jon Hall06fd0df2021-01-25 15:50:06 -0800313 result = main.TRUE
Devin Lime9f0ccf2017-08-11 17:25:12 -0700314 setCellResult = self.command( "setCell",
Jon Hall4173b242017-09-12 17:04:38 -0700315 args=[ cellName ],
316 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700317 getFrom="all" )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700318 for i in range( len( setCellResult ) ):
Jon Hall06fd0df2021-01-25 15:50:06 -0800319 result = result and setCellResult[ i ]
320 benchCellResult = main.ONOSbench.setCell( cellName )
Jon Hall3e6edb32018-08-21 16:20:30 -0700321 result = result and benchCellResult
Jon Hall06fd0df2021-01-25 15:50:06 -0800322 if not self.useDocker:
323 verifyResult = self.command( "verifyCell",
324 specificDriver=1,
325 getFrom="all" )
326 for i in range( len( verifyResult ) ):
327 result = result and verifyResult[ i ]
Devin Lime9f0ccf2017-08-11 17:25:12 -0700328 return result
Devin Lim142b5342017-07-20 15:22:39 -0700329
330 def checkService( self ):
331 """
332 Description:
333 Checking if the onos service is up. If not, it will
334 start the onos service manually.
335 Required:
336 Returns:
337 Returns main.TRUE if it successfully checked
338 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700339 getFrom = "running"
Devin Lim142b5342017-07-20 15:22:39 -0700340 onosIsUp = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700341 onosUp = self.command( "isup",
342 args=[ "ipAddress" ],
343 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700344 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700345 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700346 ctrlList = self.fromNode( getFrom )
Devin Lim40a19092017-08-15 14:54:22 -0700347 for i in range( len( onosUp ) ):
Jon Hall3e6edb32018-08-21 16:20:30 -0700348 ctrl = ctrlList[ i ]
Devin Lim40a19092017-08-15 14:54:22 -0700349 onosIsUp = onosIsUp and onosUp[ i ]
350 if onosUp[ i ] == main.TRUE:
Jon Hall9655dcb2018-02-02 11:19:06 -0800351 main.log.info( ctrl.name + " is up and ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700352 else:
Jon Hall9655dcb2018-02-02 11:19:06 -0800353 main.log.warn( ctrl.name + " may not be up." )
354 return onosIsUp
Devin Lim142b5342017-07-20 15:22:39 -0700355
You Wangf9d95be2018-08-01 14:35:37 -0700356 def killAtomix( self, killMax, stopAtomix ):
357 """
358 Description:
359 killing atomix. It will either kill the current runningnodes or
360 max number of the nodes.
361 Required:
362 * killRemoveMax - The boolean that will decide either to kill
363 only running nodes ( False ) or max number of nodes ( True ).
364 * stopAtomix - If wish to atomix onos before killing it. True for
365 enable stop, False for disable stop.
366 Returns:
367 Returns main.TRUE if successfully killing it.
368 """
369 result = main.TRUE
370 killResult = self.command( "atomixKill",
371 args=[ "ipAddress" ],
372 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700373 getFrom="all" if killMax else "running",
You Wangf9d95be2018-08-01 14:35:37 -0700374 funcFromCtrl=True )
375 for i in range( len( killResult ) ):
376 result = result and killResult[ i ]
You Wangf9d95be2018-08-01 14:35:37 -0700377 return result
378
379 def killOnos( self, killMax, stopOnos ):
Devin Lim142b5342017-07-20 15:22:39 -0700380 """
381 Description:
382 killing the onos. It will either kill the current runningnodes or
383 max number of the nodes.
384 Required:
385 * killRemoveMax - The boolean that will decide either to kill
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700386 only running nodes ( False ) or max number of nodes ( True ).
Devin Lim142b5342017-07-20 15:22:39 -0700387 * stopOnos - If wish to stop onos before killing it. True for
388 enable stop , False for disable stop.
389 Returns:
390 Returns main.TRUE if successfully killing it.
Jon Hallca319892017-06-15 15:25:22 -0700391 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700392 getFrom = "all" if killMax else "running"
Jon Hallca319892017-06-15 15:25:22 -0700393 result = main.TRUE
Devin Lim40a19092017-08-15 14:54:22 -0700394 killResult = self.command( "onosKill",
395 args=[ "ipAddress" ],
396 specificDriver=1,
Jon Hall3e6edb32018-08-21 16:20:30 -0700397 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700398 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700399 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700400 for i in range( len( killResult ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700401 result = result and killResult[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700402 ctrlList[ i ].active = False
Devin Lim142b5342017-07-20 15:22:39 -0700403 return result
404
Jon Hall3c0114c2020-08-11 15:07:42 -0700405 def dockerStop( self, killMax, atomix=True ):
406 """
407 Description:
408 killing the onos docker containers. It will either kill the
409 current runningnodes or max number of the nodes.
410 Required:
411 * killRemoveMax - The boolean that will decide either to kill
412 only running nodes ( False ) or max number of nodes ( True ).
413 Returns:
414 Returns main.TRUE if successfully killing it.
415 """
416 getFrom = "all" if killMax else "running"
417 result = main.TRUE
418 stopResult = self.command( "dockerStop",
419 args=[ "name" ],
420 specificDriver=4,
421 getFrom=getFrom,
422 funcFromCtrl=True )
423 ctrlList = self.fromNode( getFrom )
424 for i in range( len( stopResult ) ):
425 result = result and stopResult[ i ]
426 ctrlList[ i ].active = False
427 atomixResult = main.TRUE
428 if atomix:
429 atomixResult = self.stopAtomixDocker( killMax )
430 return result and atomixResult
431
432 def dockerBuild( self, pull=True ):
433 """
434 Description:
435 Build ONOS docker image
436 Optional:
437 * pull - Try to pull latest image before building
438 Returns:
439 Returns main.TRUE if successfully killing it.
440 """
441 getFrom = "all"
442 result = main.TRUE
443 atomixResult = []
444 buildResult = []
445 if self.atomixImageTag:
446 atomixResult = self.command( "dockerPull",
447 args=[ self.atomixImageTag ],
448 specificDriver=4,
449 getFrom=getFrom,
450 funcFromCtrl=False )
451 if not self.dockerImageTag:
452 main.log.error( "No image given, exiting test" )
453 return main.FALSE
454 if pull and self.dockerImageTag:
455 buildResult = self.command( "dockerPull",
456 args=[ self.dockerImageTag ],
457 specificDriver=4,
458 getFrom=getFrom,
459 funcFromCtrl=False )
460 for i in range( len( buildResult ) ):
461 result = result and buildResult[ i ]
462 if self.dockerSkipBuild:
463 return main.TRUE
464 if not result and self.dockerBuildCmd:
465 buildResult = self.command( "makeDocker",
466 args=[ self.dockerFilePath, self.dockerBuildCmd ],
467 kwargs={ "timeout": self.dockerBuildTimeout,
468 "prompt": "Successfully tagged %s" % self.dockerImageTag },
469 specificDriver=4,
470 getFrom=getFrom,
471 funcFromCtrl=False )
472
473 elif not result:
474 buildResult = self.command( "dockerBuild",
475 args=[ self.dockerFilePath, self.dockerImageTag ],
476 kwargs={ "timeout": self.dockerBuildTimeout,
477 "pull": pull },
478 specificDriver=4,
479 getFrom=getFrom,
480 funcFromCtrl=False )
481 for i in range( len( atomixResult ) ):
482 result = result and atomixResult[ i ]
483 for i in range( len( buildResult ) ):
484 result = result and buildResult[ i ]
485 return result
486
Devin Lim142b5342017-07-20 15:22:39 -0700487 def ssh( self ):
488 """
489 Description:
490 set up ssh to the onos
491 Required:
492 Returns:
493 Returns main.TRUE if it successfully setup the ssh to
494 the onos.
495 """
Devin Lim40a19092017-08-15 14:54:22 -0700496 result = main.TRUE
Jon Hall3c0114c2020-08-11 15:07:42 -0700497 if self.useDocker:
498 driver = 2
499 kwargs = { "userName": "karafUser",
500 "userPWD": "karafPass" }
501 else:
502 driver = 1
503 kwargs = { "node": "ipAddress" }
Devin Lim40a19092017-08-15 14:54:22 -0700504 sshResult = self.command( "onosSecureSSH",
Jon Hall3c0114c2020-08-11 15:07:42 -0700505 kwargs=kwargs,
506 specificDriver=driver,
Jon Hall3e6edb32018-08-21 16:20:30 -0700507 getFrom="running",
Devin Lim40a19092017-08-15 14:54:22 -0700508 funcFromCtrl=True )
509 for sshR in sshResult:
510 result = result and sshR
511 return result
Devin Lim142b5342017-07-20 15:22:39 -0700512
Jon Hall3e6edb32018-08-21 16:20:30 -0700513 def installAtomix( self, installParallel=True ):
You Wangf9d95be2018-08-01 14:35:37 -0700514 """
515 Description:
Jon Hall3e6edb32018-08-21 16:20:30 -0700516 Installing Atomix.
You Wangf9d95be2018-08-01 14:35:37 -0700517 Required:
You Wangf9d95be2018-08-01 14:35:37 -0700518 Returns:
519 Returns main.TRUE if it successfully installed
520 """
521 result = main.TRUE
Jon Hall3c0114c2020-08-11 15:07:42 -0700522 if self.useDocker:
523 # We will do this as part of startDocker
524 return result
You Wangf9d95be2018-08-01 14:35:37 -0700525 threads = []
526 i = 0
Jon Hall3e6edb32018-08-21 16:20:30 -0700527 for ctrl in self.atomixNodes:
528 options = "-f"
You Wangf9d95be2018-08-01 14:35:37 -0700529 if installParallel:
530 t = main.Thread( target=ctrl.Bench.atomixInstall,
531 name="atomix-install-" + ctrl.name,
532 kwargs={ "node" : ctrl.ipAddress,
533 "options" : options } )
534 threads.append( t )
535 t.start()
536 else:
537 result = result and \
538 main.ONOSbench.atomixInstall( node=ctrl.ipAddress, options=options )
539 i += 1
540 if installParallel:
541 for t in threads:
542 t.join()
543 result = result and t.result
544 return result
545
546 def installOnos( self, installMax=True, installParallel=True ):
Devin Lim142b5342017-07-20 15:22:39 -0700547 """
548 Description:
549 Installing onos.
550 Required:
551 * installMax - True for installing max number of nodes
552 False for installing current running nodes only.
553 Returns:
554 Returns main.TRUE if it successfully installed
555 """
556 result = main.TRUE
557 threads = []
558 i = 0
559 for ctrl in self.controllers if installMax else self.runningNodes:
560 options = "-f"
561 if installMax and i >= self.numCtrls:
562 options = "-nf"
Devin Lime9f0ccf2017-08-11 17:25:12 -0700563 if installParallel:
Jon Hall4173b242017-09-12 17:04:38 -0700564 t = main.Thread( target=ctrl.Bench.onosInstall,
You Wangf9d95be2018-08-01 14:35:37 -0700565 name="onos-install-" + ctrl.name,
Jon Hall4173b242017-09-12 17:04:38 -0700566 kwargs={ "node" : ctrl.ipAddress,
567 "options" : options } )
Devin Lime9f0ccf2017-08-11 17:25:12 -0700568 threads.append( t )
569 t.start()
570 else:
571 result = result and \
Devin Lim142b5342017-07-20 15:22:39 -0700572 main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
Jon Halla6771b32018-01-26 16:07:28 -0800573 i += 1
Devin Lime9f0ccf2017-08-11 17:25:12 -0700574 if installParallel:
575 for t in threads:
576 t.join()
577 result = result and t.result
Jon Hallca319892017-06-15 15:25:22 -0700578 return result
579
Jon Hall3c0114c2020-08-11 15:07:42 -0700580 def startONOSDocker( self, installMax=True, installParallel=True ):
581 """
582 Description:
583 Installing onos via docker containers.
584 Required:
585 * installMax - True for installing max number of nodes
586 False for installing current running nodes only.
587 Returns:
588 Returns main.TRUE if it successfully installed
589 """
590 result = main.TRUE
591 threads = []
592 for ctrl in self.controllers if installMax else self.runningNodes:
593 if installParallel:
594 t = main.Thread( target=ctrl.server.dockerRun,
595 name="onos-run-docker-" + ctrl.name,
596 args=[ self.dockerImageTag, ctrl.name ],
597 kwargs={ "options" : self.dockerOptions } )
598 threads.append( t )
599 t.start()
600 else:
601 result = result and \
602 ctrl.server.dockerRun( self.dockerImageTag,
603 ctrl.name,
604 options=self.dockerOptions )
605 if installParallel:
606 for t in threads:
607 t.join()
608 result = result and t.result
609 return result
610
Jon Hall214f88b2020-09-21 10:21:42 -0700611 def startONOSDockerNode( self, node ):
612 """
613 Description:
614 Installing onos via docker container on a specific node.
615 Required:
616 * node - the node to install ONOS on, given in index of runningNodes
617 Returns:
618 Returns main.TRUE if it successfully installed
619 """
620 ctrl = self.runningNodes[ node ]
621 result = ctrl.server.dockerRun( self.dockerImageTag,
622 ctrl.name,
623 options=self.dockerOptions )
624 return result
625
Jon Hall3c0114c2020-08-11 15:07:42 -0700626 def startAtomixDocker( self, installParallel=True ):
627 """
628 Description:
629 Installing atomix via docker containers.
630 Required:
631 * installParallel - True for installing atomix in parallel.
632 Returns:
633 Returns main.TRUE if it successfully installed
634 """
635 result = main.TRUE
636 threads = []
637 for ctrl in self.atomixNodes:
638 if installParallel:
639 t = main.Thread( target=ctrl.server.dockerRun,
640 name="atomix-run-docker-" + ctrl.name,
641 args=[ self.atomixImageTag, "atomix-" + ctrl.name ],
642 kwargs={ "options" : main.params['CLUSTER']['atomixOptions'],
643 "imageArgs": " --config /opt/atomix/conf/atomix.json --ignore-resources"} )
644 threads.append( t )
645 t.start()
646 else:
647 result = result and \
648 ctrl.server.dockerRun( self.atomixImageTag,
649 "atomix-" + ctrl.name,
650 options=main.params['CLUSTER']['atomixOptions'] )
651 if installParallel:
652 for t in threads:
653 t.join()
654 result = result and t.result
655 return result
656
657 def stopAtomixDocker( self, killMax=True, installParallel=True ):
658 """
659 Description:
660 Stoping all atomix containers
661 Required:
662 * killMax - True for stoping max number of nodes
663 False for stoping current running nodes only.
664 Returns:
665 Returns main.TRUE if it successfully stoped
666 """
667 result = main.TRUE
668 threads = []
669 for ctrl in self.controllers if killMax else self.atomixNodes:
670 if installParallel:
671 t = main.Thread( target=ctrl.server.dockerStop,
672 name="atomix-stop-docker-" + ctrl.name,
673 args=[ "atomix-" + ctrl.name ] )
674 threads.append( t )
675 t.start()
676 else:
677 result = result and \
678 ctrl.server.dockerStop( "atomix-" + ctrl.name )
679 if installParallel:
680 for t in threads:
681 t.join()
682 result = result and t.result
683 return result
684
685 def genPartitions( self, path="/tmp/cluster.json" ):
686 """
687 Description:
688 Create cluster config and move to each onos server
689 Required:
690 * installMax - True for installing max number of nodes
691 False for installing current running nodes only.
692 Returns:
693 Returns main.TRUE if it successfully installed
694 """
695 result = main.TRUE
696 # move files to onos servers
697 for ctrl in self.atomixNodes:
698 localAtomixFile = ctrl.ip_address + "-atomix.json"
699 result = result and main.ONOSbench.generateAtomixConfig( ctrl.server.ip_address, path=localAtomixFile )
700 result = result and main.ONOSbench.scp( ctrl.server,
701 localAtomixFile,
702 "/tmp/atomix.json",
703 direction="to" )
704 for ctrl in self.controllers:
705 localOnosFile = ctrl.ip_address + "-cluster.json"
706 result = result and main.ONOSbench.generateOnosConfig( ctrl.server.ip_address, path=localOnosFile )
707 result = result and main.ONOSbench.scp( ctrl.server,
708 localOnosFile,
709 path,
710 direction="to" )
711 return result
712
Jon Hallca319892017-06-15 15:25:22 -0700713 def startCLIs( self ):
714 """
Devin Lim142b5342017-07-20 15:22:39 -0700715 Description:
716 starting Onos using onosCli driver
717 Required:
718 Returns:
719 Returns main.TRUE if it successfully started.
Jon Hallca319892017-06-15 15:25:22 -0700720 """
Jon Hall3e6edb32018-08-21 16:20:30 -0700721 getFrom = "running"
Devin Lim40a19092017-08-15 14:54:22 -0700722 result = main.TRUE
723 cliResults = self.command( "startOnosCli",
724 args=[ "ipAddress" ],
Jon Hall9b0de1f2020-08-24 15:38:04 -0700725 kwargs= { "karafTimeout": "karafTimeout" },
Devin Lim40a19092017-08-15 14:54:22 -0700726 specificDriver=2,
Jon Hall3e6edb32018-08-21 16:20:30 -0700727 getFrom=getFrom,
Devin Lim40a19092017-08-15 14:54:22 -0700728 funcFromCtrl=True )
Jon Hall3e6edb32018-08-21 16:20:30 -0700729 ctrlList = self.fromNode( getFrom )
Jon Hall4173b242017-09-12 17:04:38 -0700730 for i in range( len( cliResults ) ):
Devin Lim40a19092017-08-15 14:54:22 -0700731 result = result and cliResults[ i ]
Jon Hall3e6edb32018-08-21 16:20:30 -0700732 ctrlList[ i ].active = True
Devin Lim40a19092017-08-15 14:54:22 -0700733 return result
Jon Hallca319892017-06-15 15:25:22 -0700734
Devin Lim3ebd5e72017-11-14 10:38:00 -0800735 def nodesCheck( self ):
You Wang0d9f2c02018-08-10 14:56:32 -0700736 """
737 Description:
738 Checking if all the onos nodes are in READY state
739 Required:
740 Returns:
741 Returns True if it successfully checked
742 """
Devin Lim3ebd5e72017-11-14 10:38:00 -0800743 results = True
Jon Hall06fd0df2021-01-25 15:50:06 -0800744 self.command( "getAddress", specificDriver=2 )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800745 nodesOutput = self.command( "nodes", specificDriver=2 )
746 ips = sorted( self.getIps( activeOnly=True ) )
747 for i in nodesOutput:
748 try:
749 current = json.loads( i )
750 activeIps = []
751 currentResult = False
752 for node in current:
753 if node[ 'state' ] == 'READY':
754 activeIps.append( node[ 'ip' ] )
755 activeIps.sort()
756 if ips == activeIps:
757 currentResult = True
Jon Hall3e6edb32018-08-21 16:20:30 -0700758 else:
Jon Hall627b1572020-12-01 12:01:15 -0800759 main.log.warn( "Expected {} != found {}".format( ips, activeIps ) )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800760 except ( ValueError, TypeError ):
761 main.log.error( "Error parsing nodes output" )
762 main.log.warn( repr( i ) )
763 currentResult = False
764 results = results and currentResult
Jon Hall3c0114c2020-08-11 15:07:42 -0700765 # Check to make sure all bundles are started
766 bundleOutput = self.command( "sendline", args=[ "bundle:list" ] )
767 for i in bundleOutput:
768 if "START LEVEL 100" in i:
769 currentResult = True
770 else:
771 currentResult = False
772 main.log.warn( "Node's bundles not fully started" )
773 main.log.debug( i )
774 results = results and currentResult
Devin Lim3ebd5e72017-11-14 10:38:00 -0800775 return results
776
You Wang0d9f2c02018-08-10 14:56:32 -0700777 def appsCheck( self, apps ):
778 """
779 Description:
780 Checking if all the applications are activated
781 Required:
782 apps: list of applications that are expected to be activated
783 Returns:
784 Returns True if it successfully checked
785 """
786 results = True
787 for app in apps:
788 states = self.command( "appStatus",
789 args=[ app ],
790 specificDriver=2 )
791 for i in range( len( states ) ):
792 ctrl = self.controllers[ i ]
793 if states[ i ] == "ACTIVE":
794 results = results and True
795 main.log.info( "{}: {} is activated".format( ctrl.name, app ) )
796 else:
797 results = False
798 main.log.warn( "{}: {} is in {} state".format( ctrl.name, app, states[ i ] ) )
799 return results
800
Jon Hall3c0114c2020-08-11 15:07:42 -0700801 def attachToONOSDocker( self ):
802 """
803 Description:
804 connect to onos docker using onosCli driver
805 Required:
806 Returns:
807 Returns main.TRUE if it successfully started.
808 """
809 getFrom = "running"
810 result = main.TRUE
811 execResults = self.command( "dockerExec",
812 args=[ "name" ],
813 kwargs={ "dockerPrompt": "dockerPrompt" },
814 specificDriver=2,
815 getFrom=getFrom,
816 funcFromCtrl=True )
817 ctrlList = self.fromNode( getFrom )
818 for i in range( len( execResults ) ):
819 result = result and execResults[ i ]
820 ctrlList[ i ].active = True
821 return result
822
823 def prepareForCLI( self ):
824 """
825 Description:
826 prepare docker to connect to the onos cli
827 Required:
828 Returns:
829 Returns main.TRUE if it successfully started.
830 """
831 getFrom = "running"
832 for ctrl in self.getRunningNodes():
833 ctrl.CLI.inDocker = True
834 result = main.TRUE
835 execResults = self.command( "prepareForCLI",
836 specificDriver=2,
837 getFrom=getFrom,
838 funcFromCtrl=True )
839 ctrlList = self.fromNode( getFrom )
840 for i in range( len( execResults ) ):
841 result = result and execResults[ i ]
842 ctrlList[ i ].active = True
843 return result
844
Devin Lim142b5342017-07-20 15:22:39 -0700845 def printResult( self, results, activeList, logLevel="debug" ):
846 """
847 Description:
848 Print the value of the list.
849 Required:
850 * results - list of the result
851 * activeList - list of the acitve nodes.
852 * logLevel - Type of log level you want it to be printed.
853 Returns:
854 """
855 f = getattr( main.log, logLevel )
Jon Hall4173b242017-09-12 17:04:38 -0700856 for i in range( len( results ) ):
857 f( activeList[ i ].name + "'s result : " + str( results[ i ] ) )
Devin Lim142b5342017-07-20 15:22:39 -0700858
859 def allTrueResultCheck( self, results, activeList ):
860 """
861 Description:
862 check if all the result has main.TRUE.
863 Required:
864 * results - list of the result
865 * activeList - list of the acitve nodes.
866 Returns:
867 Returns True if all == main.TRUE else
868 returns False
869 """
870 self.printResult( results, activeList )
871 return all( result == main.TRUE for result in results )
872
873 def notEmptyResultCheck( self, results, activeList ):
874 """
875 Description:
876 check if all the result has any contents
877 Required:
878 * results - list of the result
879 * activeList - list of the acitve nodes.
880 Returns:
881 Returns True if all the results has
882 something else returns False
883 """
884 self.printResult( results, activeList )
885 return all( result for result in results )
886
887 def identicalResultsCheck( self, results, activeList ):
888 """
889 Description:
890 check if all the results has same output.
891 Required:
892 * results - list of the result
893 * activeList - list of the acitve nodes.
894 Returns:
895 Returns True if all the results has
896 same result else returns False
897 """
898 self.printResult( results, activeList )
899 resultOne = results[ 0 ]
900 return all( resultOne == result for result in results )
901
Devin Lime9f0ccf2017-08-11 17:25:12 -0700902 def command( self, function, args=(), kwargs={}, returnBool=False,
Jon Hall3e6edb32018-08-21 16:20:30 -0700903 specificDriver=0, contentCheck=False, getFrom="active",
Devin Lim40a19092017-08-15 14:54:22 -0700904 funcFromCtrl=False ):
Devin Lim142b5342017-07-20 15:22:39 -0700905 """
906 Description:
907 execute some function of the active nodes.
908 Required:
909 * function - name of the function
910 * args - argument of the function
911 * kwargs - kwargs of the funciton
912 * returnBool - True if wish to check all the result has main.TRUE
913 * specificDriver - specific driver to execute the function. Since
914 some of the function can be used in different drivers, it is important
915 to specify which driver it will be executed from.
916 0 - any type of driver
917 1 - from bench
918 2 - from cli
919 3 - from rest
Jon Hall3c0114c2020-08-11 15:07:42 -0700920 4 - from server
Devin Lim142b5342017-07-20 15:22:39 -0700921 * contentCheck - If this is True, it will check if the result has some
922 contents.
Devin Lime9f0ccf2017-08-11 17:25:12 -0700923 * getFrom - from which nodes
Jon Hall3e6edb32018-08-21 16:20:30 -0700924 2 or "active" - active nodes
925 1 or "running" - current running nodes
926 0 or "all" - all nodes
Devin Lim40a19092017-08-15 14:54:22 -0700927 * funcFromCtrl - specific function of the args/kwargs
928 from each controller from the list of the controllers
Devin Lim142b5342017-07-20 15:22:39 -0700929 Returns:
930 Returns results if not returnBool and not contentCheck
931 Returns checkTruthValue of the result if returnBool
932 Returns resultContent of the result if contentCheck
933 """
Jon Hallca319892017-06-15 15:25:22 -0700934 threads = []
Jon Hall3c0114c2020-08-11 15:07:42 -0700935 drivers = [ None, "Bench", "CLI", "REST", "server" ]
Jon Hallca319892017-06-15 15:25:22 -0700936 results = []
Jon Hall3e6edb32018-08-21 16:20:30 -0700937 for ctrl in self.fromNode( getFrom ):
Jon Hall3c0114c2020-08-11 15:07:42 -0700938 funcArgs = []
939 funcKwargs = {}
Devin Lim142b5342017-07-20 15:22:39 -0700940 try:
941 f = getattr( ( ctrl if not specificDriver else
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700942 getattr( ctrl, drivers[ specificDriver ] ) ), function )
Devin Lim142b5342017-07-20 15:22:39 -0700943 except AttributeError:
944 main.log.error( "Function " + function + " not found. Exiting the Test." )
Devin Lim44075962017-08-11 10:56:37 -0700945 main.cleanAndExit()
Jon Hall3c0114c2020-08-11 15:07:42 -0700946 if funcFromCtrl:
947 if args:
948 try:
949 for i in range( len( args ) ):
950 funcArgs.append( getattr( ctrl, args[ i ] ) )
951 except AttributeError:
952 main.log.error( "Argument " + str( args[ i ] ) + " for " + str( f ) + " not found. Exiting the Test." )
953 main.cleanAndExit()
954 if kwargs:
955 try:
956 for k in kwargs:
957 funcKwargs.update( { k: getattr( ctrl, kwargs[ k ] ) } )
958 except AttributeError as e:
959 main.log.exception("")
960 main.log.error( "Keyword Argument " + str( k ) + " for " + str( f ) + " not found. Exiting the Test." )
961 main.log.debug( "Passed kwargs: %s; dir(ctrl): %s" % ( repr( kwargs ), dir( ctrl ) ) )
962 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700963 t = main.Thread( target=f,
964 name=function + "-" + ctrl.name,
Devin Lim40a19092017-08-15 14:54:22 -0700965 args=funcArgs if funcFromCtrl else args,
966 kwargs=funcKwargs if funcFromCtrl else kwargs )
Jon Hallca319892017-06-15 15:25:22 -0700967 threads.append( t )
968 t.start()
969
970 for t in threads:
971 t.join()
972 results.append( t.result )
Devin Lim142b5342017-07-20 15:22:39 -0700973 if returnBool:
Jon Hall3e6edb32018-08-21 16:20:30 -0700974 return self.allTrueResultCheck( results, self.fromNode( getFrom ) )
Devin Lim142b5342017-07-20 15:22:39 -0700975 elif contentCheck:
Jon Hall3e6edb32018-08-21 16:20:30 -0700976 return self.notEmptyResultCheck( results, self.fromNode( getFrom ) )
Jon Hall4173b242017-09-12 17:04:38 -0700977 return results
978
979 def checkPartitionSize( self, segmentSize='64', units='M', multiplier='3' ):
980 # max segment size in bytes: 1024 * 1024 * 64
981 # multiplier is somewhat arbitrary, but the idea is the logs would have
982 # been compacted before this many segments are written
983
Jon Hall43060f62020-06-23 13:13:33 -0700984 try:
985 maxSize = float( segmentSize ) * float( multiplier )
986 ret = True
987 for n in self.runningNodes:
988 # Partition logs
989 ret = ret and n.server.folderSize( "/opt/atomix/data/raft/partitions/*/*.log",
990 size=maxSize, unit=units, ignoreRoot=False )
991 return ret
992 except Exception as e:
993 main.log.error( e )
994 main.log.error( repr( e ) )