blob: e2fd28d5b23a0058c18a7a93c7b9f8367734a6d2 [file] [log] [blame]
Jon Hallca319892017-06-15 15:25:22 -07001#!/usr/bin/env python
2"""
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00003Copyright 2017 Open Networking Foundation (ONF)
Jon Hallca319892017-06-15 15:25:22 -07004
5Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
6the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
7or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
8
9 TestON is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000012 (at your option) any later version.
Jon Hallca319892017-06-15 15:25:22 -070013
14 TestON is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with TestON. If not, see <http://www.gnu.org/licenses/>.
21
22
23This driver is used to interact with an ONOS cluster. It should
24handle creating the necessary components to interact with each specific ONOS nodes.
25
26Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
27the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
28or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
29
30"""
Jon Halla4a79312022-01-25 17:16:53 -080031from distutils.util import strtobool
Jon Hallca319892017-06-15 15:25:22 -070032import pexpect
33import os
34from drivers.common.clidriver import CLI
35
36# FIXME: Move this to it's own file?
37class Controller():
Jeremy Ronquillo82705492017-10-18 14:19:55 -070038
Jon Hallca319892017-06-15 15:25:22 -070039 def __str__( self ):
40 return self.name
Jeremy Ronquillo82705492017-10-18 14:19:55 -070041
Jon Hallca319892017-06-15 15:25:22 -070042 def __repr__( self ):
Jeremy Ronquillo82705492017-10-18 14:19:55 -070043 # TODO use repr() for components?
Jon Hallca319892017-06-15 15:25:22 -070044 return "%s<IP=%s, CLI=%s, REST=%s, Bench=%s >" % ( self.name,
Jon Hall4173b242017-09-12 17:04:38 -070045 self.ipAddress,
46 self.CLI,
47 self.REST,
48 self.Bench )
Jon Hallca319892017-06-15 15:25:22 -070049
50 def __getattr__( self, name ):
51 """
52 Called when an attribute lookup has not found the attribute
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000053 in the usual places (i.e. it is not an instance attribute nor
54 is it found in the class tree for self). name is the attribute
55 name. This method should return the (computed) attribute value
Jon Hallca319892017-06-15 15:25:22 -070056 or raise an AttributeError exception.
57
Daniele Moroc9b4afe2021-08-26 18:07:01 +020058 We will look into each of the node's component handles to try to find the attribute, looking at REST first
Jon Hallca319892017-06-15 15:25:22 -070059 """
60 if hasattr( self.REST, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070061 main.log.debug( "%s: Using Rest driver's attribute for '%s'" % ( self.name, name ) )
62 return getattr( self.REST, name )
Jon Hallca319892017-06-15 15:25:22 -070063 if hasattr( self.CLI, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070064 main.log.debug( "%s: Using CLI driver's attribute for '%s'" % ( self.name, name ) )
65 return getattr( self.CLI, name )
Jon Hallca319892017-06-15 15:25:22 -070066 if hasattr( self.Bench, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070067 main.log.debug( "%s: Using Bench driver's attribute for '%s'" % ( self.name, name ) )
68 return getattr( self.Bench, name )
Daniele Moroc9b4afe2021-08-26 18:07:01 +020069 if hasattr( self.p4rtUp4, name ):
70 main.log.debug( "%s: Using UP4 driver's attribute for '%s'" % ( self.name, name ) )
71 return getattr( self.p4rtUp4, name )
Jon Halla4a79312022-01-25 17:16:53 -080072 if hasattr( self.mock_smf, name ):
73 main.log.debug( "%s: Using mock smf driver's attribute for '%s'" % ( self.name, name ) )
74 return getattr( self.mock_smf, name )
Devin Lim142b5342017-07-20 15:22:39 -070075 raise AttributeError( "Could not find the attribute %s in %r or it's component handles" % ( name, self ) )
Jon Hallca319892017-06-15 15:25:22 -070076
Jon Hall3c0114c2020-08-11 15:07:42 -070077 def __init__( self, name, ipAddress, CLI=None, REST=None, Bench=None, pos=None,
Jon Halla4a79312022-01-25 17:16:53 -080078 userName=None, server=None, k8s=None, p4rtUp4=None, mock_smf=None, dockerPrompt=None ):
Jeremy Ronquillo82705492017-10-18 14:19:55 -070079 # TODO: validate these arguments
Jon Hallca319892017-06-15 15:25:22 -070080 self.name = str( name )
81 self.ipAddress = ipAddress
82 self.CLI = CLI
83 self.REST = REST
84 self.Bench = Bench
85 self.active = False
Devin Lim142b5342017-07-20 15:22:39 -070086 self.pos = pos
87 self.ip_address = ipAddress
88 self.user_name = userName
Jon Hall4173b242017-09-12 17:04:38 -070089 self.server = server
Jon Hall06fd0df2021-01-25 15:50:06 -080090 self.k8s = k8s
Daniele Moroc9b4afe2021-08-26 18:07:01 +020091 self.p4rtUp4 = p4rtUp4
Jon Halla4a79312022-01-25 17:16:53 -080092 self.mock_smf = mock_smf
Jon Hall3c0114c2020-08-11 15:07:42 -070093 self.dockerPrompt = dockerPrompt
Jon Hallca319892017-06-15 15:25:22 -070094
95class OnosClusterDriver( CLI ):
96
97 def __init__( self ):
98 """
99 Initialize client
100 """
101 self.name = None
102 self.home = None
103 self.handle = None
Jon Hall3c0114c2020-08-11 15:07:42 -0700104 self.useDocker = False
105 self.dockerPrompt = None
Jon Halle37bd1f2020-09-10 12:16:41 -0700106 self.maxNodes = None
Siddesh52750622021-03-05 19:52:03 +0000107 self.karafPromptPass = None
Jon Hall06fd0df2021-01-25 15:50:06 -0800108 self.kubeConfig = None
Siddesh52750622021-03-05 19:52:03 +0000109 self.karafPromptUser = None
Jon Hall3a03cad2021-04-07 11:21:55 -0700110 self.nodeUser = None
111 self.nodePass = None
Jon Hallca319892017-06-15 15:25:22 -0700112 self.nodes = []
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200113 self.up4Port = None
Jon Halla4a79312022-01-25 17:16:53 -0800114 self.mock_smf = None
Jon Hallca319892017-06-15 15:25:22 -0700115 super( OnosClusterDriver, self ).__init__()
116
Jon Hallca319892017-06-15 15:25:22 -0700117 def connect( self, **connectargs ):
118 """
119 Creates ssh handle for ONOS "bench".
120 NOTE:
121 The ip_address would come from the topo file using the host tag, the
122 value can be an environment variable as well as a "localhost" to get
123 the ip address needed to ssh to the "bench"
124 """
125 try:
126 for key in connectargs:
127 vars( self )[ key ] = connectargs[ key ]
128 self.home = "~/onos"
129 for key in self.options:
130 if key == "home":
Jon Halle37bd1f2020-09-10 12:16:41 -0700131 self.home = self.options[ key ]
Jon Hallca319892017-06-15 15:25:22 -0700132 elif key == "karaf_username":
133 self.karafUser = self.options[ key ]
134 elif key == "karaf_password":
135 self.karafPass = self.options[ key ]
Siddesh52750622021-03-05 19:52:03 +0000136 elif key == "node_username":
137 self.nodeUser = self.options[ key ]
138 elif key == "node_password":
139 self.nodePass = self.options[ key ]
140 elif key == "karafPrompt_username":
141 self.karafPromptUser = self.options[ key ]
142 elif key == "karafPrompt_password":
143 self.karafPromptPass = self.options[ key ]
Jon Hallca319892017-06-15 15:25:22 -0700144 elif key == "cluster_name":
145 prefix = self.options[ key ]
Jon Hall3c0114c2020-08-11 15:07:42 -0700146 elif key == "useDocker":
147 self.useDocker = "True" == self.options[ key ]
148 elif key == "docker_prompt":
149 self.dockerPrompt = self.options[ key ]
Jon Hall9b0de1f2020-08-24 15:38:04 -0700150 elif key == "web_user":
151 self.webUser = self.options[ key ]
152 elif key == "web_pass":
153 self.webPass = self.options[ key ]
Jon Halle37bd1f2020-09-10 12:16:41 -0700154 elif key == "nodes":
155 # Maximum number of ONOS nodes to run, if there is any
156 self.maxNodes = self.options[ key ]
Jon Hall06fd0df2021-01-25 15:50:06 -0800157 elif key == "kubeConfig":
158 self.kubeConfig = self.options[ key ]
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200159 elif key == "up4_port":
160 # Defining up4_port triggers the creation of the P4RuntimeCliDriver component
161 self.up4Port = self.options[ key ]
Jon Halla4a79312022-01-25 17:16:53 -0800162 elif key == "mock_smf":
163 self.mock_smf = strtobool( self.options[ key ] )
Jon Hallca319892017-06-15 15:25:22 -0700164
Jon Hall0e240372018-05-02 11:21:57 -0700165 self.home = self.checkOptions( self.home, "~/onos" )
166 self.karafUser = self.checkOptions( self.karafUser, self.user_name )
167 self.karafPass = self.checkOptions( self.karafPass, self.pwd )
Siddesh52750622021-03-05 19:52:03 +0000168 self.nodeUser = self.checkOptions( self.nodeUser, self.user_name )
169 self.nodePass = self.checkOptions( self.nodePass, self.pwd )
170 self.karafPromptUser = self.checkOptions( self.karafPromptUser, self.user_name )
171 self.karafPromptPass = self.checkOptions( self.karafPromptPass, self.pwd )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700172 self.webUser = self.checkOptions( self.webUser, "onos" )
173 self.webPass = self.checkOptions( self.webPass, "rocks" )
Jon Hallca319892017-06-15 15:25:22 -0700174 prefix = self.checkOptions( prefix, "ONOS" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700175 self.useDocker = self.checkOptions( self.useDocker, False )
176 self.dockerPrompt = self.checkOptions( self.dockerPrompt, "~/onos#" )
Jon Halle37bd1f2020-09-10 12:16:41 -0700177 self.maxNodes = int( self.checkOptions( self.maxNodes, 100 ) )
Jon Hall06fd0df2021-01-25 15:50:06 -0800178 self.kubeConfig = self.checkOptions( self.kubeConfig, None )
Jon Halla16b4db2021-10-20 14:11:59 -0700179 self.up4Port = self.checkOptions( self.up4Port, None )
Jon Halla4a79312022-01-25 17:16:53 -0800180 self.mock_smf = self.checkOptions( self.mock_smf, None )
Jon Hallca319892017-06-15 15:25:22 -0700181
182 self.name = self.options[ 'name' ]
183
Jon Hallca319892017-06-15 15:25:22 -0700184
Jon Hall06fd0df2021-01-25 15:50:06 -0800185 if not self.kubeConfig:
186 # Grabs all OC environment variables based on max number of nodes
187 # TODO: Also support giving an ip range as a compononet option
188 self.onosIps = {} # Dictionary of all possible ONOS ip
189
190 try:
191 if self.maxNodes:
192 for i in range( self.maxNodes ):
193 envString = "OC" + str( i + 1 )
194 # If there is no more OC# then break the loop
195 if os.getenv( envString ):
196 self.onosIps[ envString ] = os.getenv( envString )
197 else:
198 self.maxNodes = len( self.onosIps )
199 main.log.info( self.name +
200 ": Created cluster data with " +
201 str( self.maxNodes ) +
202 " maximum number" +
203 " of nodes" )
204 break
205
206 if not self.onosIps:
207 main.log.info( "Could not read any environment variable"
208 + " please load a cell file with all" +
209 " onos IP" )
210 self.maxNodes = None
Jon Hallca319892017-06-15 15:25:22 -0700211 else:
Jon Hall06fd0df2021-01-25 15:50:06 -0800212 main.log.info( self.name + ": Found " +
213 str( self.onosIps.values() ) +
214 " ONOS IPs" )
215 except KeyError:
216 main.log.info( "Invalid environment variable" )
217 except Exception as inst:
218 main.log.error( "Uncaught exception: " + str( inst ) )
Jon Hallca319892017-06-15 15:25:22 -0700219 try:
220 if os.getenv( str( self.ip_address ) ) is not None:
221 self.ip_address = os.getenv( str( self.ip_address ) )
222 else:
223 main.log.info( self.name +
224 ": Trying to connect to " +
225 self.ip_address )
226 except KeyError:
227 main.log.info( "Invalid host name," +
228 " connecting to local host instead" )
229 self.ip_address = 'localhost'
230 except Exception as inst:
231 main.log.error( "Uncaught exception: " + str( inst ) )
232
233 self.handle = super( OnosClusterDriver, self ).connect(
234 user_name=self.user_name,
235 ip_address=self.ip_address,
236 port=self.port,
237 pwd=self.pwd,
238 home=self.home )
239
240 if self.handle:
241 self.handle.sendline( "cd " + self.home )
242 self.handle.expect( "\$" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800243 if self.kubeConfig:
244 # Try to get # of onos nodes using given kubernetes configuration
245 names = self.kubectlGetPodNames( self.kubeConfig,
246 main.params[ 'kubernetes' ][ 'namespace' ],
247 main.params[ 'kubernetes' ][ 'appName' ] )
248 self.podNames = names
249 self.onosIps = {} # Dictionary of all possible ONOS ip
250 for i in range( 1, len( names ) + 1 ):
251 self.onosIps[ 'OC%i' % i ] = self.ip_address
252 self.maxNodes = len( names )
Jon Hallca319892017-06-15 15:25:22 -0700253 self.createComponents( prefix=prefix )
Jon Hall06fd0df2021-01-25 15:50:06 -0800254 if self.kubeConfig:
255 # Create Port Forwarding sessions for each controller
256 for node in self.nodes:
257 kubectl = node.k8s
258 index = self.nodes.index( node )
259 # Store each pod name in the k8s component
260 kubectl.podName = self.podNames[ index ]
261 # Setup port-forwarding and save the local port
262 guiPort = 8181
263 cliPort = 8101
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200264 fwdPorts = [ guiPort, cliPort ]
265 if self.up4Port:
266 fwdPorts.append( int( self.up4Port ) )
Jon Hall06fd0df2021-01-25 15:50:06 -0800267 portsList = ""
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200268 for port in fwdPorts:
Jon Hall06fd0df2021-01-25 15:50:06 -0800269 localPort = port + index + 1
270 portsList += "%s:%s " % ( localPort, port )
271 if port == cliPort:
272 node.CLI.karafPort = localPort
Jon Hall50a00012021-03-08 11:06:11 -0800273 elif port == guiPort:
274 node.REST.port = localPort
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200275 elif self.up4Port and port == int( self.up4Port ):
276 node.p4rtUp4.p4rtPort = localPort
Jon Halla8cf76a2021-10-05 14:31:47 -0700277 # Set kubeconfig for all components
Jon Halla4a79312022-01-25 17:16:53 -0800278 for shell in [ node.CLI, node.Bench, node.k8s, node.p4rtUp4, node.mock_smf ]:
Jon Halla8cf76a2021-10-05 14:31:47 -0700279 if shell:
280 shell.setEnv( "KUBECONFIG", value=kubectl.kubeConfig )
Jon Hall06fd0df2021-01-25 15:50:06 -0800281 main.log.info( "Setting up port forward for pod %s: [ %s ]" % ( self.podNames[ index ], portsList ) )
282 pf = kubectl.kubectlPortForward( self.podNames[ index ],
283 portsList,
284 kubectl.kubeConfig,
285 main.params[ 'kubernetes' ][ 'namespace' ] )
286 if not pf:
287 main.log.error( "Failed to create port forwarding" )
288 return main.FALSE
Jon Hallca319892017-06-15 15:25:22 -0700289 return self.handle
290 else:
291 main.log.info( "Failed to create ONOS handle" )
292 return main.FALSE
293 except pexpect.EOF:
294 main.log.error( self.name + ": EOF exception found" )
295 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700296 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700297 except Exception:
298 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700299 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700300
301 def disconnect( self ):
302 """
303 Called when Test is complete to disconnect the ONOS handle.
304 """
305 response = main.TRUE
306 try:
307 if self.handle:
308 self.handle.sendline( "" )
309 self.handle.expect( "\$" )
310 self.handle.sendline( "exit" )
311 self.handle.expect( "closed" )
312 except pexpect.EOF:
313 main.log.error( self.name + ": EOF exception found" )
314 main.log.error( self.name + ": " + self.handle.before )
315 except ValueError:
316 main.log.exception( "Exception in disconnect of " + self.name )
317 response = main.TRUE
318 except Exception:
319 main.log.exception( self.name + ": Connection failed to the host" )
320 response = main.FALSE
321 return response
322
Devin Lim142b5342017-07-20 15:22:39 -0700323 def setCliOptions( self, name, host ):
Jon Hallca319892017-06-15 15:25:22 -0700324 """
325 Parse the cluster options to create an ONOS cli component with the given name
326 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000327 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
Devin Lim142b5342017-07-20 15:22:39 -0700328 clihost = main.componentDictionary[ name ][ 'COMPONENTS' ].get( "diff_clihost", "" )
329 if clihost == "True":
330 main.componentDictionary[ name ][ 'host' ] = host
Jon Hall06fd0df2021-01-25 15:50:06 -0800331 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
332 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000333 main.componentDictionary[name]['type'] = "OnosCliDriver"
Siddesh52750622021-03-05 19:52:03 +0000334 main.componentDictionary[name]['COMPONENTS']['karafPromptUser'] = self.karafPromptUser
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000335 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700336
Devin Lim142b5342017-07-20 15:22:39 -0700337 def createCliComponent( self, name, host ):
Jon Hallca319892017-06-15 15:25:22 -0700338 """
339 Creates a new onos cli component.
340
341 Arguments:
342 name - The string of the name of this component. The new component
343 will be assigned to main.<name> .
344 In addition, main.<name>.name = str( name )
345 """
346 try:
347 # look to see if this component already exists
348 getattr( main, name )
349 except AttributeError:
350 # namespace is clear, creating component
Devin Lim142b5342017-07-20 15:22:39 -0700351 self.setCliOptions( name, host )
Jon Hallca319892017-06-15 15:25:22 -0700352 return main.componentInit( name )
353 except pexpect.EOF:
354 main.log.error( self.name + ": EOF exception found" )
355 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700356 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700357 except Exception:
358 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700359 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700360 else:
361 # namespace is not clear!
362 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700363 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700364
365 def setRestOptions( self, name, host ):
366 """
367 Parse the cluster options to create an ONOS cli component with the given name
368 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000369 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000370 user = main.componentDictionary[name]['COMPONENTS'].get( "web_user", "onos" )
371 main.componentDictionary[name]['user'] = self.checkOptions( user, "onos" )
372 password = main.componentDictionary[name]['COMPONENTS'].get( "web_pass", "rocks" )
You Wangbef7ea12018-09-21 13:15:12 -0700373 main.componentDictionary[name]['password'] = self.checkOptions( password, "rocks" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000374 main.componentDictionary[name]['host'] = host
375 port = main.componentDictionary[name]['COMPONENTS'].get( "rest_port", "8181" )
376 main.componentDictionary[name]['port'] = self.checkOptions( port, "8181" )
377 main.componentDictionary[name]['type'] = "OnosRestDriver"
378 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700379
380 def createRestComponent( self, name, ipAddress ):
381 """
382 Creates a new onos rest component.
383
384 Arguments:
385 name - The string of the name of this component. The new component
386 will be assigned to main.<name> .
387 In addition, main.<name>.name = str( name )
388 """
389 try:
390 # look to see if this component already exists
391 getattr( main, name )
392 except AttributeError:
393 # namespace is clear, creating component
394 self.setRestOptions( name, ipAddress )
395 return main.componentInit( name )
396 except pexpect.EOF:
397 main.log.error( self.name + ": EOF exception found" )
398 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700399 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700400 except Exception:
401 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700402 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700403 else:
404 # namespace is not clear!
405 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700406 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700407
408 def setBenchOptions( self, name ):
409 """
410 Parse the cluster options to create an ONOS "bench" component with the given name
411 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000412 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
413 main.componentDictionary[name]['type'] = "OnosDriver"
414 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
415 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
416 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700417
418 def createBenchComponent( self, name ):
419 """
420 Creates a new onos "bench" component.
421
422 Arguments:
423 name - The string of the name of this component. The new component
424 will be assigned to main.<name> .
425 In addition, main.<name>.name = str( name )
426 """
427 try:
428 # look to see if this component already exists
429 getattr( main, name )
430 except AttributeError:
431 # namespace is clear, creating component
432 self.setBenchOptions( name )
433 return main.componentInit( name )
434 except pexpect.EOF:
435 main.log.error( self.name + ": EOF exception found" )
436 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700437 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700438 except Exception:
439 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700440 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700441 else:
442 # namespace is not clear!
443 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700444 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700445
Jon Hall4173b242017-09-12 17:04:38 -0700446 def setServerOptions( self, name, ipAddress ):
447 """
448 Parse the cluster options to create an ONOS "server" component with the given name
449
450 Arguments:
451 name - The name of the server componet
452 ipAddress - The ip address of the server
453 """
454 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
455 main.componentDictionary[name]['type'] = "OnosDriver"
456 main.componentDictionary[name]['host'] = ipAddress
457 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
458 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
You Wang4cc61912018-08-28 10:10:58 -0700459 # TODO: for now we use karaf user name and password also for logging to the onos nodes
Jon Hall06fd0df2021-01-25 15:50:06 -0800460 # FIXME: We shouldn't use karaf* for this, what we want is another set of variables to
461 # login to a shell on the server ONOS is running on
Siddesh52750622021-03-05 19:52:03 +0000462 main.componentDictionary[name]['user'] = self.nodeUser
463 main.componentDictionary[name]['password'] = self.nodePass
Jon Hall4173b242017-09-12 17:04:38 -0700464 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hall4173b242017-09-12 17:04:38 -0700465
Jon Hall4173b242017-09-12 17:04:38 -0700466 def createServerComponent( self, name, ipAddress ):
467 """
468 Creates a new onos "server" component. This will be connected to the
469 node ONOS is running on.
470
471 Arguments:
472 name - The string of the name of this component. The new component
473 will be assigned to main.<name> .
474 In addition, main.<name>.name = str( name )
475 ipAddress - The ip address of the server
476 """
477 try:
478 # look to see if this component already exists
479 getattr( main, name )
480 except AttributeError:
481 # namespace is clear, creating component
482 self.setServerOptions( name, ipAddress )
483 return main.componentInit( name )
484 except pexpect.EOF:
485 main.log.error( self.name + ": EOF exception found" )
486 main.log.error( self.name + ": " + self.handle.before )
487 main.cleanAndExit()
488 except Exception:
489 main.log.exception( self.name + ": Uncaught exception!" )
490 main.cleanAndExit()
491 else:
492 # namespace is not clear!
493 main.log.error( name + " component already exists!" )
494 main.cleanAndExit()
495
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200496 def setP4rtCLIOptions( self, name, ipAddress ):
497 """
498 Parse the cluster options to create an UP4 component with the given name
499
500 Arguments:
501 name - The name of the P4RuntimeCLI component
502 ipAddress - The ip address of the ONOS instance
503 """
504 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
505 main.componentDictionary[name]['type'] = "P4RuntimeCliDriver"
506 main.componentDictionary[name]['host'] = ipAddress
507 port = main.componentDictionary[name]['COMPONENTS'].get( "p4rt_port", "9559" )
508 main.componentDictionary[name]['p4rt_port'] = self.checkOptions( port, "9559" )
509 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
510
511 def createP4rtCLIComponent( self, name, ipAddress ):
512 """
513 Creates a new P4Runtime CLI component. This will be connected to the node
514 ONOS is running on.
515
516 Arguments:
517 name - The string of the name of this component. The new component
518 will be assigned to main.<name> .
519 In addition, main.<name>.name = str( name )
520 ipAddress - The ip address of the server
521 """
522 try:
523 # look to see if this component already exists
524 getattr( main, name )
525 except AttributeError:
526 # namespace is clear, creating component
527 self.setP4rtCLIOptions( name, ipAddress )
528 return main.componentInit( name )
529 except pexpect.EOF:
530 main.log.error( self.name + ": EOF exception found" )
531 main.log.error( self.name + ": " + self.handle.before )
532 main.cleanAndExit()
533 except Exception:
534 main.log.exception( self.name + ": Uncaught exception!" )
535 main.cleanAndExit()
536 else:
537 # namespace is not clear!
538 main.log.error( name + " component already exists!" )
539 main.cleanAndExit()
540
Jon Halla4a79312022-01-25 17:16:53 -0800541 def setMockSMFOptions( self, name, ipAddress ):
542 """
543 Parse the cluster options to create a mock smf component with the given name
544
545 Arguments:
546 name - The name of the P4RuntimeCLI component
547 ipAddress - The ip address of the ONOS instance
548 """
549 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
550 main.componentDictionary[name]['type'] = "MockSMFDriver"
551 main.componentDictionary[name]['host'] = ipAddress
552 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
553
554 def createMockSMFComponent( self, name, ipAddress ):
555 """
556 Creates a new mock smf component. This will be connected to the node
557 ONOS is running on.
558
559 Arguments:
560 name - The string of the name of this component. The new component
561 will be assigned to main.<name> .
562 In addition, main.<name>.name = str( name )
563 ipAddress - The ip address of the server
564 """
565 try:
566 # look to see if this component already exists
567 getattr( main, name )
568 except AttributeError:
569 # namespace is clear, creating component
570 self.setMockSMFOptions( name, ipAddress )
571 return main.componentInit( name )
572 except pexpect.EOF:
573 main.log.error( self.name + ": EOF exception found" )
574 main.log.error( self.name + ": " + self.handle.before )
575 main.cleanAndExit()
576 except Exception:
577 main.log.exception( self.name + ": Uncaught exception!" )
578 main.cleanAndExit()
579 else:
580 # namespace is not clear!
581 main.log.error( name + " component already exists!" )
582 main.cleanAndExit()
583
Jon Hall4173b242017-09-12 17:04:38 -0700584 def createComponents( self, prefix='', createServer=True ):
Jon Hallca319892017-06-15 15:25:22 -0700585 """
586 Creates a CLI and REST component for each nodes in the cluster
587 """
588 # TODO: This needs work to support starting two seperate clusters in one test
589 cliPrefix = prefix + "cli"
590 restPrefix = prefix + "rest"
591 benchPrefix = prefix + "bench"
Jon Hall4173b242017-09-12 17:04:38 -0700592 serverPrefix = prefix + "server"
Jon Hall06fd0df2021-01-25 15:50:06 -0800593 k8sPrefix = prefix + "k8s"
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200594 up4Prefix = prefix + "up4cl"
Jon Halla4a79312022-01-25 17:16:53 -0800595 smfPrefix = prefix + "smf"
Jon Hallca319892017-06-15 15:25:22 -0700596 for i in xrange( 1, self.maxNodes + 1 ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000597 cliName = cliPrefix + str( i )
Jon Hallca319892017-06-15 15:25:22 -0700598 restName = restPrefix + str( i )
599 benchName = benchPrefix + str( i )
Jon Hall4173b242017-09-12 17:04:38 -0700600 serverName = serverPrefix + str( i )
Jon Hall06fd0df2021-01-25 15:50:06 -0800601 if self.kubeConfig:
602 k8sName = k8sPrefix + str( i )
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200603 if self.up4Port:
604 up4Name = up4Prefix + str( i )
Jon Halla4a79312022-01-25 17:16:53 -0800605 if self.mock_smf:
606 smfName = smfPrefix + str( i )
Jon Hallca319892017-06-15 15:25:22 -0700607
608 # Unfortunately this means we need to have a cell set beofre running TestON,
609 # Even if it is just the entire possible cluster size
610 ip = self.onosIps[ 'OC' + str( i ) ]
611
Devin Lim142b5342017-07-20 15:22:39 -0700612 cli = self.createCliComponent( cliName, ip )
Jon Hallca319892017-06-15 15:25:22 -0700613 rest = self.createRestComponent( restName, ip )
614 bench = self.createBenchComponent( benchName )
Jon Hall4173b242017-09-12 17:04:38 -0700615 server = self.createServerComponent( serverName, ip ) if createServer else None
Jon Hall06fd0df2021-01-25 15:50:06 -0800616 k8s = self.createServerComponent( k8sName, ip ) if self.kubeConfig else None
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200617 p4rtUp4 = self.createP4rtCLIComponent( up4Name, ip ) if self.up4Port else None
Jon Halla4a79312022-01-25 17:16:53 -0800618 smf = self.createMockSMFComponent( smfName, ip ) if self.mock_smf else None
619 self.mock_smf = smf
Jon Hall06fd0df2021-01-25 15:50:06 -0800620 if self.kubeConfig:
621 k8s.kubeConfig = self.kubeConfig
622 k8s.podName = None
Jon Hall3c0114c2020-08-11 15:07:42 -0700623 self.nodes.append( Controller( prefix + str( i ), ip, cli, rest, bench, i - 1,
Jon Hall06fd0df2021-01-25 15:50:06 -0800624 self.user_name, server=server, k8s=k8s,
Jon Halla4a79312022-01-25 17:16:53 -0800625 p4rtUp4=p4rtUp4, mock_smf=smf, dockerPrompt=self.dockerPrompt ) )