blob: d096d1bfd72b6de76b3203009434c8bb1fdb7807 [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"""
31import pexpect
32import os
33from drivers.common.clidriver import CLI
34
35# FIXME: Move this to it's own file?
36class Controller():
Jeremy Ronquillo82705492017-10-18 14:19:55 -070037
Jon Hallca319892017-06-15 15:25:22 -070038 def __str__( self ):
39 return self.name
Jeremy Ronquillo82705492017-10-18 14:19:55 -070040
Jon Hallca319892017-06-15 15:25:22 -070041 def __repr__( self ):
Jeremy Ronquillo82705492017-10-18 14:19:55 -070042 # TODO use repr() for components?
Jon Hallca319892017-06-15 15:25:22 -070043 return "%s<IP=%s, CLI=%s, REST=%s, Bench=%s >" % ( self.name,
Jon Hall4173b242017-09-12 17:04:38 -070044 self.ipAddress,
45 self.CLI,
46 self.REST,
47 self.Bench )
Jon Hallca319892017-06-15 15:25:22 -070048
49 def __getattr__( self, name ):
50 """
51 Called when an attribute lookup has not found the attribute
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000052 in the usual places (i.e. it is not an instance attribute nor
53 is it found in the class tree for self). name is the attribute
54 name. This method should return the (computed) attribute value
Jon Hallca319892017-06-15 15:25:22 -070055 or raise an AttributeError exception.
56
Daniele Moroc9b4afe2021-08-26 18:07:01 +020057 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 -070058 """
59 if hasattr( self.REST, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070060 main.log.debug( "%s: Using Rest driver's attribute for '%s'" % ( self.name, name ) )
61 return getattr( self.REST, name )
Jon Hallca319892017-06-15 15:25:22 -070062 if hasattr( self.CLI, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070063 main.log.debug( "%s: Using CLI driver's attribute for '%s'" % ( self.name, name ) )
64 return getattr( self.CLI, name )
Jon Hallca319892017-06-15 15:25:22 -070065 if hasattr( self.Bench, name ):
Jon Hall3c0114c2020-08-11 15:07:42 -070066 main.log.debug( "%s: Using Bench driver's attribute for '%s'" % ( self.name, name ) )
67 return getattr( self.Bench, name )
Daniele Moroc9b4afe2021-08-26 18:07:01 +020068 if hasattr( self.p4rtUp4, name ):
69 main.log.debug( "%s: Using UP4 driver's attribute for '%s'" % ( self.name, name ) )
70 return getattr( self.p4rtUp4, name )
Devin Lim142b5342017-07-20 15:22:39 -070071 raise AttributeError( "Could not find the attribute %s in %r or it's component handles" % ( name, self ) )
Jon Hallca319892017-06-15 15:25:22 -070072
Jon Hall3c0114c2020-08-11 15:07:42 -070073 def __init__( self, name, ipAddress, CLI=None, REST=None, Bench=None, pos=None,
Daniele Moroc9b4afe2021-08-26 18:07:01 +020074 userName=None, server=None, k8s=None, p4rtUp4=None, dockerPrompt=None ):
Jeremy Ronquillo82705492017-10-18 14:19:55 -070075 # TODO: validate these arguments
Jon Hallca319892017-06-15 15:25:22 -070076 self.name = str( name )
77 self.ipAddress = ipAddress
78 self.CLI = CLI
79 self.REST = REST
80 self.Bench = Bench
81 self.active = False
Devin Lim142b5342017-07-20 15:22:39 -070082 self.pos = pos
83 self.ip_address = ipAddress
84 self.user_name = userName
Jon Hall4173b242017-09-12 17:04:38 -070085 self.server = server
Jon Hall06fd0df2021-01-25 15:50:06 -080086 self.k8s = k8s
Daniele Moroc9b4afe2021-08-26 18:07:01 +020087 self.p4rtUp4 = p4rtUp4
Jon Hall3c0114c2020-08-11 15:07:42 -070088 self.dockerPrompt = dockerPrompt
Jon Hallca319892017-06-15 15:25:22 -070089
90class OnosClusterDriver( CLI ):
91
92 def __init__( self ):
93 """
94 Initialize client
95 """
96 self.name = None
97 self.home = None
98 self.handle = None
Jon Hall3c0114c2020-08-11 15:07:42 -070099 self.useDocker = False
100 self.dockerPrompt = None
Jon Halle37bd1f2020-09-10 12:16:41 -0700101 self.maxNodes = None
Siddesh52750622021-03-05 19:52:03 +0000102 self.karafPromptPass = None
Jon Hall06fd0df2021-01-25 15:50:06 -0800103 self.kubeConfig = None
Siddesh52750622021-03-05 19:52:03 +0000104 self.karafPromptUser = None
Jon Hall3a03cad2021-04-07 11:21:55 -0700105 self.nodeUser = None
106 self.nodePass = None
Jon Hallca319892017-06-15 15:25:22 -0700107 self.nodes = []
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200108 self.up4Port = None
Jon Hallca319892017-06-15 15:25:22 -0700109 super( OnosClusterDriver, self ).__init__()
110
Jon Hallca319892017-06-15 15:25:22 -0700111 def connect( self, **connectargs ):
112 """
113 Creates ssh handle for ONOS "bench".
114 NOTE:
115 The ip_address would come from the topo file using the host tag, the
116 value can be an environment variable as well as a "localhost" to get
117 the ip address needed to ssh to the "bench"
118 """
119 try:
120 for key in connectargs:
121 vars( self )[ key ] = connectargs[ key ]
122 self.home = "~/onos"
123 for key in self.options:
124 if key == "home":
Jon Halle37bd1f2020-09-10 12:16:41 -0700125 self.home = self.options[ key ]
Jon Hallca319892017-06-15 15:25:22 -0700126 elif key == "karaf_username":
127 self.karafUser = self.options[ key ]
128 elif key == "karaf_password":
129 self.karafPass = self.options[ key ]
Siddesh52750622021-03-05 19:52:03 +0000130 elif key == "node_username":
131 self.nodeUser = self.options[ key ]
132 elif key == "node_password":
133 self.nodePass = self.options[ key ]
134 elif key == "karafPrompt_username":
135 self.karafPromptUser = self.options[ key ]
136 elif key == "karafPrompt_password":
137 self.karafPromptPass = self.options[ key ]
Jon Hallca319892017-06-15 15:25:22 -0700138 elif key == "cluster_name":
139 prefix = self.options[ key ]
Jon Hall3c0114c2020-08-11 15:07:42 -0700140 elif key == "useDocker":
141 self.useDocker = "True" == self.options[ key ]
142 elif key == "docker_prompt":
143 self.dockerPrompt = self.options[ key ]
Jon Hall9b0de1f2020-08-24 15:38:04 -0700144 elif key == "web_user":
145 self.webUser = self.options[ key ]
146 elif key == "web_pass":
147 self.webPass = self.options[ key ]
Jon Halle37bd1f2020-09-10 12:16:41 -0700148 elif key == "nodes":
149 # Maximum number of ONOS nodes to run, if there is any
150 self.maxNodes = self.options[ key ]
Jon Hall06fd0df2021-01-25 15:50:06 -0800151 elif key == "kubeConfig":
152 self.kubeConfig = self.options[ key ]
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200153 elif key == "up4_port":
154 # Defining up4_port triggers the creation of the P4RuntimeCliDriver component
155 self.up4Port = self.options[ key ]
Jon Hallca319892017-06-15 15:25:22 -0700156
Jon Hall0e240372018-05-02 11:21:57 -0700157 self.home = self.checkOptions( self.home, "~/onos" )
158 self.karafUser = self.checkOptions( self.karafUser, self.user_name )
159 self.karafPass = self.checkOptions( self.karafPass, self.pwd )
Siddesh52750622021-03-05 19:52:03 +0000160 self.nodeUser = self.checkOptions( self.nodeUser, self.user_name )
161 self.nodePass = self.checkOptions( self.nodePass, self.pwd )
162 self.karafPromptUser = self.checkOptions( self.karafPromptUser, self.user_name )
163 self.karafPromptPass = self.checkOptions( self.karafPromptPass, self.pwd )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700164 self.webUser = self.checkOptions( self.webUser, "onos" )
165 self.webPass = self.checkOptions( self.webPass, "rocks" )
Jon Hallca319892017-06-15 15:25:22 -0700166 prefix = self.checkOptions( prefix, "ONOS" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700167 self.useDocker = self.checkOptions( self.useDocker, False )
168 self.dockerPrompt = self.checkOptions( self.dockerPrompt, "~/onos#" )
Jon Halle37bd1f2020-09-10 12:16:41 -0700169 self.maxNodes = int( self.checkOptions( self.maxNodes, 100 ) )
Jon Hall06fd0df2021-01-25 15:50:06 -0800170 self.kubeConfig = self.checkOptions( self.kubeConfig, None )
Jon Halla16b4db2021-10-20 14:11:59 -0700171 self.up4Port = self.checkOptions( self.up4Port, None )
Jon Hallca319892017-06-15 15:25:22 -0700172
173 self.name = self.options[ 'name' ]
174
Jon Hallca319892017-06-15 15:25:22 -0700175
Jon Hall06fd0df2021-01-25 15:50:06 -0800176 if not self.kubeConfig:
177 # Grabs all OC environment variables based on max number of nodes
178 # TODO: Also support giving an ip range as a compononet option
179 self.onosIps = {} # Dictionary of all possible ONOS ip
180
181 try:
182 if self.maxNodes:
183 for i in range( self.maxNodes ):
184 envString = "OC" + str( i + 1 )
185 # If there is no more OC# then break the loop
186 if os.getenv( envString ):
187 self.onosIps[ envString ] = os.getenv( envString )
188 else:
189 self.maxNodes = len( self.onosIps )
190 main.log.info( self.name +
191 ": Created cluster data with " +
192 str( self.maxNodes ) +
193 " maximum number" +
194 " of nodes" )
195 break
196
197 if not self.onosIps:
198 main.log.info( "Could not read any environment variable"
199 + " please load a cell file with all" +
200 " onos IP" )
201 self.maxNodes = None
Jon Hallca319892017-06-15 15:25:22 -0700202 else:
Jon Hall06fd0df2021-01-25 15:50:06 -0800203 main.log.info( self.name + ": Found " +
204 str( self.onosIps.values() ) +
205 " ONOS IPs" )
206 except KeyError:
207 main.log.info( "Invalid environment variable" )
208 except Exception as inst:
209 main.log.error( "Uncaught exception: " + str( inst ) )
Jon Hallca319892017-06-15 15:25:22 -0700210 try:
211 if os.getenv( str( self.ip_address ) ) is not None:
212 self.ip_address = os.getenv( str( self.ip_address ) )
213 else:
214 main.log.info( self.name +
215 ": Trying to connect to " +
216 self.ip_address )
217 except KeyError:
218 main.log.info( "Invalid host name," +
219 " connecting to local host instead" )
220 self.ip_address = 'localhost'
221 except Exception as inst:
222 main.log.error( "Uncaught exception: " + str( inst ) )
223
224 self.handle = super( OnosClusterDriver, self ).connect(
225 user_name=self.user_name,
226 ip_address=self.ip_address,
227 port=self.port,
228 pwd=self.pwd,
229 home=self.home )
230
231 if self.handle:
232 self.handle.sendline( "cd " + self.home )
233 self.handle.expect( "\$" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800234 if self.kubeConfig:
235 # Try to get # of onos nodes using given kubernetes configuration
236 names = self.kubectlGetPodNames( self.kubeConfig,
237 main.params[ 'kubernetes' ][ 'namespace' ],
238 main.params[ 'kubernetes' ][ 'appName' ] )
239 self.podNames = names
240 self.onosIps = {} # Dictionary of all possible ONOS ip
241 for i in range( 1, len( names ) + 1 ):
242 self.onosIps[ 'OC%i' % i ] = self.ip_address
243 self.maxNodes = len( names )
Jon Hallca319892017-06-15 15:25:22 -0700244 self.createComponents( prefix=prefix )
Jon Hall06fd0df2021-01-25 15:50:06 -0800245 if self.kubeConfig:
246 # Create Port Forwarding sessions for each controller
247 for node in self.nodes:
248 kubectl = node.k8s
249 index = self.nodes.index( node )
250 # Store each pod name in the k8s component
251 kubectl.podName = self.podNames[ index ]
252 # Setup port-forwarding and save the local port
253 guiPort = 8181
254 cliPort = 8101
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200255 fwdPorts = [ guiPort, cliPort ]
256 if self.up4Port:
257 fwdPorts.append( int( self.up4Port ) )
Jon Hall06fd0df2021-01-25 15:50:06 -0800258 portsList = ""
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200259 for port in fwdPorts:
Jon Hall06fd0df2021-01-25 15:50:06 -0800260 localPort = port + index + 1
261 portsList += "%s:%s " % ( localPort, port )
262 if port == cliPort:
263 node.CLI.karafPort = localPort
Jon Hall50a00012021-03-08 11:06:11 -0800264 elif port == guiPort:
265 node.REST.port = localPort
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200266 elif self.up4Port and port == int( self.up4Port ):
267 node.p4rtUp4.p4rtPort = localPort
Jon Halla8cf76a2021-10-05 14:31:47 -0700268 # Set kubeconfig for all components
269 for shell in [ node.CLI, node.Bench, node.k8s, node.p4rtUp4 ]:
270 if shell:
271 shell.setEnv( "KUBECONFIG", value=kubectl.kubeConfig )
Jon Hall06fd0df2021-01-25 15:50:06 -0800272 main.log.info( "Setting up port forward for pod %s: [ %s ]" % ( self.podNames[ index ], portsList ) )
273 pf = kubectl.kubectlPortForward( self.podNames[ index ],
274 portsList,
275 kubectl.kubeConfig,
276 main.params[ 'kubernetes' ][ 'namespace' ] )
277 if not pf:
278 main.log.error( "Failed to create port forwarding" )
279 return main.FALSE
Jon Hallca319892017-06-15 15:25:22 -0700280 return self.handle
281 else:
282 main.log.info( "Failed to create ONOS handle" )
283 return main.FALSE
284 except pexpect.EOF:
285 main.log.error( self.name + ": EOF exception found" )
286 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700287 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700288 except Exception:
289 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700290 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700291
292 def disconnect( self ):
293 """
294 Called when Test is complete to disconnect the ONOS handle.
295 """
296 response = main.TRUE
297 try:
298 if self.handle:
299 self.handle.sendline( "" )
300 self.handle.expect( "\$" )
301 self.handle.sendline( "exit" )
302 self.handle.expect( "closed" )
303 except pexpect.EOF:
304 main.log.error( self.name + ": EOF exception found" )
305 main.log.error( self.name + ": " + self.handle.before )
306 except ValueError:
307 main.log.exception( "Exception in disconnect of " + self.name )
308 response = main.TRUE
309 except Exception:
310 main.log.exception( self.name + ": Connection failed to the host" )
311 response = main.FALSE
312 return response
313
Devin Lim142b5342017-07-20 15:22:39 -0700314 def setCliOptions( self, name, host ):
Jon Hallca319892017-06-15 15:25:22 -0700315 """
316 Parse the cluster options to create an ONOS cli component with the given name
317 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000318 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
Devin Lim142b5342017-07-20 15:22:39 -0700319 clihost = main.componentDictionary[ name ][ 'COMPONENTS' ].get( "diff_clihost", "" )
320 if clihost == "True":
321 main.componentDictionary[ name ][ 'host' ] = host
Jon Hall06fd0df2021-01-25 15:50:06 -0800322 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
323 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000324 main.componentDictionary[name]['type'] = "OnosCliDriver"
Siddesh52750622021-03-05 19:52:03 +0000325 main.componentDictionary[name]['COMPONENTS']['karafPromptUser'] = self.karafPromptUser
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000326 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700327
Devin Lim142b5342017-07-20 15:22:39 -0700328 def createCliComponent( self, name, host ):
Jon Hallca319892017-06-15 15:25:22 -0700329 """
330 Creates a new onos cli component.
331
332 Arguments:
333 name - The string of the name of this component. The new component
334 will be assigned to main.<name> .
335 In addition, main.<name>.name = str( name )
336 """
337 try:
338 # look to see if this component already exists
339 getattr( main, name )
340 except AttributeError:
341 # namespace is clear, creating component
Devin Lim142b5342017-07-20 15:22:39 -0700342 self.setCliOptions( name, host )
Jon Hallca319892017-06-15 15:25:22 -0700343 return main.componentInit( name )
344 except pexpect.EOF:
345 main.log.error( self.name + ": EOF exception found" )
346 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700347 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700348 except Exception:
349 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700350 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700351 else:
352 # namespace is not clear!
353 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700354 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700355
356 def setRestOptions( self, name, host ):
357 """
358 Parse the cluster options to create an ONOS cli component with the given name
359 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000360 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000361 user = main.componentDictionary[name]['COMPONENTS'].get( "web_user", "onos" )
362 main.componentDictionary[name]['user'] = self.checkOptions( user, "onos" )
363 password = main.componentDictionary[name]['COMPONENTS'].get( "web_pass", "rocks" )
You Wangbef7ea12018-09-21 13:15:12 -0700364 main.componentDictionary[name]['password'] = self.checkOptions( password, "rocks" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000365 main.componentDictionary[name]['host'] = host
366 port = main.componentDictionary[name]['COMPONENTS'].get( "rest_port", "8181" )
367 main.componentDictionary[name]['port'] = self.checkOptions( port, "8181" )
368 main.componentDictionary[name]['type'] = "OnosRestDriver"
369 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700370
371 def createRestComponent( self, name, ipAddress ):
372 """
373 Creates a new onos rest component.
374
375 Arguments:
376 name - The string of the name of this component. The new component
377 will be assigned to main.<name> .
378 In addition, main.<name>.name = str( name )
379 """
380 try:
381 # look to see if this component already exists
382 getattr( main, name )
383 except AttributeError:
384 # namespace is clear, creating component
385 self.setRestOptions( name, ipAddress )
386 return main.componentInit( name )
387 except pexpect.EOF:
388 main.log.error( self.name + ": EOF exception found" )
389 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700390 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700391 except Exception:
392 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700393 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700394 else:
395 # namespace is not clear!
396 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700397 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700398
399 def setBenchOptions( self, name ):
400 """
401 Parse the cluster options to create an ONOS "bench" component with the given name
402 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000403 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
404 main.componentDictionary[name]['type'] = "OnosDriver"
405 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
406 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
407 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hallca319892017-06-15 15:25:22 -0700408
409 def createBenchComponent( self, name ):
410 """
411 Creates a new onos "bench" component.
412
413 Arguments:
414 name - The string of the name of this component. The new component
415 will be assigned to main.<name> .
416 In addition, main.<name>.name = str( name )
417 """
418 try:
419 # look to see if this component already exists
420 getattr( main, name )
421 except AttributeError:
422 # namespace is clear, creating component
423 self.setBenchOptions( name )
424 return main.componentInit( name )
425 except pexpect.EOF:
426 main.log.error( self.name + ": EOF exception found" )
427 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700428 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700429 except Exception:
430 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700431 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700432 else:
433 # namespace is not clear!
434 main.log.error( name + " component already exists!" )
Devin Lim44075962017-08-11 10:56:37 -0700435 main.cleanAndExit()
Jon Hallca319892017-06-15 15:25:22 -0700436
Jon Hall4173b242017-09-12 17:04:38 -0700437 def setServerOptions( self, name, ipAddress ):
438 """
439 Parse the cluster options to create an ONOS "server" component with the given name
440
441 Arguments:
442 name - The name of the server componet
443 ipAddress - The ip address of the server
444 """
445 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
446 main.componentDictionary[name]['type'] = "OnosDriver"
447 main.componentDictionary[name]['host'] = ipAddress
448 home = main.componentDictionary[name]['COMPONENTS'].get( "onos_home", None )
449 main.componentDictionary[name]['home'] = self.checkOptions( home, None )
You Wang4cc61912018-08-28 10:10:58 -0700450 # TODO: for now we use karaf user name and password also for logging to the onos nodes
Jon Hall06fd0df2021-01-25 15:50:06 -0800451 # FIXME: We shouldn't use karaf* for this, what we want is another set of variables to
452 # login to a shell on the server ONOS is running on
Siddesh52750622021-03-05 19:52:03 +0000453 main.componentDictionary[name]['user'] = self.nodeUser
454 main.componentDictionary[name]['password'] = self.nodePass
Jon Hall4173b242017-09-12 17:04:38 -0700455 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
Jon Hall4173b242017-09-12 17:04:38 -0700456
Jon Hall4173b242017-09-12 17:04:38 -0700457 def createServerComponent( self, name, ipAddress ):
458 """
459 Creates a new onos "server" component. This will be connected to the
460 node ONOS is running on.
461
462 Arguments:
463 name - The string of the name of this component. The new component
464 will be assigned to main.<name> .
465 In addition, main.<name>.name = str( name )
466 ipAddress - The ip address of the server
467 """
468 try:
469 # look to see if this component already exists
470 getattr( main, name )
471 except AttributeError:
472 # namespace is clear, creating component
473 self.setServerOptions( name, ipAddress )
474 return main.componentInit( name )
475 except pexpect.EOF:
476 main.log.error( self.name + ": EOF exception found" )
477 main.log.error( self.name + ": " + self.handle.before )
478 main.cleanAndExit()
479 except Exception:
480 main.log.exception( self.name + ": Uncaught exception!" )
481 main.cleanAndExit()
482 else:
483 # namespace is not clear!
484 main.log.error( name + " component already exists!" )
485 main.cleanAndExit()
486
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200487 def setP4rtCLIOptions( self, name, ipAddress ):
488 """
489 Parse the cluster options to create an UP4 component with the given name
490
491 Arguments:
492 name - The name of the P4RuntimeCLI component
493 ipAddress - The ip address of the ONOS instance
494 """
495 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
496 main.componentDictionary[name]['type'] = "P4RuntimeCliDriver"
497 main.componentDictionary[name]['host'] = ipAddress
498 port = main.componentDictionary[name]['COMPONENTS'].get( "p4rt_port", "9559" )
499 main.componentDictionary[name]['p4rt_port'] = self.checkOptions( port, "9559" )
500 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
501
502 def createP4rtCLIComponent( self, name, ipAddress ):
503 """
504 Creates a new P4Runtime CLI component. This will be connected to the node
505 ONOS is running on.
506
507 Arguments:
508 name - The string of the name of this component. The new component
509 will be assigned to main.<name> .
510 In addition, main.<name>.name = str( name )
511 ipAddress - The ip address of the server
512 """
513 try:
514 # look to see if this component already exists
515 getattr( main, name )
516 except AttributeError:
517 # namespace is clear, creating component
518 self.setP4rtCLIOptions( name, ipAddress )
519 return main.componentInit( name )
520 except pexpect.EOF:
521 main.log.error( self.name + ": EOF exception found" )
522 main.log.error( self.name + ": " + self.handle.before )
523 main.cleanAndExit()
524 except Exception:
525 main.log.exception( self.name + ": Uncaught exception!" )
526 main.cleanAndExit()
527 else:
528 # namespace is not clear!
529 main.log.error( name + " component already exists!" )
530 main.cleanAndExit()
531
Jon Hall4173b242017-09-12 17:04:38 -0700532 def createComponents( self, prefix='', createServer=True ):
Jon Hallca319892017-06-15 15:25:22 -0700533 """
534 Creates a CLI and REST component for each nodes in the cluster
535 """
536 # TODO: This needs work to support starting two seperate clusters in one test
537 cliPrefix = prefix + "cli"
538 restPrefix = prefix + "rest"
539 benchPrefix = prefix + "bench"
Jon Hall4173b242017-09-12 17:04:38 -0700540 serverPrefix = prefix + "server"
Jon Hall06fd0df2021-01-25 15:50:06 -0800541 k8sPrefix = prefix + "k8s"
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200542 up4Prefix = prefix + "up4cl"
Jon Hallca319892017-06-15 15:25:22 -0700543 for i in xrange( 1, self.maxNodes + 1 ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000544 cliName = cliPrefix + str( i )
Jon Hallca319892017-06-15 15:25:22 -0700545 restName = restPrefix + str( i )
546 benchName = benchPrefix + str( i )
Jon Hall4173b242017-09-12 17:04:38 -0700547 serverName = serverPrefix + str( i )
Jon Hall06fd0df2021-01-25 15:50:06 -0800548 if self.kubeConfig:
549 k8sName = k8sPrefix + str( i )
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200550 if self.up4Port:
551 up4Name = up4Prefix + str( i )
Jon Hallca319892017-06-15 15:25:22 -0700552
553 # Unfortunately this means we need to have a cell set beofre running TestON,
554 # Even if it is just the entire possible cluster size
555 ip = self.onosIps[ 'OC' + str( i ) ]
556
Devin Lim142b5342017-07-20 15:22:39 -0700557 cli = self.createCliComponent( cliName, ip )
Jon Hallca319892017-06-15 15:25:22 -0700558 rest = self.createRestComponent( restName, ip )
559 bench = self.createBenchComponent( benchName )
Jon Hall4173b242017-09-12 17:04:38 -0700560 server = self.createServerComponent( serverName, ip ) if createServer else None
Jon Hall06fd0df2021-01-25 15:50:06 -0800561 k8s = self.createServerComponent( k8sName, ip ) if self.kubeConfig else None
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200562 p4rtUp4 = self.createP4rtCLIComponent( up4Name, ip ) if self.up4Port else None
Jon Hall06fd0df2021-01-25 15:50:06 -0800563 if self.kubeConfig:
564 k8s.kubeConfig = self.kubeConfig
565 k8s.podName = None
Jon Hall3c0114c2020-08-11 15:07:42 -0700566 self.nodes.append( Controller( prefix + str( i ), ip, cli, rest, bench, i - 1,
Jon Hall06fd0df2021-01-25 15:50:06 -0800567 self.user_name, server=server, k8s=k8s,
Daniele Moroc9b4afe2021-08-26 18:07:01 +0200568 p4rtUp4=p4rtUp4, dockerPrompt=self.dockerPrompt ) )