blob: b1f3d2c2d16df6d7604ee8cc159bbfd9b37fb1ea [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
41 logfile = sys.stderr
42 logfile = None
43
44 def __init__(self, switch_hostname, switch_telnetport=23):
45 self.exec_string = "/usr/bin/telnet %s %d" % (switch_hostname, switch_telnetport)
46
47 ################################
48 ### Switch-level API functions
49 ################################
50
51 # Connect to the switch and log in
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010052 def switch_connect(self, username, password, enablepassword):
Steve McIntyred6759dd2014-08-12 18:10:00 +010053 logging.debug("Connecting to Switch with: %s" % self.exec_string)
54 self.connection = pexpect.spawn(self.exec_string, logfile = self.logfile)
55 self._login(username, password, enablepassword)
56
57 # Try to avoid paged output
Steve McIntyre2b4c07b2014-12-22 16:10:04 +000058 self.connection.setwinsize(132, 1000)
Steve McIntyred6759dd2014-08-12 18:10:00 +010059
60 # And grab details about the switch. in case we need it
Steve McIntyre3f287882014-08-18 19:02:15 +010061 self._get_systemdata()
Steve McIntyred6759dd2014-08-12 18:10:00 +010062
63 # And also validate them - make sure we're driving a switch of
64 # the correct model! Also store the serial number
65 descr_regex = re.compile('^cisco\s+(\S+)')
66 sn_regex = re.compile('System serial number\s+:\s+(\S+)')
67 descr = ""
68
Steve McIntyre3f287882014-08-18 19:02:15 +010069 for line in self._systemdata:
Steve McIntyred6759dd2014-08-12 18:10:00 +010070 match = descr_regex.match(line)
71 if match:
72 descr = match.group(1)
73 match = sn_regex.match(line)
74 if match:
75 self.serial_number = match.group(1)
76
Steve McIntyre6d5594f2014-12-23 14:28:47 +000077 logging.debug("serial number is %s" % self.serial_number)
78 logging.debug("system description is %s" % descr)
Steve McIntyred6759dd2014-08-12 18:10:00 +010079
Steve McIntyre3f287882014-08-18 19:02:15 +010080 if not self._expected_descr_re.match(descr):
Steve McIntyred6759dd2014-08-12 18:10:00 +010081 raise IOError("Switch %s not recognised by this driver: abort" % descr)
82
83 # Now build a list of our ports, for later sanity checking
Steve McIntyre3f287882014-08-18 19:02:15 +010084 self._ports = self._get_port_names()
85 if len(self._ports) < 4:
Steve McIntyred6759dd2014-08-12 18:10:00 +010086 raise IOError("Not enough ports detected - problem!")
87
88 # Log out of the switch and drop the connection and all state
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010089 def switch_disconnect(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +010090 self._logout()
91 logging.debug("Closing connection: %s" % self.connection)
92 self.connection.close(True)
93 del(self)
94
95 # Save the current running config into flash - we want config to
96 # remain across reboots
Steve McIntyre9b09b9d2014-09-24 15:08:10 +010097 def switch_save_running_config(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +010098 self._cli("copy running-config startup-config")
Steve McIntyree1bf11a2014-08-14 17:56:25 +010099 self.connection.expect("startup-config")
100 self._cli("startup-config")
101 self.connection.expect("OK")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100102
Steve McIntyre095b4452014-12-19 17:53:43 +0000103 # Restart the switch - we need to reload config to do a
104 # roll-back. Do NOT save running-config first if the switch asks -
105 # we're trying to dump recent changes, not save them.
106 #
107 # This will also implicitly cause a connection to be closed
108 def switch_restart(self):
109 self._cli("reload")
110 index = self.connection.expect(['has been modified', 'Proceed'])
111 if index == 0:
112 self._cli("n") # No, don't save
113 self.connection.expect("Proceed")
114
115 # Fall through
116 self._cli("y") # Yes, continue to reset
117 self.connection.close(True)
118
Steve McIntyre3f287882014-08-18 19:02:15 +0100119 # List the capabilities of the switch (and driver) - some things
120 # make no sense to abstract. Returns a dict of strings, each one
121 # describing an extra feature that that higher levels may care
122 # about
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100123 def switch_get_capabilities(self):
Steve McIntyre3f287882014-08-18 19:02:15 +0100124 return self._capabilities
Steve McIntyred6759dd2014-08-12 18:10:00 +0100125
126 ################################
127 ### VLAN API functions
128 ################################
129
130 # Create a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100131 def vlan_create(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100132 logging.debug("Creating VLAN %d" % tag)
133 self._configure()
134 self._cli("vlan %d" % tag)
135 self._end_configure()
136
137 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100138 vlans = self.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100139 for vlan in vlans:
140 if vlan == tag:
141 return
142 raise IOError("Failed to create VLAN %d" % tag)
143
144 # Destroy a VLAN with the specified tag
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100145 def vlan_destroy(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100146 logging.debug("Destroying VLAN %d" % tag)
147 self._configure()
148 self._cli("no vlan %d" % tag)
149 self._end_configure()
150
151 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100152 vlans = self.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100153 for vlan in vlans:
154 if vlan == tag:
155 raise IOError("Failed to destroy VLAN %d" % tag)
156
157 # Set the name of a VLAN
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100158 def vlan_set_name(self, tag, name):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100159 logging.debug("Setting name of VLAN %d to %s" % (tag, name))
160 self._configure()
161 self._cli("vlan %d" % tag)
162 self._cli("name %s" % name)
163 self._end_configure()
164
165 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100166 read_name = self.vlan_get_name(tag)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100167 if read_name != name:
168 raise IOError("Failed to set name for VLAN %d (name found is \"%s\", not \"%s\")"
169 % (tag, read_name, name))
170
171 # Get a list of the VLAN tags currently registered on the switch
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100172 def vlan_get_list(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100173 logging.debug("Grabbing list of VLANs")
174 vlans = []
175
176 regex = re.compile('^ *(\d+).*(active)')
177
178 self._cli("show vlan brief")
179 for line in self._read_paged_output():
180 match = regex.match(line)
181 if match:
182 vlans.append(int(match.group(1)))
183 return vlans
184
185 # For a given VLAN tag, ask the switch what the associated name is
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100186 def vlan_get_name(self, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100187 logging.debug("Grabbing the name of VLAN %d" % tag)
188 name = None
189 regex = re.compile('^ *\d+\s+(\S+).*(active)')
190 self._cli("show vlan id %d" % tag)
191 for line in self._read_paged_output():
192 match = regex.match(line)
193 if match:
194 name = match.group(1)
195 name.strip()
196 return name
197
198
199 ################################
200 ### Port API functions
Steve McIntyree1bf11a2014-08-14 17:56:25 +0100201 ################################
Steve McIntyred6759dd2014-08-12 18:10:00 +0100202
Steve McIntyre9936d002014-10-01 15:54:10 +0100203 # Set the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100204 def port_set_mode(self, port, mode):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100205 logging.debug("Setting port %s to %s" % (port, mode))
206 if not self._is_port_mode_valid(mode):
207 raise IndexError("Port mode %s is not allowed" % mode)
208 if not self._is_port_name_valid(port):
209 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100210
Steve McIntyred6759dd2014-08-12 18:10:00 +0100211 self._configure()
212 self._cli("interface %s" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100213 self._cli("switchport mode %s" % mode)
214 if mode == "trunk":
215 self._cli("switchport trunk encapsulation dot1q")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100216 self._end_configure()
217
218 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100219 read_mode = self.port_get_mode(port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100220
Steve McIntyred6759dd2014-08-12 18:10:00 +0100221 if read_mode != mode:
222 raise IOError("Failed to set mode for port %s" % port)
223
Steve McIntyre9936d002014-10-01 15:54:10 +0100224 # Get the mode of a port: access or trunk
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100225 def port_get_mode(self, port):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100226 logging.debug("Getting mode of port %s" % port)
227 mode = ''
228 if not self._is_port_name_valid(port):
229 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100230 regex = re.compile('Administrative Mode: (.*)')
Steve McIntyreb7adc782014-08-13 00:22:21 +0100231 self._cli("show interfaces %s switchport" % port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100232 for line in self._read_paged_output():
233 match = regex.match(line)
234 if match:
235 mode = match.group(1)
Steve McIntyre9936d002014-10-01 15:54:10 +0100236 if mode == 'static access':
237 return 'access'
Steve McIntyre3f287882014-08-18 19:02:15 +0100238 return mode
Steve McIntyred6759dd2014-08-12 18:10:00 +0100239
Steve McIntyre9936d002014-10-01 15:54:10 +0100240 # Set an access port to be in a specified VLAN (tag)
241 def port_set_access_vlan(self, port, tag):
242 logging.debug("Setting access port %s to VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100243 if not self._is_port_name_valid(port):
244 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100245 if not (self.port_get_mode(port) == "access"):
246 raise IndexError("Port %s not in access mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100247
Steve McIntyred6759dd2014-08-12 18:10:00 +0100248 self._configure()
249 self._cli("interface %s" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100250 self._cli("switchport access vlan %d" % tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100251 self._cli("no shutdown")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100252 self._end_configure()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100253
Steve McIntyre3f287882014-08-18 19:02:15 +0100254 # Finally, validate things worked
Steve McIntyre9936d002014-10-01 15:54:10 +0100255 read_vlan = int(self.port_get_access_vlan(port))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100256 if read_vlan != tag:
Steve McIntyre9936d002014-10-01 15:54:10 +0100257 raise IOError("Failed to move access port %d to VLAN %d - got VLAN %d instead"
Steve McIntyred6759dd2014-08-12 18:10:00 +0100258 % (port, tag, read_vlan))
259
Steve McIntyred6759dd2014-08-12 18:10:00 +0100260 # Add a trunk port to a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100261 def port_add_trunk_to_vlan(self, port, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100262 logging.debug("Adding trunk port %s to VLAN %d" % (port, tag))
263 if not self._is_port_name_valid(port):
264 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100265 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100266 raise IndexError("Port %s not in trunk mode" % port)
267 self._configure()
268 self._cli("interface %s" % port)
269 self._cli("switchport trunk allowed vlan add %d" % tag)
270 self._end_configure()
271
272 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100273 read_vlans = self.port_get_trunk_vlan_list(port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100274 for vlan in read_vlans:
Steve McIntyre3f287882014-08-18 19:02:15 +0100275 if vlan == tag or vlan == "ALL":
Steve McIntyred6759dd2014-08-12 18:10:00 +0100276 return
Steve McIntyre3f287882014-08-18 19:02:15 +0100277 raise IOError("Failed to add trunk port %s to VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100278
279 # Remove a trunk port from a specified VLAN (tag)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100280 def port_remove_trunk_from_vlan(self, port, tag):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100281 logging.debug("Removing trunk port %s from VLAN %d" % (port, tag))
282 if not self._is_port_name_valid(port):
283 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100284 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100285 raise IndexError("Port %s not in trunk mode" % port)
286 self._configure()
287 self._cli("interface %s" % port)
288 self._cli("switchport trunk allowed vlan remove %d" % tag)
289 self._end_configure()
290
291 # Validate it happened
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100292 read_vlans = self.port_get_trunk_vlan_list(port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100293 for vlan in read_vlans:
294 if vlan == tag:
Steve McIntyre3f287882014-08-18 19:02:15 +0100295 raise IOError("Failed to remove trunk port %s from VLAN %d" % (port, tag))
Steve McIntyred6759dd2014-08-12 18:10:00 +0100296
Steve McIntyre9936d002014-10-01 15:54:10 +0100297 # Get the configured VLAN tag for an access port (tag)
298 def port_get_access_vlan(self, port):
299 logging.debug("Getting VLAN for access port %s" % port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100300 vlan = 1
301 if not self._is_port_name_valid(port):
302 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9936d002014-10-01 15:54:10 +0100303 if not (self.port_get_mode(port) == "access"):
304 raise IndexError("Port %s not in access mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100305 regex = re.compile('Access Mode VLAN: (\d+)')
306 self._cli("show interfaces %s switchport" % port)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100307 for line in self._read_paged_output():
308 match = regex.match(line)
309 if match:
310 vlan = match.group(1)
311 return int(vlan)
312
313 # Get the list of configured VLAN tags for a trunk port
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100314 def port_get_trunk_vlan_list(self, port):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100315 logging.debug("Getting VLANs for trunk port %s" % port)
316 vlans = [ ]
317 if not self._is_port_name_valid(port):
318 raise IndexError("Port name %s not recognised" % port)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100319 if not (self.port_get_mode(port) == "trunk"):
Steve McIntyree5ea20a2014-10-20 10:39:31 +0100320 raise IndexError("Port %s not in trunk mode" % port)
Steve McIntyre3f287882014-08-18 19:02:15 +0100321 regex_start = re.compile('Trunking VLANs Enabled: (.*)')
322 regex_continue = re.compile('\s*(\d.*)')
323 self._cli("show interfaces %s switchport" % port)
324
325 # Horrible parsing work - VLAN list may extend over several lines
326 in_match = False
327 vlan_text = ''
328
Steve McIntyred6759dd2014-08-12 18:10:00 +0100329 for line in self._read_paged_output():
Steve McIntyre3f287882014-08-18 19:02:15 +0100330 if in_match:
331 match = regex_continue.match(line)
332 if match:
333 vlan_text += match.group(1)
334 next
335 else:
336 in_match = False
337 next
338 else:
339 match = regex_start.match(line)
340 if match:
341 vlan_text += match.group(1)
342 in_match = True
343
344 vlans = self._parse_vlan_list(vlan_text)
345
Steve McIntyred6759dd2014-08-12 18:10:00 +0100346 return vlans
347
348 ################################
349 ### Internal functions
350 ################################
351
352 def _login(self, username, password, enablepassword):
353 logging.debug("attempting login with username %s, password %s" % (username, password))
354 self.connection.expect('User Access Verification')
355 if username is not None:
356 self.connection.expect("User Name:")
357 self._cli("%s" % username)
358 if password is not None:
359 self.connection.expect("Password:")
360 self._cli("%s" % password, False)
361 while True:
362 index = self.connection.expect(['User Name:', 'Password:', 'Bad passwords', 'authentication failed', r'(.*)(#|>)'])
363 if index != 4: # Any other means: failed to log in!
364 logging.error("Login failure: index %d\n" % index)
365 logging.error("Login failure: %s\n" % self.connection.match.before)
366 raise IOError
367
368 # else
Steve McIntyre3f287882014-08-18 19:02:15 +0100369 self._prompt_name = self.connection.match.group(1).strip()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100370 if self.connection.match.group(2) == ">":
371 # Need to enter "enable" mode too
372 self._cli("enable")
373 if enablepassword is not None:
374 self.connection.expect("Password:")
375 self._cli("%s" % enablepassword, False)
376 index = self.connection.expect(['Password:', 'Bad passwords', 'authentication failed', r'(.*)(#|>)'])
377 if index != 3: # Any other means: failed to log in!
378 logging.error("Enable password failure: %s\n" % self.connection.match)
379 raise IOError
380 return 0
381
382 def _logout(self):
383 logging.debug("Logging out")
384 self._cli("exit", False)
385
386 def _configure(self):
387 self._cli("configure terminal")
388
389 def _end_configure(self):
390 self._cli("end")
391
392 def _read_paged_output(self):
393 buf = []
Steve McIntyre3f287882014-08-18 19:02:15 +0100394 prompt = self._prompt_name + '#'
Steve McIntyred6759dd2014-08-12 18:10:00 +0100395 while True:
396 index = self.connection.expect([' -*More-*', prompt])
397 if index == 0: # More: <space>
398 for line in self.connection.before.split('\r\n'):
399 line1 = re.sub('(\x08|\x0D)*', '', line.strip())
400 buf.append(line1)
401 self._cli(' ', False)
402 elif index == 1: # Back to a prompt, says output is finished
403 break
404
405 for line in self.connection.before.split('\r\n'):
406 line1 = re.sub('(\x08|\x0D)*', '', line.strip())
407 buf.append(line1)
408
409 return buf
410
411 def _get_port_names(self):
412 logging.debug("Grabbing list of ports")
413 interfaces = []
414
415 # Use "Up" or "Down" to only identify lines in the output that
416 # match interfaces that exist
417 regex = re.compile('^\s*([a-zA-Z0-9_/]*).*(connect)(.*)')
418 regex1 = re.compile('.*Not Present.*')
419
420 self._cli("show interfaces status")
421 for line in self._read_paged_output():
422 match = regex.match(line)
423 if match:
424 interface = match.group(1)
425 junk = match.group(3)
426 match1 = regex1.match(junk) # Deliberately drop things
427 # marked as "Not Present"
428 if not match1:
429 interfaces.append(interface)
430 return interfaces
431
Steve McIntyred6759dd2014-08-12 18:10:00 +0100432 def _show_config(self):
433 logging.debug("Grabbing config")
434 self._cli("show running-config")
435 return self._read_paged_output()
436
437 def _show_clock(self):
438 logging.debug("Grabbing time")
439 self._cli("show clock")
440 return self._read_paged_output()
441
Steve McIntyred6759dd2014-08-12 18:10:00 +0100442 def _get_systemdata(self):
Steve McIntyred6759dd2014-08-12 18:10:00 +0100443 logging.debug("Grabbing system sw and hw versions")
Steve McIntyreffb9b5a2014-10-10 16:31:58 +0100444
Steve McIntyred6759dd2014-08-12 18:10:00 +0100445 self._cli("show version")
Steve McIntyreffb9b5a2014-10-10 16:31:58 +0100446 self._systemdata = []
Steve McIntyred6759dd2014-08-12 18:10:00 +0100447 for line in self._read_paged_output():
Steve McIntyre3f287882014-08-18 19:02:15 +0100448 self._systemdata.append(line)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100449
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000450 def _parse_vlan_list(self, inputdata):
Steve McIntyre3f287882014-08-18 19:02:15 +0100451 vlans = []
452
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000453 if inputdata == "ALL":
Steve McIntyre3f287882014-08-18 19:02:15 +0100454 return ["ALL"]
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000455 elif inputdata == "NONE":
Steve McIntyre3f287882014-08-18 19:02:15 +0100456 return []
457 else:
458 # Parse the complex list
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000459 groups = inputdata.split(',')
Steve McIntyre3f287882014-08-18 19:02:15 +0100460 for group in groups:
461 subgroups = group.split('-')
462 if len(subgroups) == 1:
463 vlans.append(int(subgroups[0]))
464 elif len(subgroups) == 2:
465 for i in range (int(subgroups[0]), int(subgroups[1]) + 1):
466 vlans.append(i)
467 else:
Steve McIntyre6d5594f2014-12-23 14:28:47 +0000468 logging.debug("Can't parse group \"" + group + "\"")
Steve McIntyre3f287882014-08-18 19:02:15 +0100469
470 return vlans
Steve McIntyred6759dd2014-08-12 18:10:00 +0100471
472 # Wrapper around connection.send - by default, expect() the same
473 # text we've sent, to remove it from the output from the
474 # switch. For the few cases where we don't need that, override
475 # this using echo=False.
476 # Horrible, but seems to work.
477 def _cli(self, text, echo=True):
478 self.connection.send(text + '\r')
479 if echo:
480 self.connection.expect(text)
481
482if __name__ == "__main__":
483 p = CiscoCatalyst('lngswitch02', 23)
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100484 p.switch_connect(None, 'lngvirtual', 'lngenable')
Steve McIntyred6759dd2014-08-12 18:10:00 +0100485
486 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100487 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100488 p._dump_list(buf)
489
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100490 buf = p.vlan_get_name(2)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100491 print "VLAN 2 is named \"%s\"" % buf
492
493 print "Create VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100494 p.vlan_create(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100495
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100496 buf = p.vlan_get_name(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100497 print "VLAN 3 is named \"%s\"" % buf
498
499 print "Set name of VLAN 3 to test333"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100500 p.vlan_set_name(3, "test333")
Steve McIntyred6759dd2014-08-12 18:10:00 +0100501
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100502 buf = p.vlan_get_name(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100503 print "VLAN 3 is named \"%s\"" % buf
504
505 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100506 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100507 p._dump_list(buf)
508
509 print "Destroy VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100510 p.vlan_destroy(3)
Steve McIntyred6759dd2014-08-12 18:10:00 +0100511
512 print "VLANs are:"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100513 buf = p.vlan_get_list()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100514 p._dump_list(buf)
515
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100516 buf = p.port_get_mode("Gi1/0/10")
Steve McIntyreb7adc782014-08-13 00:22:21 +0100517 print "Port Gi1/0/10 is in %s mode" % buf
518
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100519 buf = p.port_get_mode("Gi1/0/11")
Steve McIntyreb7adc782014-08-13 00:22:21 +0100520 print "Port Gi1/0/11 is in %s mode" % buf
Steve McIntyred6759dd2014-08-12 18:10:00 +0100521
Steve McIntyre9936d002014-10-01 15:54:10 +0100522 # Test access stuff
523 print "Set Gi1/0/9 to access mode"
524 p.port_set_mode("Gi1/0/9", "access")
Steve McIntyre3f287882014-08-18 19:02:15 +0100525
526 print "Move Gi1/0/9 to VLAN 4"
Steve McIntyre9936d002014-10-01 15:54:10 +0100527 p.port_set_access_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100528
Steve McIntyre9936d002014-10-01 15:54:10 +0100529 buf = p.port_get_access_vlan("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100530 print "Read from switch: Gi1/0/9 is on VLAN %s" % buf
531
532 print "Move Gi1/0/9 back to VLAN 1"
Steve McIntyre9936d002014-10-01 15:54:10 +0100533 p.port_set_access_vlan("Gi1/0/9", 1)
Steve McIntyre3f287882014-08-18 19:02:15 +0100534
Steve McIntyre9936d002014-10-01 15:54:10 +0100535 # Test access stuff
Steve McIntyre3f287882014-08-18 19:02:15 +0100536 print "Set Gi1/0/9 to trunk mode"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100537 p.port_set_mode("Gi1/0/9", "trunk")
Steve McIntyre3f287882014-08-18 19:02:15 +0100538 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100539 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100540 p._dump_list(buf)
541 print "Add Gi1/0/9 to VLAN 2"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100542 p.port_add_trunk_to_vlan("Gi1/0/9", 2)
Steve McIntyre3f287882014-08-18 19:02:15 +0100543 print "Add Gi1/0/9 to VLAN 3"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100544 p.port_add_trunk_to_vlan("Gi1/0/9", 3)
Steve McIntyre3f287882014-08-18 19:02:15 +0100545 print "Add Gi1/0/9 to VLAN 4"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100546 p.port_add_trunk_to_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100547 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100548 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100549 p._dump_list(buf)
550
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100551 p.port_remove_trunk_from_vlan("Gi1/0/9", 3)
552 p.port_remove_trunk_from_vlan("Gi1/0/9", 3)
553 p.port_remove_trunk_from_vlan("Gi1/0/9", 4)
Steve McIntyre3f287882014-08-18 19:02:15 +0100554 print "Read from switch: which VLANs is Gi1/0/9 on?"
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100555 buf = p.port_get_trunk_vlan_list("Gi1/0/9")
Steve McIntyre3f287882014-08-18 19:02:15 +0100556 p._dump_list(buf)
557
Steve McIntyre095b4452014-12-19 17:53:43 +0000558 print 'Restarting switch, to explicitly reset config'
559 p.switch_restart()
Steve McIntyre3f287882014-08-18 19:02:15 +0100560
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100561# p.switch_save_running_config()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100562
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100563# p.switch_disconnect()
Steve McIntyred6759dd2014-08-12 18:10:00 +0100564# p._show_config()