| # |
| # Copyright (c) 2013 Big Switch Networks, Inc. |
| # |
| # Licensed under the Eclipse Public License, Version 1.0 (the |
| # "License"); you may not use this file except in compliance with the |
| # License. You may obtain a copy of the License at |
| # |
| # http://www.eclipse.org/legal/epl-v10.html |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| # implied. See the License for the specific language governing |
| # permissions and limitations under the License. |
| # |
| |
| from sdncon.rest.config import add_config_handler |
| """ |
| from sdncon.controller.models import Feature, GlobalConfig, Controller, \ |
| ControllerInterface, ControllerDomainNameServer, \ |
| FirewallRule, ControllerAlias, SnmpServerConfig, ImageDropUser |
| from sdncon.controller.models import TacacsPlusConfig, TacacsPlusHost |
| """ |
| from oswrapper import exec_os_wrapper |
| import os |
| import re |
| import sdncon |
| from django.core import serializers |
| |
| # FIXME: Can probably get rid of default_id when the rest of the code is |
| # in place for supporting multiple controller IDs. But what about |
| # unit tests where we shouldn't rely on the boot-config file existing |
| def get_local_controller_id(default_id='localhost'): |
| local_controller_id = default_id |
| f = None |
| try: |
| f = open("%s/run/boot-config" % sdncon.SDN_ROOT, 'r') |
| data = f.read() |
| match = re.search("^controller-id=([0-9a-zA-Z\-]*)$", data, re.MULTILINE) |
| if match: |
| local_controller_id = match.group(1) |
| except Exception, _e: |
| # If there was any error, then just leave the controller ID as the |
| # default value. |
| pass |
| finally: |
| if f: |
| f.close() |
| return local_controller_id |
| |
| """ |
| # Add the config handlers here. Check the comments for add_config_handler in rest/config.py |
| # for a description of the calling conventions for config handlers. |
| |
| def network_config_handler(op, old_instance, new_instance, modified_fields): |
| valid_instance = old_instance if (op == 'DELETE') else new_instance |
| if isinstance(valid_instance, Controller): |
| controller_node = valid_instance |
| controller_id = controller_node.id |
| if op == 'DELETE': |
| # no further configuration here |
| return |
| elif isinstance(valid_instance, ControllerDomainNameServer) \ |
| or isinstance(valid_instance, ControllerInterface): |
| controller_id = valid_instance.controller_id |
| try: |
| controller_node = Controller.objects.get(pk=controller_id) |
| except Exception, _e: |
| # unknown controller node during delete, no need to |
| # do anything with any of these interfaces |
| return |
| else: |
| raise Exception('Unknown model change trigger network config handler') |
| |
| if controller_id != get_local_controller_id(): |
| return |
| |
| if op == 'DELETE': |
| # don't reconfigure the interfaces during delete, since |
| # for deletes, the values of ip/netmask don't get updated |
| dns = ControllerDomainNameServer.objects.filter( |
| controller=controller_node).order_by('timestamp') |
| exec_os_wrapper('NetworkConfig', 'set', |
| [serializers.serialize("json", [controller_node]), |
| serializers.serialize("json", dns)]) |
| else: |
| # op != 'DELETE' |
| # |
| # XXX what about HA? |
| # 'ifs' below isn't filtered by controller, the NetConfig |
| # target will only select interfaces assocaited with the |
| # controller-node 'localhost. |
| dns = ControllerDomainNameServer.objects.filter( |
| controller=controller_node).order_by('-priority') |
| ifs = ControllerInterface.objects.filter(controller=controller_node) |
| exec_os_wrapper('NetworkConfig', 'set', |
| [serializers.serialize("json", [controller_node]), |
| serializers.serialize("json", dns), |
| serializers.serialize("json", ifs)]) |
| |
| def firewall_entry_handler(op, old_instance, new_instance, modified_fields=None): |
| #allow in on eth0 proto tcp from any to any port 80 |
| print "XXX: firewall handler called-1" |
| command = "" |
| if op == "DELETE" and str(old_instance.interface.controller) == get_local_controller_id(): |
| command += "delete " |
| instance = old_instance |
| elif (op == "INSERT" or op == "UPDATE") and str(new_instance.interface.controller) == get_local_controller_id(): |
| instance = new_instance |
| else: |
| return |
| |
| print instance.action |
| print instance.proto |
| print instance.port |
| print instance.src_ip |
| print instance.vrrp_ip |
| print "XXX: firewall handler called-2" |
| controller_interface = instance.interface |
| eth = 'eth' + str(controller_interface.number) #LOOK! Hardcoded to eth interface |
| proto_str = "" |
| if instance.proto != '' and instance.proto != 'vrrp': |
| proto_str = " proto " + instance.proto |
| action_str = instance.action |
| src_str = " from any" |
| if instance.src_ip != '': |
| src_str = " from " + instance.src_ip |
| dst_str = " to any" |
| if instance.vrrp_ip != '': |
| dst_str = " to " + instance.vrrp_ip |
| print "dst_str = ", dst_str |
| port_str = "" |
| if instance.port != 0: |
| port_str = " port " + str(instance.port) |
| |
| command += (action_str + " in on " + eth + proto_str + src_str + dst_str + port_str) |
| print command |
| |
| exec_os_wrapper('ExecuteUfwCommand', 'set', [command]) |
| if instance.port == 6633 and action_str == 'reject' and op != 'DELETE': |
| exec_os_wrapper('RestartSDNPlatform', 'set', []) |
| |
| def ntp_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if new_instance != None: |
| exec_os_wrapper("SetNtpServer", 'set', [new_instance.ntp_server]) |
| |
| def tz_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == "DELETE": |
| if str(old_instance.id) != get_local_controller_id(): |
| return |
| exec_os_wrapper("UnsetTimezone", 'set') |
| elif op == "INSERT" or op == "UPDATE": |
| if str(new_instance.id) != get_local_controller_id(): |
| return |
| if new_instance.time_zone != None and str(new_instance.time_zone) != "": |
| exec_os_wrapper("SetTimezone", 'set', [new_instance.time_zone]) |
| |
| def logging_server_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == "DELETE": |
| if str(old_instance.id) != get_local_controller_id(): |
| return |
| exec_os_wrapper("UnsetSyslogServer", 'set', |
| [old_instance.logging_server, old_instance.logging_level]) |
| elif op == "INSERT" or op == "UPDATE": |
| if str(new_instance.id) != get_local_controller_id(): |
| return |
| if new_instance.logging_server != "" and new_instance.logging_enabled: |
| exec_os_wrapper("SetSyslogServer", 'set', |
| [new_instance.logging_server, new_instance.logging_level]) |
| else: |
| exec_os_wrapper("UnsetSyslogServer", 'set', |
| [new_instance.logging_server, new_instance.logging_level]) |
| |
| def vrrp_virtual_router_id_config_handle(op, old_instance, new_instance, modified_fields=None): |
| if op == "INSERT" or op == "UPDATE": |
| exec_os_wrapper("SetVrrpVirtualRouterId", 'set', |
| [new_instance.cluster_number]) |
| |
| def netvirt_feature_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == "INSERT" or op == "UPDATE": |
| if new_instance.netvirt_feature: |
| exec_os_wrapper("SetDefaultConfig", 'set', [new_instance.netvirt_feature]) |
| else: |
| exec_os_wrapper("SetStaticFlowOnlyConfig", 'set', [new_instance.netvirt_feature]) |
| |
| def controller_alias_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == 'INSERT' or op == 'UPDATE': |
| if str(new_instance.controller) == get_local_controller_id(): |
| exec_os_wrapper("SetHostname", 'set', [new_instance.alias]) |
| |
| def tacacs_plus_config_handler(op, old_instance, new_instance, modified_fields=None): |
| |
| if isinstance(old_instance, TacacsPlusConfig): |
| if op == 'DELETE': |
| # deleting the config singleton (presumably during shutdown?) |
| return |
| |
| if isinstance(old_instance, TacacsPlusConfig): |
| config_id = old_instance.id |
| else: |
| config_id = 'tacacs' |
| try: |
| config = TacacsPlusConfig.objects.get(pk=config_id) |
| except TacacsPlusConfig.DoesNotExist: |
| # cons up a dummy config object, not necessary to save it |
| config = TacacsPlusConfig() |
| |
| # get current list of hosts (op==DELETE ignored here) |
| ##hosts = TacacsPlusHost.objects.order_by('timestamp') |
| def timestampSort(h1, h2): |
| return cmp(h1.timestamp, h2.timestamp) |
| hosts = sorted(TacacsPlusHost.objects.all(), timestampSort) |
| |
| # XXX roth -- config is passed as-is, not as a single-element list |
| cj = serializers.serialize("json", [config]) |
| hj = serializers.serialize("json", hosts) |
| print "Calling oswrapper with:", [cj, hj] |
| exec_os_wrapper('TacacsPlusConfig', 'set', [cj, hj]) |
| |
| def snmp_server_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == 'DELETE': |
| exec_os_wrapper('UnsetSnmpServerConfig', 'set', []) |
| elif op == 'INSERT' or op == 'UPDATE': |
| # enable_changed is true if operation is INSERT, else compare with old instance |
| if (op == 'INSERT'): |
| enable_changed = (new_instance.server_enable is True) #since default is False |
| print 'operation= insert, enable_changed = ', enable_changed |
| else: |
| enable_changed = (new_instance.server_enable != old_instance.server_enable) |
| server_enable = new_instance.server_enable |
| community = '' if new_instance.community is None else new_instance.community |
| location = '' if new_instance.location is None else new_instance.location |
| contact = '' if new_instance.contact is None else new_instance.contact |
| |
| print "Calling oswrapper with:", [server_enable, community, location, contact, enable_changed] |
| exec_os_wrapper('SetSnmpServerConfig', 'set', |
| [server_enable, community, location, contact, enable_changed]) |
| """ |
| def test_config_handler(op, old_instance, new_instance, modified_fields=None): |
| pass |
| |
| def images_user_ssh_key_config_handler(op, old_instance, new_instance, modified_fields=None): |
| if op == 'INSERT' or op == 'UPDATE': |
| sshkey = "\"" + str(new_instance.images_user_ssh_key) + "\"" |
| exec_os_wrapper('SetImagesUserSSHKey', 'set', [sshkey]) |
| |
| def init_config(): |
| # |
| # Associate the config handlers with specific callout for each of the fields |
| # Keep in mind that these are the django names, NOT the rest api names, |
| # |
| """ |
| disabled_by_shell_variable = os.environ.get('SDNCON_CONFIG_HANDLERS_DISABLED', False) |
| disabled_by_file = os.path.exists("%s/sdncon_config_handlers_disabled" % sdncon.SDN_ROOT) |
| if not disabled_by_shell_variable and not disabled_by_file: |
| add_config_handler({Controller: ['ntp_server']}, ntp_config_handler) |
| add_config_handler({Controller: ['time_zone']}, tz_config_handler) |
| add_config_handler( |
| { |
| Controller: ['domain_lookups_enabled', 'domain_name', 'default_gateway'], |
| ControllerDomainNameServer: None, |
| ControllerInterface: ['ip', 'netmask', 'mode'], |
| }, network_config_handler) |
| add_config_handler({ControllerAlias: ['alias']}, controller_alias_config_handler) |
| add_config_handler({Controller: ['logging_enabled', 'logging_server', 'logging_level']}, logging_server_config_handler) |
| add_config_handler({Feature: ['netvirt_feature']}, netvirt_feature_config_handler) |
| add_config_handler({FirewallRule: None}, firewall_entry_handler) |
| add_config_handler({GlobalConfig: ['cluster_number']}, vrrp_virtual_router_id_config_handle) |
| add_config_handler({ TacacsPlusConfig: ["tacacs_plus_authn", "tacacs_plus_authz", "tacacs_plus_acct", |
| "local_authn", "local_authz", |
| "timeout", "key",], |
| TacacsPlusHost: ['ip', 'key'], |
| }, |
| tacacs_plus_config_handler) |
| add_config_handler({SnmpServerConfig: ['server_enable', 'community', 'location', 'contact']}, snmp_server_config_handler) |
| add_config_handler({ImageDropUser: ['images_user_ssh_key']}, images_user_ssh_key_config_handler) |
| else: |
| add_config_handler( |
| { |
| Controller: ['domain_lookups_enabled', 'domain_name', 'default_gateway'], |
| ControllerDomainNameServer: None, |
| ControllerInterface: ['ip', 'netmask', 'mode'], |
| ControllerAlias: ['alias'], |
| FirewallRule: None, |
| Feature: None, |
| GlobalConfig: ['ha-enabled', 'cluster-number'], |
| }, test_config_handler) |
| """ |