blob: 36dcd1649bcdbfa821a7bc80dad3a0510fcd1a84 [file] [log] [blame]
srikanth116e6e82014-08-19 07:22:37 -07001#
2# Copyright (c) 2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17from sdncon.rest.config import add_config_handler
18from sdncon.controller.models import Feature, GlobalConfig, Controller, \
19 ControllerInterface, ControllerDomainNameServer, \
20 FirewallRule, ControllerAlias, SnmpServerConfig, ImageDropUser
21from sdncon.controller.models import TacacsPlusConfig, TacacsPlusHost
22from oswrapper import exec_os_wrapper
23import os
24import re
25import sdncon
26from django.core import serializers
27
28# FIXME: Can probably get rid of default_id when the rest of the code is
29# in place for supporting multiple controller IDs. But what about
30# unit tests where we shouldn't rely on the boot-config file existing
31def get_local_controller_id(default_id='localhost'):
32 local_controller_id = default_id
33 f = None
34 try:
35 f = open("%s/run/boot-config" % sdncon.SDN_ROOT, 'r')
36 data = f.read()
37 match = re.search("^controller-id=([0-9a-zA-Z\-]*)$", data, re.MULTILINE)
38 if match:
39 local_controller_id = match.group(1)
40 except Exception, _e:
41 # If there was any error, then just leave the controller ID as the
42 # default value.
43 pass
44 finally:
45 if f:
46 f.close()
47 return local_controller_id
48
49
50# Add the config handlers here. Check the comments for add_config_handler in rest/config.py
51# for a description of the calling conventions for config handlers.
52
53def network_config_handler(op, old_instance, new_instance, modified_fields):
54 valid_instance = old_instance if (op == 'DELETE') else new_instance
55 if isinstance(valid_instance, Controller):
56 controller_node = valid_instance
57 controller_id = controller_node.id
58 if op == 'DELETE':
59 # no further configuration here
60 return
61 elif isinstance(valid_instance, ControllerDomainNameServer) \
62 or isinstance(valid_instance, ControllerInterface):
63 controller_id = valid_instance.controller_id
64 try:
65 controller_node = Controller.objects.get(pk=controller_id)
66 except Exception, _e:
67 # unknown controller node during delete, no need to
68 # do anything with any of these interfaces
69 return
70 else:
71 raise Exception('Unknown model change trigger network config handler')
72
73 if controller_id != get_local_controller_id():
74 return
75
76 if op == 'DELETE':
77 # don't reconfigure the interfaces during delete, since
78 # for deletes, the values of ip/netmask don't get updated
79 dns = ControllerDomainNameServer.objects.filter(
80 controller=controller_node).order_by('timestamp')
81 exec_os_wrapper('NetworkConfig', 'set',
82 [serializers.serialize("json", [controller_node]),
83 serializers.serialize("json", dns)])
84 else:
85 # op != 'DELETE'
86 #
87 # XXX what about HA?
88 # 'ifs' below isn't filtered by controller, the NetConfig
89 # target will only select interfaces assocaited with the
90 # controller-node 'localhost.
91 dns = ControllerDomainNameServer.objects.filter(
92 controller=controller_node).order_by('-priority')
93 ifs = ControllerInterface.objects.filter(controller=controller_node)
94 exec_os_wrapper('NetworkConfig', 'set',
95 [serializers.serialize("json", [controller_node]),
96 serializers.serialize("json", dns),
97 serializers.serialize("json", ifs)])
98
99def firewall_entry_handler(op, old_instance, new_instance, modified_fields=None):
100 #allow in on eth0 proto tcp from any to any port 80
101 print "XXX: firewall handler called-1"
102 command = ""
103 if op == "DELETE" and str(old_instance.interface.controller) == get_local_controller_id():
104 command += "delete "
105 instance = old_instance
106 elif (op == "INSERT" or op == "UPDATE") and str(new_instance.interface.controller) == get_local_controller_id():
107 instance = new_instance
108 else:
109 return
110
111 print instance.action
112 print instance.proto
113 print instance.port
114 print instance.src_ip
115 print instance.vrrp_ip
116 print "XXX: firewall handler called-2"
117 controller_interface = instance.interface
118 eth = 'eth' + str(controller_interface.number) #LOOK! Hardcoded to eth interface
119 proto_str = ""
120 if instance.proto != '' and instance.proto != 'vrrp':
121 proto_str = " proto " + instance.proto
122 action_str = instance.action
123 src_str = " from any"
124 if instance.src_ip != '':
125 src_str = " from " + instance.src_ip
126 dst_str = " to any"
127 if instance.vrrp_ip != '':
128 dst_str = " to " + instance.vrrp_ip
129 print "dst_str = ", dst_str
130 port_str = ""
131 if instance.port != 0:
132 port_str = " port " + str(instance.port)
133
134 command += (action_str + " in on " + eth + proto_str + src_str + dst_str + port_str)
135 print command
136
137 exec_os_wrapper('ExecuteUfwCommand', 'set', [command])
138 if instance.port == 6633 and action_str == 'reject' and op != 'DELETE':
139 exec_os_wrapper('RestartSDNPlatform', 'set', [])
140
141def ntp_config_handler(op, old_instance, new_instance, modified_fields=None):
142 if new_instance != None:
143 exec_os_wrapper("SetNtpServer", 'set', [new_instance.ntp_server])
144
145def tz_config_handler(op, old_instance, new_instance, modified_fields=None):
146 if op == "DELETE":
147 if str(old_instance.id) != get_local_controller_id():
148 return
149 exec_os_wrapper("UnsetTimezone", 'set')
150 elif op == "INSERT" or op == "UPDATE":
151 if str(new_instance.id) != get_local_controller_id():
152 return
153 if new_instance.time_zone != None and str(new_instance.time_zone) != "":
154 exec_os_wrapper("SetTimezone", 'set', [new_instance.time_zone])
155
156def logging_server_config_handler(op, old_instance, new_instance, modified_fields=None):
157 if op == "DELETE":
158 if str(old_instance.id) != get_local_controller_id():
159 return
160 exec_os_wrapper("UnsetSyslogServer", 'set',
161 [old_instance.logging_server, old_instance.logging_level])
162 elif op == "INSERT" or op == "UPDATE":
163 if str(new_instance.id) != get_local_controller_id():
164 return
165 if new_instance.logging_server != "" and new_instance.logging_enabled:
166 exec_os_wrapper("SetSyslogServer", 'set',
167 [new_instance.logging_server, new_instance.logging_level])
168 else:
169 exec_os_wrapper("UnsetSyslogServer", 'set',
170 [new_instance.logging_server, new_instance.logging_level])
171
172def vrrp_virtual_router_id_config_handle(op, old_instance, new_instance, modified_fields=None):
173 if op == "INSERT" or op == "UPDATE":
174 exec_os_wrapper("SetVrrpVirtualRouterId", 'set',
175 [new_instance.cluster_number])
176
177def netvirt_feature_config_handler(op, old_instance, new_instance, modified_fields=None):
178 if op == "INSERT" or op == "UPDATE":
179 if new_instance.netvirt_feature:
180 exec_os_wrapper("SetDefaultConfig", 'set', [new_instance.netvirt_feature])
181 else:
182 exec_os_wrapper("SetStaticFlowOnlyConfig", 'set', [new_instance.netvirt_feature])
183
184def controller_alias_config_handler(op, old_instance, new_instance, modified_fields=None):
185 if op == 'INSERT' or op == 'UPDATE':
186 if str(new_instance.controller) == get_local_controller_id():
187 exec_os_wrapper("SetHostname", 'set', [new_instance.alias])
188
189def tacacs_plus_config_handler(op, old_instance, new_instance, modified_fields=None):
190
191 if isinstance(old_instance, TacacsPlusConfig):
192 if op == 'DELETE':
193 # deleting the config singleton (presumably during shutdown?)
194 return
195
196 if isinstance(old_instance, TacacsPlusConfig):
197 config_id = old_instance.id
198 else:
199 config_id = 'tacacs'
200 try:
201 config = TacacsPlusConfig.objects.get(pk=config_id)
202 except TacacsPlusConfig.DoesNotExist:
203 # cons up a dummy config object, not necessary to save it
204 config = TacacsPlusConfig()
205
206 # get current list of hosts (op==DELETE ignored here)
207 ##hosts = TacacsPlusHost.objects.order_by('timestamp')
208 def timestampSort(h1, h2):
209 return cmp(h1.timestamp, h2.timestamp)
210 hosts = sorted(TacacsPlusHost.objects.all(), timestampSort)
211
212 # XXX roth -- config is passed as-is, not as a single-element list
213 cj = serializers.serialize("json", [config])
214 hj = serializers.serialize("json", hosts)
215 print "Calling oswrapper with:", [cj, hj]
216 exec_os_wrapper('TacacsPlusConfig', 'set', [cj, hj])
217
218def snmp_server_config_handler(op, old_instance, new_instance, modified_fields=None):
219 if op == 'DELETE':
220 exec_os_wrapper('UnsetSnmpServerConfig', 'set', [])
221 elif op == 'INSERT' or op == 'UPDATE':
222 # enable_changed is true if operation is INSERT, else compare with old instance
223 if (op == 'INSERT'):
224 enable_changed = (new_instance.server_enable is True) #since default is False
225 print 'operation= insert, enable_changed = ', enable_changed
226 else:
227 enable_changed = (new_instance.server_enable != old_instance.server_enable)
228 server_enable = new_instance.server_enable
229 community = '' if new_instance.community is None else new_instance.community
230 location = '' if new_instance.location is None else new_instance.location
231 contact = '' if new_instance.contact is None else new_instance.contact
232
233 print "Calling oswrapper with:", [server_enable, community, location, contact, enable_changed]
234 exec_os_wrapper('SetSnmpServerConfig', 'set',
235 [server_enable, community, location, contact, enable_changed])
236
237def test_config_handler(op, old_instance, new_instance, modified_fields=None):
238 pass
239
240def images_user_ssh_key_config_handler(op, old_instance, new_instance, modified_fields=None):
241 if op == 'INSERT' or op == 'UPDATE':
242 sshkey = "\"" + str(new_instance.images_user_ssh_key) + "\""
243 exec_os_wrapper('SetImagesUserSSHKey', 'set', [sshkey])
244
245def init_config():
246 #
247 # Associate the config handlers with specific callout for each of the fields
248 # Keep in mind that these are the django names, NOT the rest api names,
249 #
250 disabled_by_shell_variable = os.environ.get('SDNCON_CONFIG_HANDLERS_DISABLED', False)
251 disabled_by_file = os.path.exists("%s/sdncon_config_handlers_disabled" % sdncon.SDN_ROOT)
252 if not disabled_by_shell_variable and not disabled_by_file:
253 add_config_handler({Controller: ['ntp_server']}, ntp_config_handler)
254 add_config_handler({Controller: ['time_zone']}, tz_config_handler)
255 add_config_handler(
256 {
257 Controller: ['domain_lookups_enabled', 'domain_name', 'default_gateway'],
258 ControllerDomainNameServer: None,
259 ControllerInterface: ['ip', 'netmask', 'mode'],
260 }, network_config_handler)
261 add_config_handler({ControllerAlias: ['alias']}, controller_alias_config_handler)
262 add_config_handler({Controller: ['logging_enabled', 'logging_server', 'logging_level']}, logging_server_config_handler)
263 add_config_handler({Feature: ['netvirt_feature']}, netvirt_feature_config_handler)
264 add_config_handler({FirewallRule: None}, firewall_entry_handler)
265 add_config_handler({GlobalConfig: ['cluster_number']}, vrrp_virtual_router_id_config_handle)
266 add_config_handler({ TacacsPlusConfig: ["tacacs_plus_authn", "tacacs_plus_authz", "tacacs_plus_acct",
267 "local_authn", "local_authz",
268 "timeout", "key",],
269 TacacsPlusHost: ['ip', 'key'],
270 },
271 tacacs_plus_config_handler)
272 add_config_handler({SnmpServerConfig: ['server_enable', 'community', 'location', 'contact']}, snmp_server_config_handler)
273 add_config_handler({ImageDropUser: ['images_user_ssh_key']}, images_user_ssh_key_config_handler)
274 else:
275 add_config_handler(
276 {
277 Controller: ['domain_lookups_enabled', 'domain_name', 'default_gateway'],
278 ControllerDomainNameServer: None,
279 ControllerInterface: ['ip', 'netmask', 'mode'],
280 ControllerAlias: ['alias'],
281 FirewallRule: None,
282 Feature: None,
283 GlobalConfig: ['ha-enabled', 'cluster-number'],
284 }, test_config_handler)