blob: 479fc3b9714c4917a68d357764d93429bb505880 [file] [log] [blame]
Steve McIntyrecc297112014-08-11 18:46:58 +01001#! /usr/bin/python
2
3# Copyright 2014 Linaro Limited
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18# MA 02110-1301, USA.
19
20import logging
21import pexpect
22import sys
23import time
24import re
Steve McIntyre3c3f4fc2015-02-12 04:26:27 +000025from common import SwitchDriver, SwitchErrors
Steve McIntyrecc297112014-08-11 18:46:58 +010026
Steve McIntyre72a8bce2015-01-23 18:02:19 +000027if __name__ == '__main__':
28 vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
29 sys.path.insert(0, vlandpath)
30 sys.path.insert(0, "%s/.." % vlandpath)
31
Steve McIntyre9f7f03b2015-02-12 03:10:13 +000032from errors import CriticalError, InputError, PExpectError
Steve McIntyre72a8bce2015-01-23 18:02:19 +000033
Steve McIntyrecc297112014-08-11 18:46:58 +010034class CiscoSX300(SwitchDriver):
35
36 connection = None
Steve McIntyrebbd2ac82015-02-12 03:08:48 +000037 _username = None
38 _password = None
39 _enable_password = None
Steve McIntyre366046f2014-08-18 18:57:03 +010040
41 # No extra capabilities for this switch/driver yet
42 _capabilities = [
43 ]
44
Steve McIntyrecc297112014-08-11 18:46:58 +010045 # Regexp of expected hardware information - fail if we don't see
46 # this
Steve McIntyreb9783ff2014-12-23 16:36:35 +000047 _expected_descr_re = re.compile('.*\d+-Port.*Managed Switch.*')
Steve McIntyrecc297112014-08-11 18:46:58 +010048
Steve McIntyre16f02162014-08-14 17:47:36 +010049 logfile = None
Steve McIntyrecc297112014-08-11 18:46:58 +010050
Steve McIntyre48dc6ae2014-12-23 16:08:19 +000051 def __init__(self, switch_hostname, switch_telnetport=23, debug = False):
52 if debug:
Steve McIntyre9f5a0232014-12-23 16:14:28 +000053 self.logfile = sys.stderr
Steve McIntyrecc297112014-08-11 18:46:58 +010054 self.exec_string = "/usr/bin/telnet %s %d" % (switch_hostname, switch_telnetport)
Steve McIntyre3c3f4fc2015-02-12 04:26:27 +000055 self.errors = SwitchErrors()
Steve McIntyrecc297112014-08-11 18:46:58 +010056
57 ################################
58 ### Switch-level API functions
59 ################################
60
61 # Connect to the switch and log in
Steve McIntyrec1e42b72014-12-22 16:13:08 +000062 def switch_connect(self, username, password, enablepassword):
Steve McIntyrebbd2ac82015-02-12 03:08:48 +000063 self._username = username
64 self._password = password
65 self._enable_password = enablepassword
Steve McIntyre9295d502015-02-12 04:46:45 +000066 self._switch_connect()
67
68 # Connect to the switch and log in
69 def _switch_connect(self):
70
71 if not self.connection is None:
72 self.connection.close(True)
73 self.connection = None
74
75 logging.debug("Connecting to Switch with: %s" % self.exec_string)
76 self.connection = pexpect.spawn(self.exec_string, logfile = self.logfile)
Steve McIntyrebbd2ac82015-02-12 03:08:48 +000077
78 self._login()
Steve McIntyrecc297112014-08-11 18:46:58 +010079
Steve McIntyredd0c0012014-12-24 00:10:17 +000080 # Avoid paged output
81 self._cli("terminal datadump")
Steve McIntyre7ced0732014-08-12 18:07:56 +010082
Steve McIntyrecc297112014-08-11 18:46:58 +010083 # And grab details about the switch. in case we need it
Steve McIntyre366046f2014-08-18 18:57:03 +010084 self._get_systemdata()
Steve McIntyrecc297112014-08-11 18:46:58 +010085
86 # And also validate them - make sure we're driving a switch of
87 # the correct model! Also store the serial number
Steve McIntyreb9783ff2014-12-23 16:36:35 +000088 descr_regex = re.compile('System Description:.\s+(.*)')
Steve McIntyrecc297112014-08-11 18:46:58 +010089 sn_regex = re.compile('SN:\s+(\S_)')
90 descr = ""
91
Steve McIntyre366046f2014-08-18 18:57:03 +010092 for line in self._systemdata:
Steve McIntyrecc297112014-08-11 18:46:58 +010093 match = descr_regex.match(line)
94 if match:
95 descr = match.group(1)
96 match = sn_regex.match(line)
97 if match:
98 self.serial_number = match.group(1)
99
Steve McIntyre366046f2014-08-18 18:57:03 +0100100 if not self._expected_descr_re.match(descr):
Steve McIntyrecc297112014-08-11 18:46:58 +0100101 raise IOError("Switch %s not recognised by this driver: abort" % descr)
102
Steve McIntyre28d34ca2014-08-12 15:40:24 +0100103 # Now build a list of our ports, for later sanity checking
Steve McIntyre366046f2014-08-18 18:57:03 +0100104 self._ports = self._get_port_names()
105 if len(self._ports) < 4:
Steve McIntyre28d34ca2014-08-12 15:40:24 +0100106 raise IOError("Not enough ports detected - problem!")
107
Steve McIntyrecc297112014-08-11 18:46:58 +0100108 # Log out of the switch and drop the connection and all state
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100109 def switch_disconnect(self):
Steve McIntyrecc297112014-08-11 18:46:58 +0100110 self._logout()
111 logging.debug("Closing connection: %s" % self.connection)
112 self.connection.close(True)
Steve McIntyre11393992014-10-10 15:53:34 +0100113 self._ports = []
114 self._prompt_name = ''
115 self._systemdata = []
Steve McIntyrecc297112014-08-11 18:46:58 +0100116 del(self)
117
118 # Save the current running config into flash - we want config to
119 # remain across reboots
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100120 def switch_save_running_config(self):
Steve McIntyrec5359e62015-02-12 04:54:07 +0000121 try:
122 self._cli("copy running-config startup-config")
123 self.connection.expect("Y/N")
124 self._cli("y")
125 self.connection.expect("succeeded")
126 except PExpectError:
127 # recurse on error
128 self._switch_connect()
129 self.switch_save_running_config()
Steve McIntyrecc297112014-08-11 18:46:58 +0100130
Steve McIntyre095b4452014-12-19 17:53:43 +0000131 # Restart the switch - we need to reload config to do a
132 # roll-back. Do NOT save running-config first if the switch asks -
133 # we're trying to dump recent changes, not save them.
134 #
135 # This will also implicitly cause a connection to be closed
136 def switch_restart(self):
137 self._cli("reload")
138 index = self.connection.expect(['Are you sure', 'will reset'])
139 if index == 0:
140 self._cli("y") # Yes, continue without saving
141 self.connection.expect("reset the whole")
142
143 # Fall through
144 self._cli("y") # Yes, continue to reset
145 self.connection.close(True)
146
Steve McIntyrecc297112014-08-11 18:46:58 +0100147 ################################
148 ### VLAN API functions
149 ################################
150
151 # Create a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100152 def vlan_create(self, tag):
Steve McIntyrecc297112014-08-11 18:46:58 +0100153 logging.debug("Creating VLAN %d" % tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100154
Steve McIntyrec5359e62015-02-12 04:54:07 +0000155 try:
156 self._configure()
157 self._cli("vlan database")
158 self._cli("vlan %d" % tag)
159 self._end_configure()
160
161 # Validate it happened
162 vlans = self.vlan_get_list()
163 for vlan in vlans:
164 if vlan == tag:
165 return
166 raise IOError("Failed to create VLAN %d" % tag)
167
168 except PExpectError:
169 # recurse on error
170 self._switch_connect()
171 self.vlan_create(tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100172
173 # Destroy a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100174 def vlan_destroy(self, tag):
Steve McIntyrecc297112014-08-11 18:46:58 +0100175 logging.debug("Destroying VLAN %d" % tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100176
Steve McIntyrec5359e62015-02-12 04:54:07 +0000177 try:
178 self._configure()
179 self._cli("no vlan %d" % tag)
180 self._end_configure()
181
182 # Validate it happened
183 vlans = self.vlan_get_list()
184 for vlan in vlans:
185 if vlan == tag:
186 raise IOError("Failed to destroy VLAN %d" % tag)
187
188 except PExpectError:
189 # recurse on error
190 self._switch_connect()
191 self.vlan_destroy(tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100192
193 # Set the name of a VLAN
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100194 def vlan_set_name(self, tag, name):
Steve McIntyrecc297112014-08-11 18:46:58 +0100195 logging.debug("Setting name of VLAN %d to %s" % (tag, name))
Steve McIntyrecc297112014-08-11 18:46:58 +0100196
Steve McIntyrec5359e62015-02-12 04:54:07 +0000197 try:
198 self._configure()
199 self._cli("vlan %d" % tag)
200 self._cli("interface vlan %d" % tag)
201 self._cli("name %s" % name)
202 self._end_configure()
203
204 # Validate it happened
205 read_name = self.vlan_get_name(tag)
206 if read_name != name:
207 raise IOError("Failed to set name for VLAN %d (name found is \"%s\", not \"%s\")"
208 % (tag, read_name, name))
209
210 except PExpectError:
211 # recurse on error
212 self._switch_connect()
213 self.vlan_set_name(tag, name)
Steve McIntyrecc297112014-08-11 18:46:58 +0100214
215 # Get a list of the VLAN tags currently registered on the switch
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100216 def vlan_get_list(self):
Steve McIntyrecc297112014-08-11 18:46:58 +0100217 logging.debug("Grabbing list of VLANs")
Steve McIntyrecc297112014-08-11 18:46:58 +0100218
Steve McIntyrec5359e62015-02-12 04:54:07 +0000219 try:
220 vlans = []
221 regex = re.compile('^ *(\d+).*(D|S|G|R)')
Steve McIntyrecc297112014-08-11 18:46:58 +0100222
Steve McIntyrec5359e62015-02-12 04:54:07 +0000223 self._cli("show vlan")
224 for line in self._read_long_output():
225 match = regex.match(line)
226 if match:
227 vlans.append(int(match.group(1)))
228 return vlans
229
230 except PExpectError:
231 # recurse on error
232 self._switch_connect()
233 return self.vlan_get_list()
Steve McIntyrecc297112014-08-11 18:46:58 +0100234
235 # For a given VLAN tag, ask the switch what the associated name is
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100236 def vlan_get_name(self, tag):
Steve McIntyrecc297112014-08-11 18:46:58 +0100237 logging.debug("Grabbing the name of VLAN %d" % tag)
Steve McIntyrec5359e62015-02-12 04:54:07 +0000238
239 try:
240 name = None
241 regex = re.compile('^ *\d+\s+(\S+).*(D|S|G|R)')
242 self._cli("show vlan tag %d" % tag)
243 for line in self._read_long_output():
244 match = regex.match(line)
245 if match:
246 name = match.group(1)
247 name.strip()
248 return name
249
250 except PExpectError:
251 # recurse on error
252 self._switch_connect()
253 return self.vlan_get_name(tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100254
255 ################################
256 ### Port API functions
257 ################################
258
Steve McIntyre9936d002014-10-01 15:54:10 +0100259 # Set the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100260 def port_set_mode(self, port, mode):
Steve McIntyrecc297112014-08-11 18:46:58 +0100261 logging.debug("Setting port %s to %s" % (port, mode))
262 if not self._is_port_mode_valid(mode):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000263 raise InputError("Port mode %s is not allowed" % mode)
Steve McIntyrecc297112014-08-11 18:46:58 +0100264 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000265 raise InputError("Port name %s not recognised" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100266
Steve McIntyrec5359e62015-02-12 04:54:07 +0000267 try:
268 self._configure()
269 self._cli("interface %s" % port)
270 self._cli("switchport mode %s" % mode)
271 self._end_configure()
Steve McIntyrecc297112014-08-11 18:46:58 +0100272
Steve McIntyrec5359e62015-02-12 04:54:07 +0000273 # Validate it happened
274 read_mode = self.port_get_mode(port)
275 if read_mode != mode:
276 raise IOError("Failed to set mode for port %s" % port)
277
278 except PExpectError:
279 # recurse on error
280 self._switch_connect()
281 self.port_set_mode(port, mode)
Steve McIntyrecc297112014-08-11 18:46:58 +0100282
Steve McIntyre9936d002014-10-01 15:54:10 +0100283 # Get the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100284 def port_get_mode(self, port):
Steve McIntyrecc297112014-08-11 18:46:58 +0100285 logging.debug("Getting mode of port %s" % port)
286 mode = ''
287 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000288 raise InputError("Port name %s not recognised" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100289 regex = re.compile('Port Mode: (\S+)')
Steve McIntyrec5359e62015-02-12 04:54:07 +0000290
291 try:
292 self._cli("show interfaces switchport %s" % port)
293 for line in self._read_long_output():
294 match = regex.match(line)
295 if match:
296 mode = match.group(1)
297 return mode.lower()
298
299 except PExpectError:
300 # recurse on error
301 self._switch_connect()
302 return self.port_get_mode(port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100303
Steve McIntyre9936d002014-10-01 15:54:10 +0100304 # Set an access port to be in a specified VLAN (tag)
305 def port_set_access_vlan(self, port, tag):
306 logging.debug("Setting access port %s to VLAN %d" % (port, tag))
Steve McIntyrecc297112014-08-11 18:46:58 +0100307 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000308 raise InputError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100309 if not (self.port_get_mode(port) == "access"):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000310 raise InputError("Port %s not in access mode" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100311
Steve McIntyrec5359e62015-02-12 04:54:07 +0000312 try:
313 self._configure()
314 self._cli("interface %s" % port)
315 self._cli("switchport access vlan %d" % tag)
316 self._end_configure()
Steve McIntyrecc297112014-08-11 18:46:58 +0100317
Steve McIntyrec5359e62015-02-12 04:54:07 +0000318 # Validate things worked
319 read_vlan = int(self.port_get_access_vlan(port))
320 if read_vlan != tag:
321 raise IOError("Failed to move access port %s to VLAN %d - got VLAN %d instead"
322 % (port, tag, read_vlan))
323
324 except PExpectError:
325 # recurse on error
326 self._switch_connect()
327 self.port_set_access_vlan(port, tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100328
Steve McIntyrecc297112014-08-11 18:46:58 +0100329 # Add a trunk port to a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100330 def port_add_trunk_to_vlan(self, port, tag):
Steve McIntyrecc297112014-08-11 18:46:58 +0100331 logging.debug("Adding trunk port %s to VLAN %d" % (port, tag))
332 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000333 raise InputError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100334 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000335 raise InputError("Port %s not in trunk mode" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100336
Steve McIntyrec5359e62015-02-12 04:54:07 +0000337 try:
338 self._configure()
339 self._cli("interface %s" % port)
340 self._cli("switchport trunk allowed vlan add %d" % tag)
341 self._end_configure()
342
343 # Validate it happened
344 read_vlans = self.port_get_trunk_vlan_list(port)
345 for vlan in read_vlans:
346 if vlan == tag:
347 return
348 raise IOError("Failed to add trunk port %s to VLAN %d" % (port, tag))
349
350 except PExpectError:
351 # recurse on error
352 self._switch_connect()
353 self.port_add_trunk_to_vlan(port, tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100354
355 # Remove a trunk port from a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100356 def port_remove_trunk_from_vlan(self, port, tag):
Steve McIntyrecc297112014-08-11 18:46:58 +0100357 logging.debug("Removing trunk port %s from VLAN %d" % (port, tag))
358 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000359 raise InputError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100360 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000361 raise InputError("Port %s not in trunk mode" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100362
Steve McIntyrec5359e62015-02-12 04:54:07 +0000363 try:
364 self._configure()
365 self._cli("interface %s" % port)
366 self._cli("switchport trunk allowed vlan remove %d" % tag)
367 self._end_configure()
368
369 # Validate it happened
370 read_vlans = self.port_get_trunk_vlan_list(port)
371 for vlan in read_vlans:
372 if vlan == tag:
373 raise IOError("Failed to remove trunk port %s from VLAN %d" % (port, tag))
374
375 except PExpectError:
376 # recurse on error
377 self._switch_connect()
378 self.port_remove_trunk_from_vlan(port, tag)
Steve McIntyrecc297112014-08-11 18:46:58 +0100379
Steve McIntyre9936d002014-10-01 15:54:10 +0100380 # Get the configured VLAN tag for an access port (tag)
381 def port_get_access_vlan(self, port):
382 logging.debug("Getting VLAN for access port %s" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100383 vlan = 1
384 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000385 raise InputError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100386 if not (self.port_get_mode(port) == "access"):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000387 raise InputError("Port %s not in access mode" % port)
Steve McIntyre0f893602014-12-24 02:14:53 +0000388 regex = re.compile('(\d+)\s+\S+\s+Untagged\s+(Static|System)')
Steve McIntyrec5359e62015-02-12 04:54:07 +0000389
390 try:
391 self._cli("show interfaces switchport %s" % port)
392 for line in self._read_long_output():
393 match = regex.match(line)
394 if match:
395 vlan = match.group(1)
396 return int(vlan)
397
398 except PExpectError:
399 # recurse on error
400 self._switch_connect()
401 return self.port_get_access_vlan(port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100402
403 # Get the list of configured VLAN tags for a trunk port
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100404 def port_get_trunk_vlan_list(self, port):
Steve McIntyrecc297112014-08-11 18:46:58 +0100405 logging.debug("Getting VLANs for trunk port %s" % port)
406 vlans = [ ]
407 if not self._is_port_name_valid(port):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000408 raise InputError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100409 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyre72a8bce2015-01-23 18:02:19 +0000410 raise InputError("Port %s not in trunk mode" % port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100411 regex = re.compile('(\d+)\s+\S+\s+(Tagged|Untagged)\s+Static')
Steve McIntyrec5359e62015-02-12 04:54:07 +0000412
413 try:
414 self._cli("show interfaces switchport %s" % port)
415 for line in self._read_long_output():
416 match = regex.match(line)
417 if match:
418 vlans.append (int(match.group(1)))
419 return vlans
420
421 except PExpectError:
422 # recurse on error
423 self._switch_connect()
424 return self.port_get_trunk_vlan_list(port)
Steve McIntyrecc297112014-08-11 18:46:58 +0100425
426 ################################
427 ### Internal functions
428 ################################
429
Steve McIntyrebbd2ac82015-02-12 03:08:48 +0000430 def _login(self):
431 logging.debug("attempting login with username %s, password %s" % (self._username, self._password))
Steve McIntyrecc297112014-08-11 18:46:58 +0100432 self._cli("")
433 self.connection.expect("User Name:")
Steve McIntyrebbd2ac82015-02-12 03:08:48 +0000434 self._cli("%s" % self._username)
Steve McIntyrecc297112014-08-11 18:46:58 +0100435 self.connection.expect("Password:")
Steve McIntyrebbd2ac82015-02-12 03:08:48 +0000436 self._cli("%s" % self._password, False)
Steve McIntyreca6c5a32014-12-23 15:34:29 +0000437 self.connection.expect("\*\*")
Steve McIntyrecc297112014-08-11 18:46:58 +0100438 while True:
Steve McIntyreca6c5a32014-12-23 15:34:29 +0000439 index = self.connection.expect(['User Name:', 'authentication failed', r'(.*)#', 'Password:', '.+'])
Steve McIntyrecc297112014-08-11 18:46:58 +0100440 if index == 0 or index == 1: # Failed to log in!
441 logging.error("Login failure: %s\n" % self.connection.match)
442 raise IOError
443 elif index == 2:
Steve McIntyre366046f2014-08-18 18:57:03 +0100444 self._prompt_name = self.connection.match.group(1).strip()
Steve McIntyreca6c5a32014-12-23 15:34:29 +0000445 logging.debug("Got prompt name %s" % self._prompt_name)
Steve McIntyre2eececb2015-02-12 03:09:17 +0000446 print "Got prompt name %s" % self._prompt_name
Steve McIntyrecc297112014-08-11 18:46:58 +0100447 return 0
Steve McIntyreca6c5a32014-12-23 15:34:29 +0000448 elif index == 3 or index == 4:
449 self._cli("", False)
Steve McIntyrecc297112014-08-11 18:46:58 +0100450
451 def _logout(self):
452 logging.debug("Logging out")
453 self._cli("exit", False)
454
Steve McIntyrecc297112014-08-11 18:46:58 +0100455 def _configure(self):
456 self._cli("configure terminal")
457
458 def _end_configure(self):
459 self._cli("end")
460
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000461 def _read_long_output(self):
Steve McIntyre366046f2014-08-18 18:57:03 +0100462 prompt = self._prompt_name + '#'
Steve McIntyre2eececb2015-02-12 03:09:17 +0000463 try:
464 self.connection.expect(prompt)
Steve McIntyre1d23b492015-02-12 03:47:24 +0000465 except (pexpect.EOF, pexpect.TIMEOUT):
Steve McIntyred0614fb2015-02-12 03:44:42 +0000466 # Something went wrong; logout, log in and try again!
467 print "PEXPECT FAILURE, RECONNECT"
Steve McIntyre3c3f4fc2015-02-12 04:26:27 +0000468 self.errors.log_error_in("")
Steve McIntyre1a3e2f72015-02-12 03:49:05 +0000469 raise PExpectError("_read_long_output failed")
Steve McIntyre2eececb2015-02-12 03:09:17 +0000470 except:
471 print "prompt is \"%s\"" % prompt
472 raise
Steve McIntyrea7cdefc2014-12-24 00:48:19 +0000473 buf = []
474 for line in self.connection.before.split('\r\n'):
475 buf.append(line.strip())
476 return buf
Steve McIntyrecc297112014-08-11 18:46:58 +0100477
478 def _get_port_names(self):
479 logging.debug("Grabbing list of ports")
480 interfaces = []
481
482 # Use "Up" or "Down" to only identify lines in the output that
483 # match interfaces that exist
484 regex = re.compile('^(\w+).*(Up|Down)')
485
486 self._cli("show interfaces status detailed")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000487 for line in self._read_long_output():
Steve McIntyrecc297112014-08-11 18:46:58 +0100488 match = regex.match(line)
489 if match:
490 interfaces.append(match.group(1))
491 return interfaces
492
Steve McIntyrecc297112014-08-11 18:46:58 +0100493 def _show_config(self):
494 logging.debug("Grabbing config")
495 self._cli("show running-config")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000496 return self._read_long_output()
Steve McIntyrecc297112014-08-11 18:46:58 +0100497
498 def _show_clock(self):
499 logging.debug("Grabbing time")
500 self._cli("show clock")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000501 return self._read_long_output()
Steve McIntyrecc297112014-08-11 18:46:58 +0100502
Steve McIntyrecc297112014-08-11 18:46:58 +0100503 def _get_systemdata(self):
Steve McIntyrecc297112014-08-11 18:46:58 +0100504
Steve McIntyreffb9b5a2014-10-10 16:31:58 +0100505 self._systemdata = []
506
Steve McIntyre28d34ca2014-08-12 15:40:24 +0100507 logging.debug("Grabbing system data")
Steve McIntyrecc297112014-08-11 18:46:58 +0100508 self._cli("show system")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000509 for line in self._read_long_output():
Steve McIntyre366046f2014-08-18 18:57:03 +0100510 self._systemdata.append(line)
Steve McIntyre28d34ca2014-08-12 15:40:24 +0100511
512 logging.debug("Grabbing system sw and hw versions")
513 self._cli("show version")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000514 for line in self._read_long_output():
Steve McIntyre366046f2014-08-18 18:57:03 +0100515 self._systemdata.append(line)
Steve McIntyrecc297112014-08-11 18:46:58 +0100516
Steve McIntyre16f02162014-08-14 17:47:36 +0100517 ######################################
518 # Internal port access helper methods
519 ######################################
520 # N.B. No parameter checking here, for speed reasons - if you're
521 # calling this internal API then you should already have validated
522 # things yourself! Equally, no post-set checks in here - do that
523 # at the higher level.
524 ######################################
525
Steve McIntyrecc297112014-08-11 18:46:58 +0100526 # Wrapper around connection.send - by default, expect() the same
527 # text we've sent, to remove it from the output from the
528 # switch. For the few cases where we don't need that, override
529 # this using echo=False.
530 # Horrible, but seems to work.
531 def _cli(self, text, echo=True):
532 self.connection.send(text + '\r')
533 if echo:
Steve McIntyre9f7f03b2015-02-12 03:10:13 +0000534 try:
535 self.connection.expect(text)
Steve McIntyre1d23b492015-02-12 03:47:24 +0000536 except (pexpect.EOF, pexpect.TIMEOUT):
Steve McIntyre9f7f03b2015-02-12 03:10:13 +0000537 # Something went wrong; logout, log in and try again!
538 print "PEXPECT FAILURE, RECONNECT"
Steve McIntyre3c3f4fc2015-02-12 04:26:27 +0000539 self.errors.log_error_out(text)
Steve McIntyre729d9502015-02-12 03:14:10 +0000540 raise PExpectError("_cli failed on %s" % text)
Steve McIntyre9f7f03b2015-02-12 03:10:13 +0000541 except:
542 print "Unexpected error:", sys.exc_info()[0]
543 raise
Steve McIntyrecc297112014-08-11 18:46:58 +0100544
545if __name__ == "__main__":
Steve McIntyref1699322014-08-19 22:49:43 +0100546# p = CiscoSX300('10.172.2.52', 23)
Steve McIntyre48dc6ae2014-12-23 16:08:19 +0000547
548 import optparse
549
550 switch = 'vlandswitch02'
551 parser = optparse.OptionParser()
552 parser.add_option("--switch",
553 dest = "switch",
554 action = "store",
555 nargs = 1,
556 type = "string",
557 help = "specify switch to connect to for testing",
558 metavar = "<switch>")
559 (opts, args) = parser.parse_args()
560 if opts.switch:
561 switch = opts.switch
562
563 p = CiscoSX300(switch, 23, debug = True)
Steve McIntyreaea995c2014-12-22 17:17:38 +0000564 p.switch_connect('cisco', 'cisco', None)
Steve McIntyrecc297112014-08-11 18:46:58 +0100565 #buf = p._show_clock()
566 #print "%s" % buf
567 #buf = p._show_config()
568 #p._dump_list(buf)
569
Steve McIntyre366046f2014-08-18 18:57:03 +0100570 print "System data:"
571 p._dump_list(p._systemdata)
Steve McIntyrecc297112014-08-11 18:46:58 +0100572
573 print "Creating VLANs for testing:"
574 for i in [ 2, 3, 4, 5, 20 ]:
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100575 p.vlan_create(i)
576 p.vlan_set_name(i, "test%d" % i)
Steve McIntyrecc297112014-08-11 18:46:58 +0100577 print " %d (test%d)" % (i, i)
578
579 #print "And dump config\n"
580 #buf = p._show_config()
581 #print "%s" % buf
582
583 #print "Destroying VLAN 2\n"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100584 #p.vlan_destroy(2)
Steve McIntyrecc297112014-08-11 18:46:58 +0100585
586 #print "And dump config\n"
587 #buf = p._show_config()
588 #print "%s" % buf
589
590 #print "Port names are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100591 #buf = p.switch_get_port_names()
Steve McIntyrecc297112014-08-11 18:46:58 +0100592 #p._dump_list(buf)
593
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100594 #buf = p.vlan_get_name(25)
Steve McIntyrecc297112014-08-11 18:46:58 +0100595 #print "VLAN with tag 25 is called \"%s\"" % buf
596
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100597 #p.vlan_set_name(35, "foo")
Steve McIntyrecc297112014-08-11 18:46:58 +0100598 #print "VLAN with tag 35 is called \"foo\""
599
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100600 #buf = p.port_get_mode("fa12")
Steve McIntyrecc297112014-08-11 18:46:58 +0100601 #print "Port fa12 is in %s mode" % buf
602
Steve McIntyre9936d002014-10-01 15:54:10 +0100603 # Test access stuff
604 print "Set fa6 to access mode"
605 p.port_set_mode("fa6", "access")
Steve McIntyre16f02162014-08-14 17:47:36 +0100606 print "Move fa6 to VLAN 2"
Steve McIntyre9936d002014-10-01 15:54:10 +0100607 p.port_set_access_vlan("fa6", 2)
608 buf = p.port_get_access_vlan("fa6")
Steve McIntyrecc297112014-08-11 18:46:58 +0100609 print "Read from switch: fa6 is on VLAN %s" % buf
Steve McIntyre16f02162014-08-14 17:47:36 +0100610 print "Move fa6 back to default VLAN 1"
Steve McIntyre9936d002014-10-01 15:54:10 +0100611 p.port_set_access_vlan("fa6", 1)
Steve McIntyrecc297112014-08-11 18:46:58 +0100612 #print "And move fa6 back to a trunk port"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100613 #p.port_set_mode("fa6", "trunk")
614 #buf = p.port_get_mode("fa6")
Steve McIntyrecc297112014-08-11 18:46:58 +0100615 #print "Port fa6 is in %s mode" % buf
616
617 # Test trunk stuff
618 print "Set gi2 to trunk mode"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100619 p.port_set_mode("gi2", "trunk")
Steve McIntyrecc297112014-08-11 18:46:58 +0100620 print "Add gi2 to VLAN 2"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100621 p.port_add_trunk_to_vlan("gi2", 2)
Steve McIntyrecc297112014-08-11 18:46:58 +0100622 print "Add gi2 to VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100623 p.port_add_trunk_to_vlan("gi2", 3)
Steve McIntyrecc297112014-08-11 18:46:58 +0100624 print "Add gi2 to VLAN 4"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100625 p.port_add_trunk_to_vlan("gi2", 4)
Steve McIntyrecc297112014-08-11 18:46:58 +0100626 print "Read from switch: which VLANs is gi2 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100627 buf = p.port_get_trunk_vlan_list("gi2")
Steve McIntyrecc297112014-08-11 18:46:58 +0100628 p._dump_list(buf)
629
Steve McIntyre366046f2014-08-18 18:57:03 +0100630 print "Remove gi2 from VLANs 3,3,4"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100631 p.port_remove_trunk_from_vlan("gi2", 3)
632 p.port_remove_trunk_from_vlan("gi2", 3)
633 p.port_remove_trunk_from_vlan("gi2", 4)
Steve McIntyrecc297112014-08-11 18:46:58 +0100634 print "Read from switch: which VLANs is gi2 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100635 buf = p.port_get_trunk_vlan_list("gi2")
Steve McIntyrecc297112014-08-11 18:46:58 +0100636 p._dump_list(buf)
637
638 # print "Adding lots of ports to VLANs"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100639 # p.port_add_trunk_to_vlan("fa1", 2)
640 # p.port_add_trunk_to_vlan("fa3", 2)
641 # p.port_add_trunk_to_vlan("fa5", 2)
642 # p.port_add_trunk_to_vlan("fa7", 2)
643 # p.port_add_trunk_to_vlan("fa9", 2)
644 # p.port_add_trunk_to_vlan("fa11", 2)
645 # p.port_add_trunk_to_vlan("fa13", 2)
646 # p.port_add_trunk_to_vlan("fa15", 2)
647 # p.port_add_trunk_to_vlan("fa17", 2)
648 # p.port_add_trunk_to_vlan("fa19", 2)
649 # p.port_add_trunk_to_vlan("fa21", 2)
650 # p.port_add_trunk_to_vlan("fa23", 2)
651 # p.port_add_trunk_to_vlan("gi4", 2)
Steve McIntyrecc297112014-08-11 18:46:58 +0100652
653 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100654 buf = p.vlan_get_list()
Steve McIntyrecc297112014-08-11 18:46:58 +0100655 p._dump_list(buf)
656
Steve McIntyre7460d972014-12-23 14:45:30 +0000657# print 'Restarting switch, to explicitly reset config'
658# p.switch_restart()
Steve McIntyrecc297112014-08-11 18:46:58 +0100659
Steve McIntyrebf5dc882014-12-19 17:54:58 +0000660# p.switch_save_running_config()
Steve McIntyrecc297112014-08-11 18:46:58 +0100661# p._show_config()
662