blob: ac909eef9ccf35ca8759f2111ffd7a833a61198e [file] [log] [blame]
Pier6a0c4de2018-03-18 16:01:30 -07001#!/usr/bin/env python
2"""
3Copyright 2018 Open Networking Foundation (ONF)
4
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
9TestON is free software: you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation, either version 2 of the License, or
12( at your option ) any later version.
13
14TestON is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with TestON. If not, see <http://www.gnu.org/licenses/>.
21"""
22
23import pexpect
24import re
25import json
26import types
27import time
28import os
29from drivers.common.clidriver import CLI
30from core import utilities
31from shutil import copyfile
32
33class OFDPASwitchDriver( CLI ):
34
35 def __init__( self ):
36 """
37 Initialize client
38 """
39 super( CLI, self ).__init__()
40 self.name = None
41 self.handle = None
42 self.prompt = "~#"
43 # Respect to bin folder
44 self.home = "../drivers/common/cli/ofdpa/"
45 # Local home for functions using scp
46 self.tempDirectory = "/tmp/"
47 self.conf = "ofagent.conf"
48 self.switchDirectory = "/etc/ofagent/"
49
50 def connect( self, **connectargs ):
51 """
52 Creates ssh handle for Accton cli.
53 """
54 try:
55 # Parse keys in xml object
56 for key in connectargs:
57 vars( self )[ key ] = connectargs[ key ]
58 # Get the name
You Wang4cc61912018-08-28 10:10:58 -070059 self.name = self.options[ 'name' ]
Pier6a0c4de2018-03-18 16:01:30 -070060 # Get the dpid
61 self.dpid = self.options[ 'dpid' ]
You Wang4cc61912018-08-28 10:10:58 -070062 # Get ofagent patch
63 if 'confDir' in self.options:
64 self.switchDirectory = self.options[ 'confDir' ]
Pier6a0c4de2018-03-18 16:01:30 -070065 # Parse the IP address
66 try:
67 if os.getenv( str( self.ip_address ) ) is not None:
68 self.ip_address = os.getenv( str( self.ip_address ) )
69 # Otherwise is an ip address
70 else:
71 main.log.info( self.name + ": Trying to connect to " + self.ip_address )
72 # Error handling
73 except KeyError:
74 main.log.info( "Invalid host name," + " connecting to local host instead" )
75 self.ip_address = 'localhost'
76 except Exception as inst:
77 main.log.error( "Uncaught exception: " + str( inst ) )
78 # Build the handle using the above information
79 self.handle = super(OFDPASwitchDriver, self ).connect(
80 user_name=self.user_name,
81 ip_address=self.ip_address,
82 port=None,
83 pwd=self.pwd)
84 # Successful connection
85 if self.handle:
86 main.log.info( "Connection successful to the host " + self.user_name + "@" + self.ip_address )
87 self.handle.sendline( "" )
88 self.handle.expect( self.prompt )
89 return main.TRUE
90 # Connection failed
91 else:
92 main.log.error( "Connection failed to the host " + self.user_name + "@" + self.ip_address )
93 main.log.error( "Failed to connect to the OFDPA CLI" )
94 return main.FALSE
95 # Error handling
96 except TypeError:
97 main.log.exception( self.name + ": Object not as expected" )
98 return None
99 except pexpect.EOF:
100 main.log.error( self.name + ": EOF exception found" )
101 main.log.error( self.name + ": " + self.handle.before )
102 main.cleanup()
103 main.exit()
104 except Exception:
105 main.log.exception( self.name + ": Uncaught exception!" )
106 main.cleanup()
107 main.exit()
108
109 def disconnect( self ):
110 """
111 Called when Test is complete to disconnect the OFDPASwitchDriver handle.
112 """
113 response = main.TRUE
114 try:
115 if self.handle:
116 # Stop the ofagent
117 self.stopOfAgent()
118 # Disconnect from the device
119 self.handle.sendline( "" )
120 self.handle.expect( self.prompt )
121 self.handle.sendline( "exit" )
122 self.handle.expect( "closed" )
123 # Errors handling
124 except pexpect.TIMEOUT:
125 main.log.error( self.name + ": pexpect.TIMEOUT found" )
126 return main.FALSE
127 except TypeError:
128 main.log.exception( self.name + ": Object not as expected" )
129 response = main.FALSE
130 except pexpect.EOF:
131 main.log.error( self.name + ": EOF exception found" )
132 main.log.error( self.name + ": " + self.handle.before )
133 except ValueError:
134 main.log.exception( "Exception in disconnect of " + self.name )
135 response = main.TRUE
136 except Exception:
137 main.log.exception( self.name + ": Connection failed to the host" )
138 response = main.FALSE
139 return response
140
You Wang4cc61912018-08-28 10:10:58 -0700141 def assignSwController( self, ip, port="6653", ptcp="", updateConf=False ):
Pier6a0c4de2018-03-18 16:01:30 -0700142 """
143 Description:
144 The assignment is realized properly creating the agent.conf
145 for each switch and then pushing it into the device.
146 Required:
147 ip - Ip addresses of controllers. This can be a list or a string.
148 Optional:
149 port - controller port is ignored
150 ptcp - ptcp information is ignored
You Wang4cc61912018-08-28 10:10:58 -0700151 updateConf - create new ofagent conf file and push to the switch if
152 set to True; otherwise will use the existing conf file
153 on the switch.
Pier6a0c4de2018-03-18 16:01:30 -0700154 Return:
155 Returns main.TRUE if the switch is correctly assigned to controllers,
156 otherwise it will return main.FALSE or an appropriate exception(s)
157 """
158 assignResult = main.TRUE
159 # Initial arguments for OFDPA
160 opt_args = 'OPT_ARGS="-d 2 -c 2 -c 4 '
161 onosIp = ""
162 # Parses the controller option
163 try:
164 if isinstance( ip, types.StringType ):
165 onosIp = "-t " + str( ip )
166 elif isinstance( ip, types.ListType ):
167 for ipAddress in ip:
168 onosIp += "-t " + str( ipAddress ) + " "
169 else:
170 main.log.error( self.name + ": Invalid ip address" )
171 return main.FALSE
172 # Complete the arguments adding the dpid
173 opt_args += onosIp + '-i %s' % self.dpid + '"'
You Wang4cc61912018-08-28 10:10:58 -0700174 if updateConf:
175 # Create a copy of the cfg file using the template
176 self.createCfg()
177 # Load the cfg file and adds the missing option
178 self.updateCfg( opt_args )
179 # Backup the cfg on the switch
180 self.backupCfg()
181 # Push the new cfg on the device
182 self.pushCfg()
183 # Start the ofagent on the device
Pier6a0c4de2018-03-18 16:01:30 -0700184 self.startOfAgent()
185 # Enable all the ports
186 assignResult = utilities.retry(
187 self.enablePorts,
188 main.FALSE,
189 kwargs={},
You Wang4cc61912018-08-28 10:10:58 -0700190 attempts=10,
Pier6a0c4de2018-03-18 16:01:30 -0700191 sleep=10)
192 # Done return true
193 return assignResult
194 # Errors handling
195 except pexpect.TIMEOUT:
196 main.log.error( self.name + ": pexpect.TIMEOUT found" )
197 return main.FALSE
198 except pexpect.EOF:
199 main.log.error( self.name + ": EOF exception found" )
200 main.log.error( self.name + ": " + self.handle.before )
201 main.cleanAndExit()
202 except Exception:
203 main.log.exception( self.name + ": Uncaught exception!" )
204 main.cleanAndExit()
205
206 def createCfg( self ):
207 """
208 Create in bench context a new config file starting from the template
209 """
210 copyfile(self.home + self.conf + ".template", self.tempDirectory + self.conf)
211
212 def updateCfg( self, opt_args):
213 """
214 Add the arguments related to the current switch (self)
215 """
216 with open(self.tempDirectory + self.conf, "a") as cfg:
217 cfg.write(opt_args + "\n")
218 cfg.close()
219
220 def backupCfg( self ):
221 """
222 Create a backup file of the old configuration on the switch
223 """
224 self.handle.sendline( "" )
225 self.handle.expect( self.prompt )
226 self.handle.sendline( "cp %s%s %s%s.backup" % (self.switchDirectory, self.conf, self.switchDirectory, self.conf) )
227 self.handle.expect( self.prompt )
228
229 def pushCfg( self ):
230 """
231 Push the new configuration from the network bench
232 """
233 # We use os.system to send the command from TestON cluster
234 # to the switches. This means that passwordless access is
235 # necessary in order to push the configuration file
236 os.system( "scp " + self.tempDirectory + self.conf + " " +
237 self.user_name + "@" + self.ip_address + ":" + self.switchDirectory)
238
239 def startOfAgent( self ):
240 """
241 Start the ofagent on the device
242 """
243 self.handle.sendline( "" )
244 self.handle.expect( self.prompt )
245 self.handle.sendline( "service ofagentd start" )
246 self.handle.expect( self.prompt )
247
248 def stopOfAgent( self ):
249 """
250 Stop the ofagent on the device
251 """
252 self.handle.sendline( "" )
253 self.handle.expect( self.prompt )
254 self.handle.sendline( "service ofagentd stop" )
255 self.handle.expect( self.prompt )
256
257 def dumpFlows( self ):
258 """
259 Dump the flows from the devices
260 FIXME need changes in the workflow in order to be used
261 """
262 try:
263 self.handle.sendline( "" )
264 self.handle.expect( self.prompt )
265 # Create the dump of the flows locally on the switches
266 self.handle.sendline( "client_flowtable_dump" )
267 self.handle.expect( self.prompt )
268 response = self.handle.before
269 # Write back in the tmp folder - needs to be changed in future
270 with open(self.tempDirectory + "flows_%s.txt" % self.dpid, "w") as flows:
271 flows.write(response + "\n")
272 flows.close()
273 # Done return for further processing
274 return response
275 # Errors handling
276 except pexpect.TIMEOUT:
277 main.log.error( self.name + ": pexpect.TIMEOUT found" )
278 return main.FALSE
279 except pexpect.EOF:
280 main.log.error( self.name + ": EOF exception found" )
281 main.log.error( self.name + ": " + self.handle.before )
282 main.cleanAndExit()
283 except Exception:
284 main.log.exception( self.name + ": Uncaught exception!" )
285 main.cleanAndExit()
286
287 def dumpGroups( self ):
288 """
289 Dump the groups from the devices
290 FIXME need changes in the workflow in order to be used
291 """
292 try:
293 self.handle.sendline( "" )
294 self.handle.expect( self.prompt )
295 self.handle.sendline( "client_grouptable_dump > groups.txt" )
296 self.handle.expect( self.prompt )
297 response = self.handle.before
298 # Write back in the tmp folder - needs to be changed in future
299 with open(self.tempDirectory + "groups_%s.txt" % self.dpid, "w") as groups:
300 groups.write(response + "\n")
301 groups.close()
302 # Done return for further processing
303 return response
304 # Errors handling
305 except pexpect.TIMEOUT:
306 main.log.error( self.name + ": pexpect.TIMEOUT found" )
307 return main.FALSE
308 except pexpect.EOF:
309 main.log.error( self.name + ": EOF exception found" )
310 main.log.error( self.name + ": " + self.handle.before )
311 main.cleanAndExit()
312 except Exception:
313 main.log.exception( self.name + ": Uncaught exception!" )
314 main.cleanAndExit()
315
316 def enablePorts( self ):
317 """
318 Enable all the ports on the devices
319 It needs to wait for the boot
320 """
321 self.handle.sendline( "" )
322 self.handle.expect( self.prompt )
323 self.handle.sendline( "client_port_table_dump" )
324 self.handle.expect( self.prompt )
325 response = self.handle.before
326 if "Error from ofdpaClientInitialize()" in response:
You Wang4cc61912018-08-28 10:10:58 -0700327 main.log.warn( self.name + ": Not yet started" )
Pier6a0c4de2018-03-18 16:01:30 -0700328 return main.FALSE
You Wang4cc61912018-08-28 10:10:58 -0700329 # Change port speed
330 self.handle.sendline( "sh portspeed" )
Pier6a0c4de2018-03-18 16:01:30 -0700331 self.handle.expect( self.prompt )
You Wang4cc61912018-08-28 10:10:58 -0700332 response = self.handle.before
333 if "Failure calling" in response:
334 main.log.warn( self.name + ": failed to change port speed" )
335 return main.FALSE
Pier6a0c4de2018-03-18 16:01:30 -0700336 return main.TRUE