blob: 5b875231e2e8c9ad3c51180a14cc258f6fd49aea [file] [log] [blame]
Steve McIntyred6759dd2014-08-12 18:10:00 +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
25from common import SwitchDriver
26
27class CiscoCatalyst(SwitchDriver):
28
29 connection = None
Steve McIntyre3f287882014-08-18 19:02:15 +010030
31 _capabilities = [
32 'TrunkWildCardVlans' # Trunk ports are on all VLANs by
33 # default, so we shouldn't need to
34 # bugger with them
35 ]
36
Steve McIntyred6759dd2014-08-12 18:10:00 +010037 # Regexp of expected hardware information - fail if we don't see
38 # this
Steve McIntyre3f287882014-08-18 19:02:15 +010039 _expected_descr_re = re.compile('WS-C\S+-\d+P')
Steve McIntyred6759dd2014-08-12 18:10:00 +010040
Steve McIntyred6759dd2014-08-12 18:10:00 +010041 logfile = None
42
Steve McIntyre48dc6ae2014-12-23 16:08:19 +000043 def __init__(self, switch_hostname, switch_telnetport=23, debug = False):
44 if debug:
Steve McIntyre9f5a0232014-12-23 16:14:28 +000045 self.logfile = sys.stderr
Steve McIntyred6759dd2014-08-12 18:10:00 +010046 self.exec_string = "/usr/bin/telnet %s %d" % (switch_hostname, switch_telnetport)
47
48 ################################
49 ### Switch-level API functions
50 ################################
51
52 # Connect to the switch and log in
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010053 def switch_connect(self, username, password, enablepassword):
Steve McIntyred6759dd2014-08-12 18:10:00 +010054 logging.debug("Connecting to Switch with: %s" % self.exec_string)
55 self.connection = pexpect.spawn(self.exec_string, logfile = self.logfile)
56 self._login(username, password, enablepassword)
57
58 # Try to avoid paged output
Steve McIntyredd0c0012014-12-24 00:10:17 +000059 self._cli("terminal length 0")
Steve McIntyred6759dd2014-08-12 18:10:00 +010060
61 # And grab details about the switch. in case we need it
Steve McIntyre3f287882014-08-18 19:02:15 +010062 self._get_systemdata()
Steve McIntyred6759dd2014-08-12 18:10:00 +010063
64 # And also validate them - make sure we're driving a switch of
65 # the correct model! Also store the serial number
66 descr_regex = re.compile('^cisco\s+(\S+)')
67 sn_regex = re.compile('System serial number\s+:\s+(\S+)')
68 descr = ""
69
Steve McIntyre3f287882014-08-18 19:02:15 +010070 for line in self._systemdata:
Steve McIntyred6759dd2014-08-12 18:10:00 +010071 match = descr_regex.match(line)
72 if match:
73 descr = match.group(1)
74 match = sn_regex.match(line)
75 if match:
76 self.serial_number = match.group(1)
77
Steve McIntyre6d5594f2014-12-23 14:28:47 +000078 logging.debug("serial number is %s" % self.serial_number)
79 logging.debug("system description is %s" % descr)
Steve McIntyred6759dd2014-08-12 18:10:00 +010080
Steve McIntyre3f287882014-08-18 19:02:15 +010081 if not self._expected_descr_re.match(descr):
Steve McIntyred6759dd2014-08-12 18:10:00 +010082 raise IOError("Switch %s not recognised by this driver: abort" % descr)
83
84 # Now build a list of our ports, for later sanity checking
Steve McIntyre3f287882014-08-18 19:02:15 +010085 self._ports = self._get_port_names()
86 if len(self._ports) < 4:
Steve McIntyred6759dd2014-08-12 18:10:00 +010087 raise IOError("Not enough ports detected - problem!")
88
89 # Log out of the switch and drop the connection and all state
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010090 def switch_disconnect(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +010091 self._logout()
92 logging.debug("Closing connection: %s" % self.connection)
93 self.connection.close(True)
94 del(self)
95
96 # Save the current running config into flash - we want config to
97 # remain across reboots
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010098 def switch_save_running_config(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +010099 self._cli("copy running-config startup-config")
Steve McIntyree1bf11a2014-08-14 17:56:25 +0100100 self.connection.expect("startup-config")
101 self._cli("startup-config")
102 self.connection.expect("OK")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100103
Steve McIntyre095b4452014-12-19 17:53:43 +0000104 # Restart the switch - we need to reload config to do a
105 # roll-back. Do NOT save running-config first if the switch asks -
106 # we're trying to dump recent changes, not save them.
107 #
108 # This will also implicitly cause a connection to be closed
109 def switch_restart(self):
110 self._cli("reload")
111 index = self.connection.expect(['has been modified', 'Proceed'])
112 if index == 0:
113 self._cli("n") # No, don't save
114 self.connection.expect("Proceed")
115
116 # Fall through
117 self._cli("y") # Yes, continue to reset
118 self.connection.close(True)
119
Steve McIntyre3f287882014-08-18 19:02:15 +0100120 # List the capabilities of the switch (and driver) - some things
121 # make no sense to abstract. Returns a dict of strings, each one
122 # describing an extra feature that that higher levels may care
123 # about
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100124 def switch_get_capabilities(self):
Steve McIntyre3f287882014-08-18 19:02:15 +0100125 return self._capabilities
Steve McIntyred6759dd2014-08-12 18:10:00 +0100126
127 ################################
128 ### VLAN API functions
129 ################################
130
131 # Create a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100132 def vlan_create(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100133 logging.debug("Creating VLAN %d" % tag)
134 self._configure()
135 self._cli("vlan %d" % tag)
136 self._end_configure()
137
138 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100139 vlans = self.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100140 for vlan in vlans:
141 if vlan == tag:
142 return
143 raise IOError("Failed to create VLAN %d" % tag)
144
145 # Destroy a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100146 def vlan_destroy(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100147 logging.debug("Destroying VLAN %d" % tag)
148 self._configure()
149 self._cli("no vlan %d" % tag)
150 self._end_configure()
151
152 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100153 vlans = self.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100154 for vlan in vlans:
155 if vlan == tag:
156 raise IOError("Failed to destroy VLAN %d" % tag)
157
158 # Set the name of a VLAN
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100159 def vlan_set_name(self, tag, name):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100160 logging.debug("Setting name of VLAN %d to %s" % (tag, name))
161 self._configure()
162 self._cli("vlan %d" % tag)
163 self._cli("name %s" % name)
164 self._end_configure()
165
166 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100167 read_name = self.vlan_get_name(tag)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100168 if read_name != name:
169 raise IOError("Failed to set name for VLAN %d (name found is \"%s\", not \"%s\")"
170 % (tag, read_name, name))
171
172 # Get a list of the VLAN tags currently registered on the switch
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100173 def vlan_get_list(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100174 logging.debug("Grabbing list of VLANs")
175 vlans = []
176
177 regex = re.compile('^ *(\d+).*(active)')
178
179 self._cli("show vlan brief")
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000180 for line in self._read_long_output():
Steve McIntyred6759dd2014-08-12 18:10:00 +0100181 match = regex.match(line)
182 if match:
183 vlans.append(int(match.group(1)))
184 return vlans
185
186 # For a given VLAN tag, ask the switch what the associated name is
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100187 def vlan_get_name(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100188 logging.debug("Grabbing the name of VLAN %d" % tag)
189 name = None
190 regex = re.compile('^ *\d+\s+(\S+).*(active)')
191 self._cli("show vlan id %d" % tag)
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000192 for line in self._read_long_output():
Steve McIntyred6759dd2014-08-12 18:10:00 +0100193 match = regex.match(line)
194 if match:
195 name = match.group(1)
196 name.strip()
197 return name
198
199
200 ################################
201 ### Port API functions
Steve McIntyree1bf11a2014-08-14 17:56:25 +0100202 ################################
Steve McIntyred6759dd2014-08-12 18:10:00 +0100203
Steve McIntyre9936d002014-10-01 15:54:10 +0100204 # Set the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100205 def port_set_mode(self, port, mode):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100206 logging.debug("Setting port %s to %s" % (port, mode))
207 if not self._is_port_mode_valid(mode):
208 raise IndexError("Port mode %s is not allowed" % mode)
209 if not self._is_port_name_valid(port):
210 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100211
Steve McIntyred6759dd2014-08-12 18:10:00 +0100212 self._configure()
213 self._cli("interface %s" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100214 self._cli("switchport mode %s" % mode)
215 if mode == "trunk":
216 self._cli("switchport trunk encapsulation dot1q")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100217 self._end_configure()
218
219 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100220 read_mode = self.port_get_mode(port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100221
Steve McIntyred6759dd2014-08-12 18:10:00 +0100222 if read_mode != mode:
223 raise IOError("Failed to set mode for port %s" % port)
224
Steve McIntyre9936d002014-10-01 15:54:10 +0100225 # Get the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100226 def port_get_mode(self, port):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100227 logging.debug("Getting mode of port %s" % port)
228 mode = ''
229 if not self._is_port_name_valid(port):
230 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100231 regex = re.compile('Administrative Mode: (.*)')
Steve McIntyreb7adc782014-08-13 00:22:21 +0100232 self._cli("show interfaces %s switchport" % port)
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000233 for line in self._read_long_output():
Steve McIntyred6759dd2014-08-12 18:10:00 +0100234 match = regex.match(line)
235 if match:
236 mode = match.group(1)
Steve McIntyre9936d002014-10-01 15:54:10 +0100237 if mode == 'static access':
238 return 'access'
Steve McIntyre6c279b42014-12-23 22:09:04 +0000239 if mode == 'dynamic auto':
240 return 'trunk'
Steve McIntyre3f287882014-08-18 19:02:15 +0100241 return mode
Steve McIntyred6759dd2014-08-12 18:10:00 +0100242
Steve McIntyre9936d002014-10-01 15:54:10 +0100243 # Set an access port to be in a specified VLAN (tag)
244 def port_set_access_vlan(self, port, tag):
245 logging.debug("Setting access port %s to VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100246 if not self._is_port_name_valid(port):
247 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100248 if not (self.port_get_mode(port) == "access"):
249 raise IndexError("Port %s not in access mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100250
Steve McIntyred6759dd2014-08-12 18:10:00 +0100251 self._configure()
252 self._cli("interface %s" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100253 self._cli("switchport access vlan %d" % tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100254 self._cli("no shutdown")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100255 self._end_configure()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100256
Steve McIntyre3f287882014-08-18 19:02:15 +0100257 # Finally, validate things worked
Steve McIntyre9936d002014-10-01 15:54:10 +0100258 read_vlan = int(self.port_get_access_vlan(port))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100259 if read_vlan != tag:
Steve McIntyre9936d002014-10-01 15:54:10 +0100260 raise IOError("Failed to move access port %d to VLAN %d - got VLAN %d instead"
Steve McIntyred6759dd2014-08-12 18:10:00 +0100261 % (port, tag, read_vlan))
262
Steve McIntyred6759dd2014-08-12 18:10:00 +0100263 # Add a trunk port to a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100264 def port_add_trunk_to_vlan(self, port, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100265 logging.debug("Adding trunk port %s to VLAN %d" % (port, tag))
266 if not self._is_port_name_valid(port):
267 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100268 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100269 raise IndexError("Port %s not in trunk mode" % port)
270 self._configure()
271 self._cli("interface %s" % port)
272 self._cli("switchport trunk allowed vlan add %d" % tag)
273 self._end_configure()
274
275 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100276 read_vlans = self.port_get_trunk_vlan_list(port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100277 for vlan in read_vlans:
Steve McIntyre3f287882014-08-18 19:02:15 +0100278 if vlan == tag or vlan == "ALL":
Steve McIntyred6759dd2014-08-12 18:10:00 +0100279 return
Steve McIntyre3f287882014-08-18 19:02:15 +0100280 raise IOError("Failed to add trunk port %s to VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100281
282 # Remove a trunk port from a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100283 def port_remove_trunk_from_vlan(self, port, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100284 logging.debug("Removing trunk port %s from VLAN %d" % (port, tag))
285 if not self._is_port_name_valid(port):
286 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100287 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100288 raise IndexError("Port %s not in trunk mode" % port)
289 self._configure()
290 self._cli("interface %s" % port)
291 self._cli("switchport trunk allowed vlan remove %d" % tag)
292 self._end_configure()
293
294 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100295 read_vlans = self.port_get_trunk_vlan_list(port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100296 for vlan in read_vlans:
297 if vlan == tag:
Steve McIntyre3f287882014-08-18 19:02:15 +0100298 raise IOError("Failed to remove trunk port %s from VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100299
Steve McIntyre9936d002014-10-01 15:54:10 +0100300 # Get the configured VLAN tag for an access port (tag)
301 def port_get_access_vlan(self, port):
302 logging.debug("Getting VLAN for access port %s" % port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100303 vlan = 1
304 if not self._is_port_name_valid(port):
305 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100306 if not (self.port_get_mode(port) == "access"):
307 raise IndexError("Port %s not in access mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100308 regex = re.compile('Access Mode VLAN: (\d+)')
309 self._cli("show interfaces %s switchport" % port)
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000310 for line in self._read_long_output():
Steve McIntyred6759dd2014-08-12 18:10:00 +0100311 match = regex.match(line)
312 if match:
313 vlan = match.group(1)
314 return int(vlan)
315
316 # Get the list of configured VLAN tags for a trunk port
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100317 def port_get_trunk_vlan_list(self, port):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100318 logging.debug("Getting VLANs for trunk port %s" % port)
319 vlans = [ ]
320 if not self._is_port_name_valid(port):
321 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100322 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyree5ea20a2014-10-20 10:39:31 +0100323 raise IndexError("Port %s not in trunk mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100324 regex_start = re.compile('Trunking VLANs Enabled: (.*)')
325 regex_continue = re.compile('\s*(\d.*)')
326 self._cli("show interfaces %s switchport" % port)
327
328 # Horrible parsing work - VLAN list may extend over several lines
329 in_match = False
330 vlan_text = ''
331
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000332 for line in self._read_long_output():
Steve McIntyre3f287882014-08-18 19:02:15 +0100333 if in_match:
334 match = regex_continue.match(line)
335 if match:
336 vlan_text += match.group(1)
337 next
338 else:
339 in_match = False
340 next
341 else:
342 match = regex_start.match(line)
343 if match:
344 vlan_text += match.group(1)
345 in_match = True
346
347 vlans = self._parse_vlan_list(vlan_text)
348
Steve McIntyred6759dd2014-08-12 18:10:00 +0100349 return vlans
350
351 ################################
352 ### Internal functions
353 ################################
354
355 def _login(self, username, password, enablepassword):
356 logging.debug("attempting login with username %s, password %s" % (username, password))
357 self.connection.expect('User Access Verification')
358 if username is not None:
359 self.connection.expect("User Name:")
360 self._cli("%s" % username)
361 if password is not None:
362 self.connection.expect("Password:")
363 self._cli("%s" % password, False)
364 while True:
365 index = self.connection.expect(['User Name:', 'Password:', 'Bad passwords', 'authentication failed', r'(.*)(#|>)'])
366 if index != 4: # Any other means: failed to log in!
367 logging.error("Login failure: index %d\n" % index)
368 logging.error("Login failure: %s\n" % self.connection.match.before)
369 raise IOError
370
371 # else
Steve McIntyre3f287882014-08-18 19:02:15 +0100372 self._prompt_name = self.connection.match.group(1).strip()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100373 if self.connection.match.group(2) == ">":
374 # Need to enter "enable" mode too
375 self._cli("enable")
376 if enablepassword is not None:
377 self.connection.expect("Password:")
378 self._cli("%s" % enablepassword, False)
379 index = self.connection.expect(['Password:', 'Bad passwords', 'authentication failed', r'(.*)(#|>)'])
380 if index != 3: # Any other means: failed to log in!
381 logging.error("Enable password failure: %s\n" % self.connection.match)
382 raise IOError
383 return 0
384
385 def _logout(self):
386 logging.debug("Logging out")
387 self._cli("exit", False)
388
389 def _configure(self):
390 self._cli("configure terminal")
391
392 def _end_configure(self):
393 self._cli("end")
394
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000395 def _read_long_output(self):
Steve McIntyre3f287882014-08-18 19:02:15 +0100396 prompt = self._prompt_name + '#'
Steve McIntyrec68d6d72014-12-24 00:23:36 +0000397 self.connection.expect(prompt)
398 return self.connection.before.split('\r\n')
Steve McIntyred6759dd2014-08-12 18:10:00 +0100399
400 def _get_port_names(self):
401 logging.debug("Grabbing list of ports")
402 interfaces = []
403
404 # Use "Up" or "Down" to only identify lines in the output that
405 # match interfaces that exist
406 regex = re.compile('^\s*([a-zA-Z0-9_/]*).*(connect)(.*)')
407 regex1 = re.compile('.*Not Present.*')
Steve McIntyre6c279b42014-12-23 22:09:04 +0000408 regex2 = re.compile('.*routed.*')
Steve McIntyred6759dd2014-08-12 18:10:00 +0100409
410 self._cli("show interfaces status")
Steve McIntyreac5047e2014-12-24 00:26:40 +0000411 for line in self._read_long_output():
Steve McIntyred6759dd2014-08-12 18:10:00 +0100412 match = regex.match(line)
413 if match:
414 interface = match.group(1)
415 junk = match.group(3)
416 match1 = regex1.match(junk) # Deliberately drop things
417 # marked as "Not Present"
Steve McIntyre6c279b42014-12-23 22:09:04 +0000418 match2 = regex2.match(junk) # Deliberately drop things
419 # marked as "routed"
420 if not match1 and not match2:
Steve McIntyred6759dd2014-08-12 18:10:00 +0100421 interfaces.append(interface)
422 return interfaces
423
Steve McIntyred6759dd2014-08-12 18:10:00 +0100424 def _show_config(self):
425 logging.debug("Grabbing config")
426 self._cli("show running-config")
Steve McIntyreac5047e2014-12-24 00:26:40 +0000427 return self._read_long_output()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100428
429 def _show_clock(self):
430 logging.debug("Grabbing time")
431 self._cli("show clock")
Steve McIntyreac5047e2014-12-24 00:26:40 +0000432 return self._read_long_output()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100433
Steve McIntyred6759dd2014-08-12 18:10:00 +0100434 def _get_systemdata(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100435 logging.debug("Grabbing system sw and hw versions")
Steve McIntyreffb9b5a2014-10-10 16:31:58 +0100436
Steve McIntyred6759dd2014-08-12 18:10:00 +0100437 self._cli("show version")
Steve McIntyreffb9b5a2014-10-10 16:31:58 +0100438 self._systemdata = []
Steve McIntyreac5047e2014-12-24 00:26:40 +0000439 for line in self._read_long_output():
Steve McIntyre3f287882014-08-18 19:02:15 +0100440 self._systemdata.append(line)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100441
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000442 def _parse_vlan_list(self, inputdata):
Steve McIntyre3f287882014-08-18 19:02:15 +0100443 vlans = []
444
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000445 if inputdata == "ALL":
Steve McIntyre3f287882014-08-18 19:02:15 +0100446 return ["ALL"]
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000447 elif inputdata == "NONE":
Steve McIntyre3f287882014-08-18 19:02:15 +0100448 return []
449 else:
450 # Parse the complex list
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000451 groups = inputdata.split(',')
Steve McIntyre3f287882014-08-18 19:02:15 +0100452 for group in groups:
453 subgroups = group.split('-')
454 if len(subgroups) == 1:
455 vlans.append(int(subgroups[0]))
456 elif len(subgroups) == 2:
457 for i in range (int(subgroups[0]), int(subgroups[1]) + 1):
458 vlans.append(i)
459 else:
Steve McIntyre6d5594f2014-12-23 14:28:47 +0000460 logging.debug("Can't parse group \"" + group + "\"")
Steve McIntyre3f287882014-08-18 19:02:15 +0100461
462 return vlans
Steve McIntyred6759dd2014-08-12 18:10:00 +0100463
464 # Wrapper around connection.send - by default, expect() the same
465 # text we've sent, to remove it from the output from the
466 # switch. For the few cases where we don't need that, override
467 # this using echo=False.
468 # Horrible, but seems to work.
469 def _cli(self, text, echo=True):
470 self.connection.send(text + '\r')
471 if echo:
472 self.connection.expect(text)
473
474if __name__ == "__main__":
Steve McIntyre48dc6ae2014-12-23 16:08:19 +0000475
476 import optparse
477
478 switch = 'vlandswitch01'
479 parser = optparse.OptionParser()
480 parser.add_option("--switch",
481 dest = "switch",
482 action = "store",
483 nargs = 1,
484 type = "string",
485 help = "specify switch to connect to for testing",
486 metavar = "<switch>")
487 (opts, args) = parser.parse_args()
488 if opts.switch:
489 switch = opts.switch
490
491 p = CiscoCatalyst(switch, 23, debug=True)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100492 p.switch_connect(None, 'lngvirtual', 'lngenable')
Steve McIntyred6759dd2014-08-12 18:10:00 +0100493
494 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100495 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100496 p._dump_list(buf)
497
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100498 buf = p.vlan_get_name(2)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100499 print "VLAN 2 is named \"%s\"" % buf
500
501 print "Create VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100502 p.vlan_create(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100503
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100504 buf = p.vlan_get_name(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100505 print "VLAN 3 is named \"%s\"" % buf
506
507 print "Set name of VLAN 3 to test333"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100508 p.vlan_set_name(3, "test333")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100509
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100510 buf = p.vlan_get_name(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100511 print "VLAN 3 is named \"%s\"" % buf
512
513 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100514 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100515 p._dump_list(buf)
516
517 print "Destroy VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100518 p.vlan_destroy(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100519
520 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100521 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100522 p._dump_list(buf)
523
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100524 buf = p.port_get_mode("Gi1/0/10")
Steve McIntyreb7adc782014-08-13 00:22:21 +0100525 print "Port Gi1/0/10 is in %s mode" % buf
526
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100527 buf = p.port_get_mode("Gi1/0/11")
Steve McIntyreb7adc782014-08-13 00:22:21 +0100528 print "Port Gi1/0/11 is in %s mode" % buf
Steve McIntyred6759dd2014-08-12 18:10:00 +0100529
Steve McIntyre9936d002014-10-01 15:54:10 +0100530 # Test access stuff
531 print "Set Gi1/0/9 to access mode"
532 p.port_set_mode("Gi1/0/9", "access")
Steve McIntyre3f287882014-08-18 19:02:15 +0100533
534 print "Move Gi1/0/9 to VLAN 4"
Steve McIntyre9936d002014-10-01 15:54:10 +0100535 p.port_set_access_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100536
Steve McIntyre9936d002014-10-01 15:54:10 +0100537 buf = p.port_get_access_vlan("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100538 print "Read from switch: Gi1/0/9 is on VLAN %s" % buf
539
540 print "Move Gi1/0/9 back to VLAN 1"
Steve McIntyre9936d002014-10-01 15:54:10 +0100541 p.port_set_access_vlan("Gi1/0/9", 1)
Steve McIntyre3f287882014-08-18 19:02:15 +0100542
Steve McIntyre9936d002014-10-01 15:54:10 +0100543 # Test access stuff
Steve McIntyre3f287882014-08-18 19:02:15 +0100544 print "Set Gi1/0/9 to trunk mode"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100545 p.port_set_mode("Gi1/0/9", "trunk")
Steve McIntyre3f287882014-08-18 19:02:15 +0100546 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100547 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100548 p._dump_list(buf)
549 print "Add Gi1/0/9 to VLAN 2"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100550 p.port_add_trunk_to_vlan("Gi1/0/9", 2)
Steve McIntyre3f287882014-08-18 19:02:15 +0100551 print "Add Gi1/0/9 to VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100552 p.port_add_trunk_to_vlan("Gi1/0/9", 3)
Steve McIntyre3f287882014-08-18 19:02:15 +0100553 print "Add Gi1/0/9 to VLAN 4"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100554 p.port_add_trunk_to_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100555 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100556 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100557 p._dump_list(buf)
558
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100559 p.port_remove_trunk_from_vlan("Gi1/0/9", 3)
560 p.port_remove_trunk_from_vlan("Gi1/0/9", 3)
561 p.port_remove_trunk_from_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100562 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100563 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100564 p._dump_list(buf)
565
Steve McIntyre7460d972014-12-23 14:45:30 +0000566# print 'Restarting switch, to explicitly reset config'
567# p.switch_restart()
Steve McIntyre3f287882014-08-18 19:02:15 +0100568
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100569# p.switch_save_running_config()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100570
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100571# p.switch_disconnect()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100572# p._show_config()