blob: d1b2a51124ecf72eeb3d35d75627f2801f57c0ba [file] [log] [blame]
Steve McIntyref1c04f92014-12-16 18:23:15 +00001import logging
Steve McIntyre53c7ad92014-12-16 19:21:13 +00002import time
Steve McIntyref1c04f92014-12-16 18:23:15 +00003from errors import CriticalError, InputError, ConfigError, SocketError
4
5class VlanUtil:
6 """VLANd utility functions"""
7
Steve McIntyre5f6f85e2014-12-22 16:42:28 +00008 def get_switch_driver(self, switch_name, config):
Steve McIntyre5fa22652015-04-01 18:01:45 +01009 logging.debug("Trying to find a driver for %s", switch_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +000010 driver = config.switches[switch_name].driver
Steve McIntyre5fa22652015-04-01 18:01:45 +010011 logging.debug("Driver: %s", driver)
Steve McIntyref1c04f92014-12-16 18:23:15 +000012 module = __import__("drivers.%s" % driver, fromlist=[driver])
13 class_ = getattr(module, driver)
Steve McIntyre0f38f0e2015-07-14 15:26:05 +010014 return class_(switch_name, debug = config.switches[switch_name].debug)
Steve McIntyref1c04f92014-12-16 18:23:15 +000015
Steve McIntyre519158e2014-12-23 13:44:44 +000016 def probe_switches(self, state):
17 config = state.config
Steve McIntyree8d80582014-12-23 16:53:39 +000018 ret = {}
Steve McIntyre5f6f85e2014-12-22 16:42:28 +000019 for switch_name in sorted(config.switches):
Steve McIntyre5fa22652015-04-01 18:01:45 +010020 logging.debug("Found switch %s:", switch_name)
Steve McIntyre7cf80982015-02-12 07:03:40 +000021 logging.debug(" Probing...")
Steve McIntyre519158e2014-12-23 13:44:44 +000022
Steve McIntyre4b4ab652014-12-22 17:19:09 +000023 s = self.get_switch_driver(switch_name, config)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +000024 s.switch_connect(config.switches[switch_name].username,
25 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +000026 config.switches[switch_name].enable_password)
Steve McIntyre27d4b582014-12-23 22:51:00 +000027 ret[switch_name] = 'Found %d ports: ' % len(s.switch_get_port_names())
28 for name in s.switch_get_port_names():
29 ret[switch_name] += '%s ' % name
Steve McIntyrea2a8f792014-12-17 17:34:32 +000030 s.switch_disconnect()
Steve McIntyre2ed90f52015-07-21 17:59:52 +010031 del s
Steve McIntyrea2020cb2014-12-23 16:56:40 +000032 return ret
Steve McIntyrec68a18e2014-12-17 16:29:28 +000033
Steve McIntyre091e2ac2014-12-16 19:20:07 +000034 # Simple helper wrapper for all the read-only database queries
Steve McIntyre2150bc22014-12-17 13:13:56 +000035 def perform_db_query(self, state, command, data):
Steve McIntyre7cf80982015-02-12 07:03:40 +000036 logging.debug('perform_db_query')
37 logging.debug(command)
38 logging.debug(data)
Steve McIntyref1c04f92014-12-16 18:23:15 +000039 ret = {}
Steve McIntyre2150bc22014-12-17 13:13:56 +000040 db = state.db
Steve McIntyref1c04f92014-12-16 18:23:15 +000041 try:
Steve McIntyre091e2ac2014-12-16 19:20:07 +000042 if command == 'db.all_switches':
Steve McIntyref1c04f92014-12-16 18:23:15 +000043 ret = db.all_switches()
44 elif command == 'db.all_ports':
45 ret = db.all_ports()
46 elif command == 'db.all_vlans':
47 ret = db.all_vlans()
48 elif command == 'db.get_switch_by_id':
49 ret = db.get_switch_by_id(data['switch_id'])
50 elif command == 'db.get_switch_id_by_name':
51 ret = db.get_switch_id_by_name(data['name'])
52 elif command == 'db.get_switch_name_by_id':
53 ret = db.get_switch_name_by_id(data['switch_id'])
54 elif command == 'db.get_port_by_id':
55 ret = db.get_port_by_id(data['port_id'])
56 elif command == 'db.get_ports_by_switch':
57 ret = db.get_ports_by_switch(data['switch_id'])
58 elif command == 'db.get_port_by_switch_and_name':
59 ret = db.get_port_by_switch_and_name(data['switch_id'], data['name'])
60 elif command == 'db.get_current_vlan_id_by_port':
61 ret = db.get_current_vlan_id_by_port(data['port_id'])
62 elif command == 'db.get_base_vlan_id_by_port':
63 ret = db.get_base_vlan_id_by_port(data['port_id'])
64 elif command == 'db.get_ports_by_current_vlan':
65 ret = db.get_ports_by_current_vlan(data['vlan_id'])
66 elif command == 'db.get_ports_by_base_vlan':
67 ret = db.get_ports_by_base_vlan(data['vlan_id'])
68 elif command == 'db.get_vlan_by_id':
69 ret = db.get_vlan_by_id(data['vlan_id'])
Steve McIntyre65533d72015-01-23 18:01:17 +000070 elif command == 'db.get_vlan_tag_by_id':
71 ret = db.get_vlan_tag_by_id(data['vlan_id'])
Steve McIntyref1c04f92014-12-16 18:23:15 +000072 elif command == 'db.get_vlan_id_by_name':
73 ret = db.get_vlan_id_by_name(data['name'])
74 elif command == 'db.get_vlan_id_by_tag':
Steve McIntyre07946c22014-12-17 13:14:15 +000075 ret = db.get_vlan_id_by_tag(data['tag'])
Steve McIntyref1c04f92014-12-16 18:23:15 +000076 elif command == 'db.get_vlan_name_by_id':
77 ret = db.get_vlan_name_by_id(data['vlan_id'])
78 else:
Steve McIntyree749fef2014-12-17 16:35:45 +000079 raise InputError("Unknown db_query command \"%s\"" % command)
Steve McIntyref1c04f92014-12-16 18:23:15 +000080
Steve McIntyre5da37fa2014-12-17 13:14:44 +000081 except InputError:
82 raise
83
Steve McIntyre798af842014-12-23 22:29:46 +000084# except:
85# raise InputError("Invalid input in query")
Steve McIntyref1c04f92014-12-16 18:23:15 +000086
87 return ret
88
Steve McIntyre53c7ad92014-12-16 19:21:13 +000089 # Simple helper wrapper for all the read-only daemon state queries
90 def perform_daemon_query(self, state, command, data):
Steve McIntyre7cf80982015-02-12 07:03:40 +000091 logging.debug('perform_daemon_query')
92 logging.debug(command)
93 logging.debug(data)
Steve McIntyre53c7ad92014-12-16 19:21:13 +000094 ret = {}
95 try:
96 if command == 'daemon.status':
97 # data ignored
98 ret['running'] = 'ok'
99 elif command == 'daemon.version':
100 # data ignored
101 ret['version'] = state.version
102 elif command == 'daemon.statistics':
103 ret['uptime'] = time.time() - state.starttime
Steve McIntyre88b79df2014-12-23 13:45:08 +0000104 elif command == 'daemon.probe_switches':
105 ret = self.probe_switches(state)
Steve McIntyre06fe6422015-01-23 17:55:43 +0000106 elif command == 'daemon.shutdown':
107 # data ignored
108 ret['shutdown'] = 'Shutting down'
109 state.running = False
Steve McIntyre53c7ad92014-12-16 19:21:13 +0000110 else:
Steve McIntyree749fef2014-12-17 16:35:45 +0000111 raise InputError("Unknown daemon_query command \"%s\"" % command)
Steve McIntyre53c7ad92014-12-16 19:21:13 +0000112
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000113 except InputError:
114 raise
115
Steve McIntyre798af842014-12-23 22:29:46 +0000116# except:
117# raise InputError("Invalid input in query")
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000118
119 return ret
120
Steve McIntyree749fef2014-12-17 16:35:45 +0000121 # Helper wrapper for API functions modifying database state only
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000122 def perform_db_update(self, state, command, data):
Steve McIntyre7cf80982015-02-12 07:03:40 +0000123 logging.debug('perform_db_update')
124 logging.debug(command)
125 logging.debug(data)
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000126 ret = {}
127 db = state.db
128 try:
129 if command == 'db.create_switch':
130 ret = db.create_switch(data['name'])
131 elif command == 'db.create_port':
132 ret = db.create_port(data['switch_id'], data['name'],
Steve McIntyrefefdbb42014-12-22 16:14:28 +0000133 state.default_vlan_id,
134 state.default_vlan_id)
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000135 elif command == 'db.delete_switch':
136 ret = db.delete_switch(data['switch_id'])
137 elif command == 'db.delete_port':
138 ret = db.delete_port(data['port_id'])
139 elif command == 'db.set_port_is_locked':
140 ret = db.set_port_is_locked(data['port_id'], data['is_locked'])
141 elif command == 'db.set_base_vlan':
142 ret = db.set_base_vlan(data['port_id'], data['base_vlan_id'])
143 else:
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000144 raise InputError("Unknown db_update command \"%s\"" % command)
145
146 except InputError:
147 raise
148
Steve McIntyre798af842014-12-23 22:29:46 +0000149# except:
150# raise InputError("Invalid input in query")
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000151
152 return ret
153
154 # Helper wrapper for API functions that modify both database state
155 # and on-switch VLAN state
156 def perform_vlan_update(self, state, command, data):
Steve McIntyre7cf80982015-02-12 07:03:40 +0000157 logging.debug('perform_vlan_update')
158 logging.debug(command)
159 logging.debug(data)
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000160 ret = {}
Steve McIntyre4b4ab652014-12-22 17:19:09 +0000161
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000162 try:
163 # All of these are complex commands, so call helpers
164 # rather than inline the code here
165 if command == 'api.create_vlan':
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000166 ret = self.create_vlan(state, data['name'], int(data['tag']), data['is_base_vlan'])
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000167 elif command == 'api.delete_vlan':
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000168 ret = self.delete_vlan(state, int(data['vlan_id']))
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000169 elif command == 'api.set_port_mode':
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000170 ret = self.set_port_mode(state, int(data['port_id']), data['mode'])
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000171 elif command == 'api.set_current_vlan':
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000172 ret = self.set_current_vlan(state, int(data['port_id']), int(data['vlan_id']))
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000173 elif command == 'api.restore_base_vlan':
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000174 ret = self.restore_base_vlan(state, int(data['port_id']))
175 elif command == 'api.auto_import_switch':
176 ret = self.auto_import_switch(state, data['switch'])
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000177 else:
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000178 raise InputError("Unknown query command \"%s\"" % command)
179
Steve McIntyre3256b182014-12-19 15:38:15 +0000180 except InputError as e:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100181 logging.debug('got error %s', e)
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000182 raise
183
Steve McIntyre798af842014-12-23 22:29:46 +0000184# except:
185# raise InputError("Invalid input in query")
Steve McIntyre53c7ad92014-12-16 19:21:13 +0000186
187 return ret
188
189
Steve McIntyre3256b182014-12-19 15:38:15 +0000190 # Complex call
191 # 1. create the VLAN in the DB
192 # 2. Iterate through all switches:
Steve McIntyre1ab8b872014-12-19 18:37:00 +0000193 # a. Create the VLAN
194 # b. Add the VLAN to all trunk ports (if needed)
195 # 3. If all went OK, save config on all the switches
Steve McIntyre3256b182014-12-19 15:38:15 +0000196 #
197 # The VLAN may already exist on some of the switches, that's
Steve McIntyre153157d2014-12-19 18:05:20 +0000198 # fine. If things fail, we attempt to roll back by rebooting
199 # switches then removing the VLAN in the DB.
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000200 def create_vlan(self, state, name, tag, is_base_vlan):
Steve McIntyre3256b182014-12-19 15:38:15 +0000201
Steve McIntyre7cf80982015-02-12 07:03:40 +0000202 logging.debug('create_vlan')
Steve McIntyre3256b182014-12-19 15:38:15 +0000203 db = state.db
204 config = state.config
205
Steve McIntyre6b8d3862015-08-03 19:28:25 +0100206 # Check for tag == -1, i.e. use the next available tag
207 if tag == -1:
208 tag = db.find_lowest_unused_vlan_tag()
209 logging.debug('create_vlan called with a tag of -1, found first unused tag %d', tag)
210
Steve McIntyre3256b182014-12-19 15:38:15 +0000211 # 1. Database record first
212 try:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100213 logging.debug('Adding DB record first: name %s, tag %d, is_base_vlan %d', name, tag, is_base_vlan)
Steve McIntyre3256b182014-12-19 15:38:15 +0000214 vlan_id = db.create_vlan(name, tag, is_base_vlan)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100215 logging.debug('Added VLAN tag %d, name %s to the database, created VLAN ID %d', tag, name, vlan_id)
Steve McIntyre3256b182014-12-19 15:38:15 +0000216 except InputError:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000217 logging.debug('DB creation failed')
Steve McIntyre3256b182014-12-19 15:38:15 +0000218 raise
219
Steve McIntyre153157d2014-12-19 18:05:20 +0000220 # Keep track of which switches we've configured, for later use
221 switches_done = []
222
Steve McIntyre3256b182014-12-19 15:38:15 +0000223 # 2. Now the switches
224 try:
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000225 for switch in db.all_switches():
Steve McIntyre3256b182014-12-19 15:38:15 +0000226 trunk_ports = []
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000227 switch_name = switch.name
Steve McIntyre3256b182014-12-19 15:38:15 +0000228 try:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100229 logging.debug('Adding new VLAN to switch %s', switch_name)
Steve McIntyre3256b182014-12-19 15:38:15 +0000230 # Get the right driver
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000231 s = self.get_switch_driver(switch_name, config)
232 s.switch_connect(config.switches[switch_name].username,
233 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000234 config.switches[switch_name].enable_password)
Steve McIntyre3256b182014-12-19 15:38:15 +0000235
Steve McIntyre153157d2014-12-19 18:05:20 +0000236 # Mark this switch as one we've touched, for
237 # either config saving or rollback below
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000238 switches_done.append(switch_name)
Steve McIntyre153157d2014-12-19 18:05:20 +0000239
Steve McIntyre3256b182014-12-19 15:38:15 +0000240 # 2a. Create the VLAN on the switch
241 s.vlan_create(tag)
242 s.vlan_set_name(tag, name)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100243 logging.debug('Added VLAN tag %d, name %s to switch %s', tag, name, switch_name)
Steve McIntyre3256b182014-12-19 15:38:15 +0000244
245 # 2b. Do we need to worry about trunk ports on this switch?
246 if 'TrunkWildCardVlans' in s.switch_get_capabilities():
Steve McIntyre7cf80982015-02-12 07:03:40 +0000247 logging.debug('This switch does not need special trunk port handling')
Steve McIntyre3256b182014-12-19 15:38:15 +0000248 else:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000249 logging.debug('This switch needs special trunk port handling')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000250 trunk_ports = db.get_trunk_port_names_by_switch(switch.switch_id)
Steve McIntyre3256b182014-12-19 15:38:15 +0000251 if trunk_ports is None:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000252 logging.debug("But it has no trunk ports defined")
Steve McIntyre3256b182014-12-19 15:38:15 +0000253 trunk_ports = []
254 else:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100255 logging.debug('Found %d trunk_ports that need adjusting', len(trunk_ports))
Steve McIntyre3256b182014-12-19 15:38:15 +0000256
257 # Modify any trunk ports as needed
258 for port in trunk_ports:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100259 logging.debug('Added VLAN tag %d, name %s to switch %s', tag, name, switch_name)
Steve McIntyre3256b182014-12-19 15:38:15 +0000260 s.port_add_trunk_to_vlan(port, tag)
261
Steve McIntyre3256b182014-12-19 15:38:15 +0000262 # And now we're done with this switch
263 s.switch_disconnect()
264 del s
265
266 except IOError:
267 raise
Steve McIntyreb826fc72015-07-27 17:57:40 +0100268
Steve McIntyre3256b182014-12-19 15:38:15 +0000269 except IOError:
Steve McIntyre153157d2014-12-19 18:05:20 +0000270 # Bugger. Looks like one of the switch calls above
271 # failed. To undo the changes safely, we'll need to reset
272 # all the switches we managed to configure. This could
273 # take some time!
Steve McIntyre38a24e52015-07-21 17:54:58 +0100274 logging.error('create_vlan failed, resetting all switches to recover')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000275 for switch_name in switches_done:
276 s = self.get_switch_driver(switch_name, config)
277 s.switch_connect(config.switches[switch_name].username,
278 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000279 config.switches[switch_name].enable_password)
Steve McIntyre153157d2014-12-19 18:05:20 +0000280 s.switch_restart() # Will implicitly also close the connection
281 del s
282
Steve McIntyre3256b182014-12-19 15:38:15 +0000283 # Undo the database change
Steve McIntyre7cf80982015-02-12 07:03:40 +0000284 logging.debug('Switch access failed. Deleting the new VLAN entry in the database')
Steve McIntyre3256b182014-12-19 15:38:15 +0000285 db.delete_vlan(vlan_id)
286 raise
287
Steve McIntyre153157d2014-12-19 18:05:20 +0000288 # If we've got this far, things were successful. Save config
289 # on all the switches so it will persist across reboots
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000290 for switch_name in switches_done:
291 s = self.get_switch_driver(switch_name, config)
292 s.switch_connect(config.switches[switch_name].username,
293 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000294 config.switches[switch_name].enable_password)
Steve McIntyre153157d2014-12-19 18:05:20 +0000295 s.switch_save_running_config()
296 s.switch_disconnect()
297 del s
298
Steve McIntyre6b8d3862015-08-03 19:28:25 +0100299 return (vlan_id, tag) # If we're successful
Steve McIntyre3256b182014-12-19 15:38:15 +0000300
Steve McIntyrefeb64522014-12-19 18:53:02 +0000301 # Complex call
302 # 1. Check in the DB if there are any ports on the VLAN. Bail if so
303 # 2. Iterate through all switches:
304 # a. Remove the VLAN from all trunk ports (if needed)
305 # b. Remove the VLAN
306 # 3. If all went OK, save config on the switches
307 # 4. Remove the VLAN in the DB
308 #
309 # If things fail, we attempt to roll back by rebooting switches.
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000310 def delete_vlan(self, state, vlan_id):
Steve McIntyrefeb64522014-12-19 18:53:02 +0000311
Steve McIntyre7cf80982015-02-12 07:03:40 +0000312 logging.debug('delete_vlan')
Steve McIntyrefeb64522014-12-19 18:53:02 +0000313 db = state.db
314 config = state.config
315
Steve McIntyrefeb64522014-12-19 18:53:02 +0000316 # 1. Check for database records first
Steve McIntyre5fa22652015-04-01 18:01:45 +0100317 logging.debug('Checking for ports using VLAN ID %d', vlan_id)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000318 vlan = db.get_vlan_by_id(vlan_id)
319 if vlan is None:
320 raise InputError("VLAN ID %d does not exist" % vlan_id)
321 vlan_tag = vlan.tag
322 ports = db.get_ports_by_current_vlan(vlan_id)
323 if ports is not None:
324 raise InputError("Cannot delete VLAN ID %d when it still has %d ports" %
325 (vlan_id, len(ports)))
326 ports = db.get_ports_by_base_vlan(vlan_id)
327 if ports is not None:
328 raise InputError("Cannot delete VLAN ID %d when it still has %d ports" %
329 (vlan_id, len(ports)))
330
331 # Keep track of which switches we've configured, for later use
332 switches_done = []
333
334 # 2. Now the switches
335 try:
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000336 for switch in db.all_switches():
337 switch_name = switch.name
Steve McIntyrefeb64522014-12-19 18:53:02 +0000338 trunk_ports = []
339 try:
340 # Get the right driver
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000341 s = self.get_switch_driver(switch_name, config)
342 s.switch_connect(config.switches[switch_name].username,
343 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000344 config.switches[switch_name].enable_password)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000345
346 # Mark this switch as one we've touched, for
347 # either config saving or rollback below
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000348 switches_done.append(switch_name)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000349
350 # 2a. Do we need to worry about trunk ports on this switch?
351 if 'TrunkWildCardVlans' in s.switch_get_capabilities():
Steve McIntyre7cf80982015-02-12 07:03:40 +0000352 logging.debug('This switch does not need special trunk port handling')
Steve McIntyrefeb64522014-12-19 18:53:02 +0000353 else:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000354 logging.debug('This switch needs special trunk port handling')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000355 trunk_ports = db.get_trunk_port_names_by_switch(switch.switch_id)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000356 if trunk_ports is None:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000357 logging.debug("But it has no trunk ports defined")
Steve McIntyrefeb64522014-12-19 18:53:02 +0000358 trunk_ports = []
359 else:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100360 logging.debug('Found %d trunk_ports that need adjusting', len(trunk_ports))
Steve McIntyrefeb64522014-12-19 18:53:02 +0000361
362 # Modify any trunk ports as needed
363 for port in trunk_ports:
Steve McIntyre4b4ab652014-12-22 17:19:09 +0000364 s.port_remove_trunk_from_vlan(port, vlan_tag)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100365 logging.debug('Removed VLAN tag %d from switch %s port %s', vlan_tag, switch_name, port)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000366
367 # 2b. Remove the VLAN from the switch
Steve McIntyre5fa22652015-04-01 18:01:45 +0100368 logging.debug('Removing VLAN tag %d from switch %s', vlan_tag, switch_name)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000369 s.vlan_destroy(vlan_tag)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100370 logging.debug('Removed VLAN tag %d from switch %s', vlan_tag, switch_name)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000371
372 # And now we're done with this switch
373 s.switch_disconnect()
374 del s
375
376 except IOError:
377 raise
378
379 except IOError:
380 # Bugger. Looks like one of the switch calls above
381 # failed. To undo the changes safely, we'll need to reset
382 # all the switches we managed to configure. This could
383 # take some time!
Steve McIntyre38a24e52015-07-21 17:54:58 +0100384 logging.error('delete_vlan failed, resetting all switches to recover')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000385 for switch_name in switches_done:
386 s = self.get_switch_driver(switch_name, config)
387 s.switch_connect(config.switches[switch_name].username,
388 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000389 config.switches[switch_name].enable_password)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000390 s.switch_restart() # Will implicitly also close the connection
391 del s
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000392 raise
Steve McIntyrefeb64522014-12-19 18:53:02 +0000393
394 # 3. If we've got this far, things were successful. Save
395 # config on all the switches so it will persist across reboots
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000396 for switch_name in switches_done:
397 s = self.get_switch_driver(switch_name, config)
398 s.switch_connect(config.switches[switch_name].username,
399 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000400 config.switches[switch_name].enable_password)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000401 s.switch_save_running_config()
402 s.switch_disconnect()
403 del s
404
405 # 4. Finally, remove the VLAN in the DB
406 try:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100407 logging.debug('Removing DB record: VLAN ID %d', vlan_id)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000408 vlan_id = db.delete_vlan(vlan_id)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100409 logging.debug('Removed VLAN ID %d from the database OK', vlan_id)
Steve McIntyrefeb64522014-12-19 18:53:02 +0000410 except InputError:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000411 logging.debug('DB deletion failed')
Steve McIntyrefeb64522014-12-19 18:53:02 +0000412 raise
413
414 return vlan_id # If we're successful
415
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000416 # Complex call, depends on existing state a lot
417 # 1. Check validity of inputs
418 # 2. Switch mode and other config on the port.
419 # a. If switching trunk->access, remove all trunk VLANs from it
420 # (if needed) and switch back to the base VLAN for the
421 # port. Next, switch to access mode.
422 # b. If switching access->trunk, switch back to the base VLAN
423 # for the port. Next, switch mode. Then add all trunk VLANs
424 # to it (if needed)
425 # 3. If all went OK, save config on the switch
426 # 4. Change details of the port in the DB
427 #
428 # If things fail, we attempt to roll back by rebooting the switch
Steve McIntyre4b4ab652014-12-22 17:19:09 +0000429 def set_port_mode(self, state, port_id, mode):
Steve McIntyrefeb64522014-12-19 18:53:02 +0000430
Steve McIntyre7cf80982015-02-12 07:03:40 +0000431 logging.debug('set_port_mode')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000432 db = state.db
433 config = state.config
434
435 # 1. Sanity-check inputs
Steve McIntyre5b0de002015-01-23 18:05:13 +0000436 if mode != 'access' and mode != 'trunk':
437 raise InputError("Port mode '%s' is not a valid option: try 'access' or 'trunk'" % mode)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000438 port = db.get_port_by_id(port_id)
439 if port is None:
440 raise InputError("Port ID %d does not exist" % port_id)
Steve McIntyre28114092015-02-13 03:04:40 +0000441 if port.is_locked:
442 raise InputError("Port ID %d is locked" % port_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000443 if mode == 'trunk' and port.is_trunk:
Steve McIntyre3aff7da2015-02-13 04:00:11 +0000444 raise InputError("Port ID %d is already in trunk mode" % port_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000445 if mode == 'access' and not port.is_trunk:
Steve McIntyre3aff7da2015-02-13 04:00:11 +0000446 raise InputError("Port ID %d is already in access mode" % port_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000447 base_vlan_tag = db.get_vlan_tag_by_id(port.base_vlan_id)
448
449 # Get the right driver
450 switch_name = db.get_switch_name_by_id(port.switch_id)
451 s = self.get_switch_driver(switch_name, config)
452
453 # 2. Now start configuring the switch
454 try:
455 s.switch_connect(config.switches[switch_name].username,
456 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000457 config.switches[switch_name].enable_password)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000458 except:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100459 logging.debug('Failed to talk to switch %s!', switch_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000460 raise
461
462 try:
463 if port.is_trunk:
464 # 2a. We're going from a trunk port to an access port
465 if 'TrunkWildCardVlans' in s.switch_get_capabilities():
Steve McIntyre7cf80982015-02-12 07:03:40 +0000466 logging.debug('This switch does not need special trunk port handling')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000467 else:
Steve McIntyre7cf80982015-02-12 07:03:40 +0000468 logging.debug('This switch needs special trunk port handling')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000469 vlans = s.port_get_trunk_vlan_list(port.name)
470 if vlans is None:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100471 logging.debug("But it has no VLANs defined on port %s", port.name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000472 vlans = []
473 else:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100474 logging.debug('Found %d vlans that may need dropping on port %s', len(vlans), port.name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000475
476 for vlan in vlans:
Steve McIntyre97f5e872015-01-23 18:07:05 +0000477 if vlan != state.config.vland.default_vlan_tag:
478 s.port_remove_trunk_from_vlan(port.name, vlan)
Steve McIntyref903b692015-07-09 18:29:05 +0100479
480 s.port_set_mode(port.name, "access")
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000481
482 else:
483 # 2b. We're going from an access port to a trunk port
484 s.port_set_access_vlan(port.name, base_vlan_tag)
485 s.port_set_mode(port.name, "trunk")
486 if 'TrunkWildCardVlans' in s.switch_get_capabilities():
Steve McIntyre7cf80982015-02-12 07:03:40 +0000487 logging.debug('This switch does not need special trunk port handling')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000488 else:
489 vlans = db.all_vlans()
490 for vlan in vlans:
491 s.port_add_trunk_to_vlan(port.name, vlan.tag)
492
493 except IOError:
Steve McIntyre38a24e52015-07-21 17:54:58 +0100494 logging.error('set_port_mode failed, resetting switch to recover')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000495 # Bugger. Looks like one of the switch calls above
496 # failed. To undo the changes safely, we'll need to reset
497 # all the config on this switch
498 s.switch_restart() # Will implicitly also close the connection
499 del s
500 raise
501
502 # 3. All seems to have worked so far!
503 s.switch_save_running_config()
504 s.switch_disconnect()
505 del s
506
507 # 4. And update the DB
508 db.set_port_mode(port_id, mode)
509
510 return port_id # If we're successful
511
512 # Complex call, updating both DB and switch state
513 # 1. Check validity of inputs
514 # 2. Update the port config on the switch
515 # 3. If all went OK, save config on the switch
516 # 4. Change details of the port in the DB
517 #
518 # If things fail, we attempt to roll back by rebooting the switch
519 def set_current_vlan(self, state, port_id, vlan_id):
520
Steve McIntyre7cf80982015-02-12 07:03:40 +0000521 logging.debug('set_current_vlan')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000522 db = state.db
523 config = state.config
524
525 # 1. Sanity checks!
526 port = db.get_port_by_id(port_id)
527 if port is None:
528 raise InputError("Port ID %d does not exist" % port_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000529 if port.is_locked:
530 raise InputError("Port ID %d is locked" % port_id)
Steve McIntyre3bb7bbd2015-02-13 03:06:01 +0000531 if port.is_trunk:
532 raise InputError("Port ID %d is not an access port" % port_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000533
534 vlan = db.get_vlan_by_id(vlan_id)
535 if vlan is None:
536 raise InputError("VLAN ID %d does not exist" % vlan_id)
537
538 # Get the right driver
539 switch_name = db.get_switch_name_by_id(port.switch_id)
540 s = self.get_switch_driver(switch_name, config)
541
542 # 2. Now start configuring the switch
543 try:
544 s.switch_connect(config.switches[switch_name].username,
545 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000546 config.switches[switch_name].enable_password)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000547 except:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100548 logging.debug('Failed to talk to switch %s!', switch_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000549 raise
550
551 try:
552 s.port_set_access_vlan(port.name, vlan.tag)
553 except IOError:
Steve McIntyre38a24e52015-07-21 17:54:58 +0100554 logging.error('set_current_vlan failed, resetting switch to recover')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000555 # Bugger. Looks like one of the switch calls above
556 # failed. To undo the changes safely, we'll need to reset
557 # all the config on this switch
558 s.switch_restart() # Will implicitly also close the connection
559 del s
560 raise
561
562 # 3. All seems to have worked so far!
563 s.switch_save_running_config()
564 s.switch_disconnect()
565 del s
566
567 # 4. And update the DB
568 db.set_current_vlan(port_id, vlan_id)
569
570 return port_id # If we're successful
571
572 # Complex call, updating both DB and switch state
573 # 1. Check validity of input
574 # 2. Update the port config on the switch
575 # 3. If all went OK, save config on the switch
576 # 4. Change details of the port in the DB
577 #
578 # If things fail, we attempt to roll back by rebooting the switch
579 def restore_base_vlan(self, state, port_id):
580
Steve McIntyre7cf80982015-02-12 07:03:40 +0000581 logging.debug('restore_base_vlan')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000582 db = state.db
583 config = state.config
584
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000585 # 1. Sanity checks!
586 port = db.get_port_by_id(port_id)
587 if port is None:
588 raise InputError("Port ID %d does not exist" % port_id)
589 if port.is_trunk:
590 raise InputError("Port ID %d is not an access port" % port_id)
591 if port.is_locked:
592 raise InputError("Port ID %d is locked" % port_id)
593
594 # Bail out early if we're *already* on the base VLAN. This is
595 # not an error
596 if port.current_vlan_id == port.base_vlan_id:
597 return port_id
598
599 vlan = db.get_vlan_by_id(port.base_vlan_id)
600
601 # Get the right driver
602 switch_name = db.get_switch_name_by_id(port.switch_id)
603 s = self.get_switch_driver(switch_name, config)
604
605 # 2. Now start configuring the switch
606 try:
607 s.switch_connect(config.switches[switch_name].username,
608 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000609 config.switches[switch_name].enable_password)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000610 except:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100611 logging.debug('Failed to talk to switch %s!', switch_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000612 raise
613
614 try:
615 s.port_set_access_vlan(port.name, vlan.tag)
616 except IOError:
Steve McIntyre38a24e52015-07-21 17:54:58 +0100617 logging.error('restore_base_vlan failed, resetting switch to recover')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000618 # Bugger. Looks like one of the switch calls above
619 # failed. To undo the changes safely, we'll need to reset
620 # all the config on this switch
621 s.switch_restart() # Will implicitly also close the connection
622 del s
623 raise
624
625 # 3. All seems to have worked so far!
626 s.switch_save_running_config()
627 s.switch_disconnect()
628 del s
629
630 # 4. And update the DB
631 db.set_current_vlan(port_id, port.base_vlan_id)
632
633 return port_id # If we're successful
634
635 # Complex call, updating both DB and switch state
636 # * Check validity of input
637 # * Read all the config from the switch (switch, ports, VLANs)
638 # * Create initial DB entries to match each of those
639 # * Merge VLANs across all switches
640 # * Set up ports appropriately
641 #
642 def auto_import_switch(self, state, switch_name):
643
Steve McIntyre7cf80982015-02-12 07:03:40 +0000644 logging.debug('auto_import_switch')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000645 db = state.db
646 config = state.config
647
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000648 port_vlans = {}
649
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000650 # 1. Sanity checks!
651 switch_id = db.get_switch_id_by_name(switch_name)
652 if switch_id is not None:
653 raise InputError("Switch name %s already exists in the DB (ID %d)" % (switch_name, switch_id))
654
Steve McIntyre4b4ab652014-12-22 17:19:09 +0000655 if not switch_name in config.switches:
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000656 raise InputError("Switch name %s not defined in config" % switch_name)
657
658 # 2. Now start reading config from the switch
659 try:
660 s = self.get_switch_driver(switch_name, config)
661 s.switch_connect(config.switches[switch_name].username,
662 config.switches[switch_name].password,
Steve McIntyre3b655af2014-12-23 13:43:19 +0000663 config.switches[switch_name].enable_password)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000664 except:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100665 logging.debug('Failed to talk to switch %s!', switch_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000666 raise
667
668 # DON'T create the switch record in the DB first - we'll want
Steve McIntyrefc511242014-12-23 22:28:30 +0000669 # to create VLANs on *other* switches, and it's easier to do
670 # that before we've added our new switch
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000671
672 new_vlan_tags = []
673
674 # Grab the VLANs defined on this switch
675 vlan_tags = s.vlan_get_list()
Steve McIntyrefc511242014-12-23 22:28:30 +0000676
Steve McIntyre5fa22652015-04-01 18:01:45 +0100677 logging.debug(' found %d vlans on the switch', len(vlan_tags))
Steve McIntyrefc511242014-12-23 22:28:30 +0000678
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000679 for vlan_tag in vlan_tags:
680 vlan_name = s.vlan_get_name(vlan_tag)
681
682 # If a VLAN is already in the database, then that's easy -
683 # we can just ignore it. However, we have to check that
684 # there is not a different name for the existing VLAN tag
Steve McIntyreb1529072014-12-23 17:17:22 +0000685 # - bail out if so... UNLESS we're looking at the default
686 # VLAN
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000687 #
688 # If this VLAN tag is not already in the DB, we'll need to
689 # add it there and to all the other switches (and their
690 # trunk ports!) too.
Steve McIntyrefc511242014-12-23 22:28:30 +0000691 vlan_id = db.get_vlan_id_by_tag(vlan_tag)
Steve McIntyre6c09c0c2015-07-17 17:20:01 +0100692 if vlan_id != state.default_vlan_id:
Steve McIntyreb1529072014-12-23 17:17:22 +0000693 if vlan_id is not None:
694 vlan_db_name = db.get_vlan_name_by_id(vlan_id)
695 if vlan_name != vlan_db_name:
696 raise InputError("Can't add VLAN tag %d (name %s) for this switch - VLAN tag %d already exists in the database, but with a different name (%s)" % (vlan_tag, vlan_name, vlan_tag, vlan_db_name))
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000697
Steve McIntyreb1529072014-12-23 17:17:22 +0000698 else:
699 # OK, we'll need to set up the new VLAN now. It can't
700 # be a base VLAN - switches don't have such a concept!
701 # Rather than create individually here, add to a
702 # list. *Only* once we've worked through all the
703 # switch's VLANs successfully (checking for existing
704 # records and possible clashes!) should we start
705 # committing changes
706 new_vlan_tags.append(vlan_tag)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000707
708 # Now create the VLAN DB entries
709 for vlan_tag in new_vlan_tags:
710 vlan_name = s.vlan_get_name(vlan_tag)
711 vlan_id = self.create_vlan(state, vlan_name, vlan_tag, False)
712
713 # *Now* add this switch itself to the database, after we've
714 # worked on all the other switches
715 switch_id = db.create_switch(switch_name)
716
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000717 # And now the ports
718 trunk_ports = []
719 ports = s.switch_get_port_names()
Steve McIntyre5fa22652015-04-01 18:01:45 +0100720 logging.debug(' found %d ports on the switch', len(ports))
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000721 for port_name in ports:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100722 logging.debug(' trying to import port %s', port_name)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000723 port_id = None
724 port_mode = s.port_get_mode(port_name)
725 if port_mode == 'access':
726 # Access ports are easy - just create the port, and
727 # set both the current and base VLANs to the current
728 # VLAN on the switch. We'll end up changing this after
729 # import if needed.
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000730 port_vlans[port_name] = (s.port_get_access_vlan(port_name),)
731 port_vlan_id = db.get_vlan_id_by_tag(port_vlans[port_name][0])
Steve McIntyre6f17b102014-12-24 02:18:08 +0000732 port_id = db.create_port(switch_id, port_name,
733 port_vlan_id, port_vlan_id)
Steve McIntyre5fa22652015-04-01 18:01:45 +0100734 logging.debug(' access port, VLAN %d', int(port_vlans[port_name][0]))
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000735 # Nothing further needed
736 elif port_mode == 'trunk':
Steve McIntyre7cf80982015-02-12 07:03:40 +0000737 logging.debug(' trunk port, VLANs:')
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000738 # Trunk ports are a little more involved. First,
739 # create the port in the DB, setting the VLANs to the
740 # first VLAN found on the trunk port. This will *also*
741 # be in access mode by default, and unlocked.
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000742 port_vlans[port_name] = s.port_get_trunk_vlan_list(port_name)
Steve McIntyre7cf80982015-02-12 07:03:40 +0000743 logging.debug(port_vlans[port_name])
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000744 if port_vlans[port_name] == [] or port_vlans[port_name] is None or 'ALL' in port_vlans[port_name]:
745 port_vlans[port_name] = (state.config.vland.default_vlan_tag,)
746 port_vlan_id = db.get_vlan_id_by_tag(port_vlans[port_name][0])
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000747 port_id = db.create_port(switch_id, port_name,
Steve McIntyre6f17b102014-12-24 02:18:08 +0000748 port_vlan_id, port_vlan_id)
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000749 # Append to a list of trunk ports that we will need to
750 # modify once we're done
751 trunk_ports.append(port_id)
Steve McIntyrefc511242014-12-23 22:28:30 +0000752 else:
Steve McIntyre857d89f2015-07-24 16:22:37 +0100753 # We've found a port mode we don't want, e.g. the
754 # "dynamic auto" on a Cisco Catalyst. Handle that here
755 # - tell the switch to set that port to access and
756 # handle accordingly.
757 s.port_set_mode(port_name, 'access')
758 port_vlans[port_name] = (s.port_get_access_vlan(port_name),)
759 port_vlan_id = db.get_vlan_id_by_tag(port_vlans[port_name][0])
760 port_id = db.create_port(switch_id, port_name,
761 port_vlan_id, port_vlan_id)
762 logging.debug(' Found port in %s mode', port_mode)
763 logging.debug(' Forcing to access mode, VLAN %d', int(port_vlans[port_name][0]))
764 port_mode = "access"
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000765
Steve McIntyre5fa22652015-04-01 18:01:45 +0100766 logging.debug(" Added port %s, got port ID %d", port_name, port_id)
Steve McIntyrefc511242014-12-23 22:28:30 +0000767
Steve McIntyre574e3342015-01-23 18:08:33 +0000768 db.set_port_mode(port_id, port_mode)
769
Steve McIntyre6feea572015-02-09 15:49:20 +0000770 # Make sure this switch has all the VLANs we need
771 for vlan in db.all_vlans():
Steve McIntyre49d3c082015-07-24 16:17:23 +0100772 if vlan.tag != state.config.vland.default_vlan_tag:
Steve McIntyred7fb4072015-02-11 17:13:50 +0000773 if not vlan.tag in vlan_tags:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100774 logging.debug("Adding VLAN tag %d to this switch", vlan.tag)
Steve McIntyre6feea572015-02-09 15:49:20 +0000775 s.vlan_create(vlan.tag)
776 s.vlan_set_name(vlan.tag, vlan.name)
777
Steve McIntyrefc511242014-12-23 22:28:30 +0000778 # Now, on each trunk port on the switch, we need to add all
779 # the VLANs already configured across our system
780 if not 'TrunkWildCardVlans' in s.switch_get_capabilities():
781 for port_id in trunk_ports:
782 port = db.get_port_by_id(port_id)
Steve McIntyreb826fc72015-07-27 17:57:40 +0100783
Steve McIntyrefc511242014-12-23 22:28:30 +0000784 for vlan in db.all_vlans():
Steve McIntyre49d3c082015-07-24 16:17:23 +0100785 if vlan.vlan_id != state.default_vlan_id:
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000786 if not vlan.tag in port_vlans[port.name]:
Steve McIntyre5fa22652015-04-01 18:01:45 +0100787 logging.debug("Adding allowed VLAN tag %d to trunk port %s", vlan.tag, port.name)
Steve McIntyrea8fe1de2015-02-11 17:13:12 +0000788 s.port_add_trunk_to_vlan(port.name, vlan.tag)
Steve McIntyrefc511242014-12-23 22:28:30 +0000789
Steve McIntyrefc511242014-12-23 22:28:30 +0000790 # Done with this switch \o/
791 s.switch_save_running_config()
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000792 s.switch_disconnect()
793 del s
794
Steve McIntyre4b4ab652014-12-22 17:19:09 +0000795 ret = {}
Steve McIntyre5f6f85e2014-12-22 16:42:28 +0000796 ret['switch_id'] = switch_id
797 ret['num_ports_added'] = len(ports)
798 ret['num_vlans_added'] = len(new_vlan_tags)
799 return ret # If we're successful