blob: c24f5642416f439838c3a439bf64fff0ae2c9579 [file] [log] [blame]
Steve McIntyref1c04f92014-12-16 18:23:15 +00001import logging
2import os
Steve McIntyre53c7ad92014-12-16 19:21:13 +00003import time
Steve McIntyref1c04f92014-12-16 18:23:15 +00004from db.db import VlanDB
5from errors import CriticalError, InputError, ConfigError, SocketError
6
7class VlanUtil:
8 """VLANd utility functions"""
9
10 def get_switch_driver(self, switch, config):
11 logging.debug("Trying to find a driver for %s" % switch)
12 driver = config.switches[switch].driver
13 logging.debug("Driver: %s" % driver)
14 module = __import__("drivers.%s" % driver, fromlist=[driver])
15 class_ = getattr(module, driver)
16 return class_(switch)
17
Steve McIntyrec68a18e2014-12-17 16:29:28 +000018 def get_all_switches(self, config):
19 for switch in sorted(config.switches):
Steve McIntyrea2a8f792014-12-17 17:34:32 +000020 print "Found switch %s:" % (switch)
21 print " Probing:"
Steve McIntyrec68a18e2014-12-17 16:29:28 +000022
Steve McIntyrea2a8f792014-12-17 17:34:32 +000023 s = util.get_switch_driver(switch, config)
24 s.switch_connect(config.switches[switch].username, config.switches[switch].password)
25 print " Found details of switch:"
26 s._dump_list(s._systemdata)
27 print " Switch has %d ports:" % len(s.switch_get_port_names())
28 for port in s.switch_get_port_names():
29 print " %s" % port
30 if 0 == 1:
31 mode = s.port_get_mode(port)
32 if mode == "trunk":
33 print " port %s is in trunk mode, VLAN(s):" % port
34 vlans = s.port_get_trunk_vlan_list(port)
35 for vlan in vlans:
36 name = s.vlan_get_name(vlan)
37 print " %d (%s)" % (vlan, name)
38 else:
39 vlan = s.port_get_access_vlan(port)
40 name = s.vlan_get_name(vlan)
41 print " port %s is in access mode, VLAN %d (%s):" % (port, vlan, name)
42 s.switch_disconnect()
43 del(s)
Steve McIntyrec68a18e2014-12-17 16:29:28 +000044
Steve McIntyre091e2ac2014-12-16 19:20:07 +000045 # Simple helper wrapper for all the read-only database queries
Steve McIntyre2150bc22014-12-17 13:13:56 +000046 def perform_db_query(self, state, command, data):
Steve McIntyre091e2ac2014-12-16 19:20:07 +000047 print 'perform_db_query'
Steve McIntyref1c04f92014-12-16 18:23:15 +000048 print command
49 print data
50 ret = {}
Steve McIntyre2150bc22014-12-17 13:13:56 +000051 db = state.db
Steve McIntyref1c04f92014-12-16 18:23:15 +000052 try:
Steve McIntyre091e2ac2014-12-16 19:20:07 +000053 if command == 'db.all_switches':
Steve McIntyref1c04f92014-12-16 18:23:15 +000054 ret = db.all_switches()
55 elif command == 'db.all_ports':
56 ret = db.all_ports()
57 elif command == 'db.all_vlans':
58 ret = db.all_vlans()
59 elif command == 'db.get_switch_by_id':
60 ret = db.get_switch_by_id(data['switch_id'])
61 elif command == 'db.get_switch_id_by_name':
62 ret = db.get_switch_id_by_name(data['name'])
63 elif command == 'db.get_switch_name_by_id':
64 ret = db.get_switch_name_by_id(data['switch_id'])
65 elif command == 'db.get_port_by_id':
66 ret = db.get_port_by_id(data['port_id'])
67 elif command == 'db.get_ports_by_switch':
68 ret = db.get_ports_by_switch(data['switch_id'])
69 elif command == 'db.get_port_by_switch_and_name':
70 ret = db.get_port_by_switch_and_name(data['switch_id'], data['name'])
71 elif command == 'db.get_current_vlan_id_by_port':
72 ret = db.get_current_vlan_id_by_port(data['port_id'])
73 elif command == 'db.get_base_vlan_id_by_port':
74 ret = db.get_base_vlan_id_by_port(data['port_id'])
75 elif command == 'db.get_ports_by_current_vlan':
76 ret = db.get_ports_by_current_vlan(data['vlan_id'])
77 elif command == 'db.get_ports_by_base_vlan':
78 ret = db.get_ports_by_base_vlan(data['vlan_id'])
79 elif command == 'db.get_vlan_by_id':
80 ret = db.get_vlan_by_id(data['vlan_id'])
81 elif command == 'db.get_vlan_id_by_name':
82 ret = db.get_vlan_id_by_name(data['name'])
83 elif command == 'db.get_vlan_id_by_tag':
Steve McIntyre07946c22014-12-17 13:14:15 +000084 ret = db.get_vlan_id_by_tag(data['tag'])
Steve McIntyref1c04f92014-12-16 18:23:15 +000085 elif command == 'db.get_vlan_name_by_id':
86 ret = db.get_vlan_name_by_id(data['vlan_id'])
87 else:
Steve McIntyree749fef2014-12-17 16:35:45 +000088 raise InputError("Unknown db_query command \"%s\"" % command)
Steve McIntyref1c04f92014-12-16 18:23:15 +000089
Steve McIntyre5da37fa2014-12-17 13:14:44 +000090 except InputError:
91 raise
92
Steve McIntyref1c04f92014-12-16 18:23:15 +000093 except:
94 raise InputError("Invalid input in query")
95
96 return ret
97
Steve McIntyre53c7ad92014-12-16 19:21:13 +000098 # Simple helper wrapper for all the read-only daemon state queries
99 def perform_daemon_query(self, state, command, data):
100 print 'perform_daemon_query'
101 print command
102 print data
103 ret = {}
104 try:
105 if command == 'daemon.status':
106 # data ignored
107 ret['running'] = 'ok'
108 elif command == 'daemon.version':
109 # data ignored
110 ret['version'] = state.version
111 elif command == 'daemon.statistics':
112 ret['uptime'] = time.time() - state.starttime
113 else:
Steve McIntyree749fef2014-12-17 16:35:45 +0000114 raise InputError("Unknown daemon_query command \"%s\"" % command)
Steve McIntyre53c7ad92014-12-16 19:21:13 +0000115
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000116 except InputError:
117 raise
118
119 except:
120 raise InputError("Invalid input in query")
121
122 return ret
123
Steve McIntyree749fef2014-12-17 16:35:45 +0000124 # Helper wrapper for API functions modifying database state only
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000125 def perform_db_update(self, state, command, data):
126 print 'perform_db_update'
127 print command
128 print data
129 ret = {}
130 db = state.db
131 try:
132 if command == 'db.create_switch':
133 ret = db.create_switch(data['name'])
134 elif command == 'db.create_port':
135 ret = db.create_port(data['switch_id'], data['name'],
136 state.config.default_vlan_id,
137 state.config.default_vlan_id)
138 elif command == 'db.delete_switch':
139 ret = db.delete_switch(data['switch_id'])
140 elif command == 'db.delete_port':
141 ret = db.delete_port(data['port_id'])
142 elif command == 'db.set_port_is_locked':
143 ret = db.set_port_is_locked(data['port_id'], data['is_locked'])
144 elif command == 'db.set_base_vlan':
145 ret = db.set_base_vlan(data['port_id'], data['base_vlan_id'])
146 else:
Steve McIntyre0f9dea62014-12-17 16:37:01 +0000147 raise InputError("Unknown db_update command \"%s\"" % command)
148
149 except InputError:
150 raise
151
152 except:
153 raise InputError("Invalid input in query")
154
155 return ret
156
157 # Helper wrapper for API functions that modify both database state
158 # and on-switch VLAN state
159 def perform_vlan_update(self, state, command, data):
160 print 'perform_vlan_update'
161 print command
162 print data
163 ret = {}
164 db = state.db
165 try:
166 # All of these are complex commands, so call helpers
167 # rather than inline the code here
168 if command == 'api.create_vlan':
169 ret = self.create_vlan(state, command, data)
170 elif command == 'api.delete_vlan':
171 ret = self.delete_vlan(state, command, data)
172 elif command == 'api.set_port_mode':
173 ret = self.set_port_mode(state, command, data)
174 elif command == 'api.set_current_vlan':
175 ret = self.set_current_vlan(state, command, data)
176 elif command == 'api.restore_base_vlan':
177 ret = self.restore_base_vlan(state, command, data)
178 else:
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000179 raise InputError("Unknown query command \"%s\"" % command)
180
Steve McIntyre3256b182014-12-19 15:38:15 +0000181 except InputError as e:
182 print 'got error %s' % e
Steve McIntyrea590b5b2014-12-17 13:15:14 +0000183 raise
184
Steve McIntyre53c7ad92014-12-16 19:21:13 +0000185 except:
186 raise InputError("Invalid input in query")
187
188 return ret
189
190
Steve McIntyre3256b182014-12-19 15:38:15 +0000191 # Complex call
192 # 1. create the VLAN in the DB
193 # 2. Iterate through all switches:
194 # a. Create the VLAN
195 # b. Add the VLAN to all trunk ports (if needed)
196 #
197 # The VLAN may already exist on some of the switches, that's
198 # fine.
199 def create_vlan(self, state, command, data):
200
201 print 'create_vlan'
202 db = state.db
203 config = state.config
204
205 name = data['name']
206 tag = int(data['tag'])
207 is_base_vlan = data['is_base_vlan']
208
209 # 1. Database record first
210 try:
211 print 'Adding DB record first: name %s, tag %d, is_base_vlan %d' % (name, tag, is_base_vlan)
212 vlan_id = db.create_vlan(name, tag, is_base_vlan)
213 print 'Added VLAN tag %d, name %s to the database, created VLAN ID %d' % (tag, name, vlan_id)
214 except InputError:
215 print 'DB creation failed'
216 raise
217
218 # 2. Now the switches
219 try:
220 for switch in sorted(config.switches):
221 trunk_ports = []
222 try:
223 print 'Adding new VLAN to switch %s' % switch
224 # Get the right driver
225 s = self.get_switch_driver(switch, config)
226 s.switch_connect(config.switches[switch].username, config.switches[switch].password)
227
228 # 2a. Create the VLAN on the switch
229 s.vlan_create(tag)
230 s.vlan_set_name(tag, name)
231 print 'Added VLAN tag %d, name %s to switch %s' % (tag, name, switch)
232
233 # 2b. Do we need to worry about trunk ports on this switch?
234 if 'TrunkWildCardVlans' in s.switch_get_capabilities():
235 print 'This switch does not need special trunk port handling'
236 else:
237 print 'This switch needs special trunk port handling'
238 switch_id = db.get_switch_id_by_name(switch)
239 trunk_ports = db.get_trunk_port_names_by_switch(switch_id)
240 if trunk_ports is None:
241 print "But it has no trunk ports defined"
242 trunk_ports = []
243 else:
244 print 'Found %d trunk_ports that need adjusting' % len(trunk_ports)
245
246 # Modify any trunk ports as needed
247 for port in trunk_ports:
248 print 'Added VLAN tag %d, name %s to switch %s' % (tag, name, switch)
249 s.port_add_trunk_to_vlan(port, tag)
250
251 # Save switch config so it will stay across reboots
252 s.switch_save_running_config()
253
254 # And now we're done with this switch
255 s.switch_disconnect()
256 del s
257
258 except IOError:
259 raise
260
261 except IOError:
262 # Bugger. Looks like one of the switch calls above failed.
263 # Undo the database change
264 print 'Switch access failed. Deleting the new VLAN entry in the database'
265 db.delete_vlan(vlan_id)
266 raise
267
268 return vlan_id # If we're successful
269