blob: b080c9656925b8bdca92d569d3a54d3ca7cb918d [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
59 self.name = self.options['name']
60 # Get the dpid
61 self.dpid = self.options[ 'dpid' ]
62 # Parse the IP address
63 try:
64 if os.getenv( str( self.ip_address ) ) is not None:
65 self.ip_address = os.getenv( str( self.ip_address ) )
66 # Otherwise is an ip address
67 else:
68 main.log.info( self.name + ": Trying to connect to " + self.ip_address )
69 # Error handling
70 except KeyError:
71 main.log.info( "Invalid host name," + " connecting to local host instead" )
72 self.ip_address = 'localhost'
73 except Exception as inst:
74 main.log.error( "Uncaught exception: " + str( inst ) )
75 # Build the handle using the above information
76 self.handle = super(OFDPASwitchDriver, self ).connect(
77 user_name=self.user_name,
78 ip_address=self.ip_address,
79 port=None,
80 pwd=self.pwd)
81 # Successful connection
82 if self.handle:
83 main.log.info( "Connection successful to the host " + self.user_name + "@" + self.ip_address )
84 self.handle.sendline( "" )
85 self.handle.expect( self.prompt )
86 return main.TRUE
87 # Connection failed
88 else:
89 main.log.error( "Connection failed to the host " + self.user_name + "@" + self.ip_address )
90 main.log.error( "Failed to connect to the OFDPA CLI" )
91 return main.FALSE
92 # Error handling
93 except TypeError:
94 main.log.exception( self.name + ": Object not as expected" )
95 return None
96 except pexpect.EOF:
97 main.log.error( self.name + ": EOF exception found" )
98 main.log.error( self.name + ": " + self.handle.before )
99 main.cleanup()
100 main.exit()
101 except Exception:
102 main.log.exception( self.name + ": Uncaught exception!" )
103 main.cleanup()
104 main.exit()
105
106 def disconnect( self ):
107 """
108 Called when Test is complete to disconnect the OFDPASwitchDriver handle.
109 """
110 response = main.TRUE
111 try:
112 if self.handle:
113 # Stop the ofagent
114 self.stopOfAgent()
115 # Disconnect from the device
116 self.handle.sendline( "" )
117 self.handle.expect( self.prompt )
118 self.handle.sendline( "exit" )
119 self.handle.expect( "closed" )
120 # Errors handling
121 except pexpect.TIMEOUT:
122 main.log.error( self.name + ": pexpect.TIMEOUT found" )
123 return main.FALSE
124 except TypeError:
125 main.log.exception( self.name + ": Object not as expected" )
126 response = main.FALSE
127 except pexpect.EOF:
128 main.log.error( self.name + ": EOF exception found" )
129 main.log.error( self.name + ": " + self.handle.before )
130 except ValueError:
131 main.log.exception( "Exception in disconnect of " + self.name )
132 response = main.TRUE
133 except Exception:
134 main.log.exception( self.name + ": Connection failed to the host" )
135 response = main.FALSE
136 return response
137
138 def assignSwController( self, ip, port="6653", ptcp=""):
139 """
140 Description:
141 The assignment is realized properly creating the agent.conf
142 for each switch and then pushing it into the device.
143 Required:
144 ip - Ip addresses of controllers. This can be a list or a string.
145 Optional:
146 port - controller port is ignored
147 ptcp - ptcp information is ignored
148 Return:
149 Returns main.TRUE if the switch is correctly assigned to controllers,
150 otherwise it will return main.FALSE or an appropriate exception(s)
151 """
152 assignResult = main.TRUE
153 # Initial arguments for OFDPA
154 opt_args = 'OPT_ARGS="-d 2 -c 2 -c 4 '
155 onosIp = ""
156 # Parses the controller option
157 try:
158 if isinstance( ip, types.StringType ):
159 onosIp = "-t " + str( ip )
160 elif isinstance( ip, types.ListType ):
161 for ipAddress in ip:
162 onosIp += "-t " + str( ipAddress ) + " "
163 else:
164 main.log.error( self.name + ": Invalid ip address" )
165 return main.FALSE
166 # Complete the arguments adding the dpid
167 opt_args += onosIp + '-i %s' % self.dpid + '"'
168 # Create a copy of the cfg file using the template
169 self.createCfg()
170 # Load the cfg file and adds the missing option
171 self.updateCfg( opt_args )
172 # Backup the cfg on the switch
173 self.backupCfg()
174 # Push the new cfg on the device
175 self.pushCfg()
176 # Start the ofagent on the device
177 self.startOfAgent()
178 # Enable all the ports
179 assignResult = utilities.retry(
180 self.enablePorts,
181 main.FALSE,
182 kwargs={},
183 attempts=5,
184 sleep=10)
185 # Done return true
186 return assignResult
187 # Errors handling
188 except pexpect.TIMEOUT:
189 main.log.error( self.name + ": pexpect.TIMEOUT found" )
190 return main.FALSE
191 except pexpect.EOF:
192 main.log.error( self.name + ": EOF exception found" )
193 main.log.error( self.name + ": " + self.handle.before )
194 main.cleanAndExit()
195 except Exception:
196 main.log.exception( self.name + ": Uncaught exception!" )
197 main.cleanAndExit()
198
199 def createCfg( self ):
200 """
201 Create in bench context a new config file starting from the template
202 """
203 copyfile(self.home + self.conf + ".template", self.tempDirectory + self.conf)
204
205 def updateCfg( self, opt_args):
206 """
207 Add the arguments related to the current switch (self)
208 """
209 with open(self.tempDirectory + self.conf, "a") as cfg:
210 cfg.write(opt_args + "\n")
211 cfg.close()
212
213 def backupCfg( self ):
214 """
215 Create a backup file of the old configuration on the switch
216 """
217 self.handle.sendline( "" )
218 self.handle.expect( self.prompt )
219 self.handle.sendline( "cp %s%s %s%s.backup" % (self.switchDirectory, self.conf, self.switchDirectory, self.conf) )
220 self.handle.expect( self.prompt )
221
222 def pushCfg( self ):
223 """
224 Push the new configuration from the network bench
225 """
226 # We use os.system to send the command from TestON cluster
227 # to the switches. This means that passwordless access is
228 # necessary in order to push the configuration file
229 os.system( "scp " + self.tempDirectory + self.conf + " " +
230 self.user_name + "@" + self.ip_address + ":" + self.switchDirectory)
231
232 def startOfAgent( self ):
233 """
234 Start the ofagent on the device
235 """
236 self.handle.sendline( "" )
237 self.handle.expect( self.prompt )
238 self.handle.sendline( "service ofagentd start" )
239 self.handle.expect( self.prompt )
240
241 def stopOfAgent( self ):
242 """
243 Stop the ofagent on the device
244 """
245 self.handle.sendline( "" )
246 self.handle.expect( self.prompt )
247 self.handle.sendline( "service ofagentd stop" )
248 self.handle.expect( self.prompt )
249
250 def dumpFlows( self ):
251 """
252 Dump the flows from the devices
253 FIXME need changes in the workflow in order to be used
254 """
255 try:
256 self.handle.sendline( "" )
257 self.handle.expect( self.prompt )
258 # Create the dump of the flows locally on the switches
259 self.handle.sendline( "client_flowtable_dump" )
260 self.handle.expect( self.prompt )
261 response = self.handle.before
262 # Write back in the tmp folder - needs to be changed in future
263 with open(self.tempDirectory + "flows_%s.txt" % self.dpid, "w") as flows:
264 flows.write(response + "\n")
265 flows.close()
266 # Done return for further processing
267 return response
268 # Errors handling
269 except pexpect.TIMEOUT:
270 main.log.error( self.name + ": pexpect.TIMEOUT found" )
271 return main.FALSE
272 except pexpect.EOF:
273 main.log.error( self.name + ": EOF exception found" )
274 main.log.error( self.name + ": " + self.handle.before )
275 main.cleanAndExit()
276 except Exception:
277 main.log.exception( self.name + ": Uncaught exception!" )
278 main.cleanAndExit()
279
280 def dumpGroups( self ):
281 """
282 Dump the groups from the devices
283 FIXME need changes in the workflow in order to be used
284 """
285 try:
286 self.handle.sendline( "" )
287 self.handle.expect( self.prompt )
288 self.handle.sendline( "client_grouptable_dump > groups.txt" )
289 self.handle.expect( self.prompt )
290 response = self.handle.before
291 # Write back in the tmp folder - needs to be changed in future
292 with open(self.tempDirectory + "groups_%s.txt" % self.dpid, "w") as groups:
293 groups.write(response + "\n")
294 groups.close()
295 # Done return for further processing
296 return response
297 # Errors handling
298 except pexpect.TIMEOUT:
299 main.log.error( self.name + ": pexpect.TIMEOUT found" )
300 return main.FALSE
301 except pexpect.EOF:
302 main.log.error( self.name + ": EOF exception found" )
303 main.log.error( self.name + ": " + self.handle.before )
304 main.cleanAndExit()
305 except Exception:
306 main.log.exception( self.name + ": Uncaught exception!" )
307 main.cleanAndExit()
308
309 def enablePorts( self ):
310 """
311 Enable all the ports on the devices
312 It needs to wait for the boot
313 """
314 self.handle.sendline( "" )
315 self.handle.expect( self.prompt )
316 self.handle.sendline( "client_port_table_dump" )
317 self.handle.expect( self.prompt )
318 response = self.handle.before
319 if "Error from ofdpaClientInitialize()" in response:
320 main.log.warn(
321 self.name +
322 ": Not yet started" )
323 return main.FALSE
324 main.log.info( self.name + ": started" )
325 self.handle.sendline( "sh portspeed.sh" )
326 self.handle.expect( self.prompt )
327 return main.TRUE