diff --git a/src/config/svc-monitor/SConscript b/src/config/svc-monitor/SConscript index 01f88a3deca..df77146c7e8 100644 --- a/src/config/svc-monitor/SConscript +++ b/src/config/svc-monitor/SConscript @@ -2,7 +2,7 @@ # # Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. -# +# import os Import('CfgmEnv') @@ -17,6 +17,8 @@ sources = [ '.coveragerc', 'MANIFEST.in', 'svc_monitor/__init__.py', + 'svc_monitor/agent.py', + 'svc_monitor/agent_manager.py', 'svc_monitor/svc_monitor.py', 'svc_monitor/instance_manager.py', 'svc_monitor/virtual_machine_manager.py', @@ -42,6 +44,7 @@ sources = [ 'svc_monitor/tests/test_virtual_machine_manager.py', 'svc_monitor/tests/test_dep_track.py', 'svc_monitor/tests/test_snat.py', + 'svc_monitor/tests/test_snat_agent.py', 'svc_monitor/tests/scheduler/__init__.py', 'svc_monitor/tests/scheduler/test_vrouter_schedulers.py', ] @@ -81,8 +84,8 @@ if 'install' in BUILD_TARGETS: env.Alias('install', env.Install(env['INSTALL_CONF'], 'contrail-svc-monitor.conf')) env.Alias('install', env.InstallAs( env['INSTALL_INITD'] + '/contrail-svc-monitor', 'contrail-svc-monitor.initd.supervisord')) -env.Alias('install', env.Install(env['INSTALL_CONF']+ - '/supervisord_config_files', 'contrail-svc-monitor.ini')) +env.Alias('install', env.Install(env['INSTALL_CONF']+ + '/supervisord_config_files', 'contrail-svc-monitor.ini')) buildspace_link = os.environ.get('CONTRAIL_REPO') if buildspace_link: diff --git a/src/config/svc-monitor/svc_monitor/agent.py b/src/config/svc-monitor/svc_monitor/agent.py new file mode 100644 index 00000000000..fc27eb41cb7 --- /dev/null +++ b/src/config/svc-monitor/svc_monitor/agent.py @@ -0,0 +1,40 @@ +# Copyright (c) 2015 Redhat +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 +# +# 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. +# +# @author: Sylvain Afchain + +import abc + + +class Agent(object): + __metaclass__ = abc.ABCMeta + + def __init__(self, svc_mon, vnc_lib, cassandra, config_section): + self._vnc_lib = vnc_lib + self._svc_mon = svc_mon + self._cassandra = cassandra + self._args = config_section + + @abc.abstractmethod + def handle_service_type(self): + pass + + # method called just before creation of vm and vmi + def pre_create_service_vm(self, instance_index, si, st, vm): + pass + + # method called just after creation of vm and vmi + def post_create_service_vm(self, instance_index, si, st, vm): + pass diff --git a/src/config/svc-monitor/svc_monitor/agent_manager.py b/src/config/svc-monitor/svc_monitor/agent_manager.py new file mode 100644 index 00000000000..5736b7b1e2c --- /dev/null +++ b/src/config/svc-monitor/svc_monitor/agent_manager.py @@ -0,0 +1,36 @@ +# Copyright (c) 2015 Redhat +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 +# +# 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. +# +# @author: Sylvain Afchain + + +class AgentManager(object): + + def __init__(self): + self._agents = {} + + def register_agent(self, agent): + type = agent.handle_service_type() + self._agents[type] = agent + + def pre_create_service_vm(self, instance_index, si, st, vm): + agent = self._agents.get(st.params.get('service_type')) + if agent: + agent.pre_create_service_vm(instance_index, si, st, vm) + + def post_create_service_vm(self, instance_index, si, st, vm): + agent = self._agents.get(st.params.get('service_type')) + if agent: + agent.post_create_service_vm(instance_index, si, st, vm) diff --git a/src/config/svc-monitor/svc_monitor/config_db.py b/src/config/svc-monitor/svc_monitor/config_db.py index 35b80dd9571..78ca3fffdda 100644 --- a/src/config/svc-monitor/svc_monitor/config_db.py +++ b/src/config/svc-monitor/svc_monitor/config_db.py @@ -828,6 +828,7 @@ def __init__(self, uuid, obj_dict=None): self.service_instance = None self.virtual_network = None self.virtual_machine_interfaces = set() + self.last_virtual_machine_interfaces = set() self.update(obj_dict) # end __init__ diff --git a/src/config/svc-monitor/svc_monitor/instance_manager.py b/src/config/svc-monitor/svc_monitor/instance_manager.py index 0e89b12592b..b9a5010c4ee 100644 --- a/src/config/svc-monitor/svc_monitor/instance_manager.py +++ b/src/config/svc-monitor/svc_monitor/instance_manager.py @@ -30,11 +30,12 @@ class InstanceManager(object): def __init__(self, vnc_lib, db, logger, vrouter_scheduler, - nova_client, args=None): + nova_client, agent_manager, args=None): self.logger = logger self._vnc_lib = vnc_lib self._args = args self._nc = nova_client + self._agent_manager = agent_manager self.vrouter_scheduler = vrouter_scheduler @abc.abstractmethod @@ -87,7 +88,7 @@ def _get_project_obj(self, proj_fq_name): break if not proj_obj: self.logger.log_error("%s project not found" % - (proj_fq_name.join(':'))) + (':'.join(proj_fq_name))) return proj_obj def _allocate_iip(self, vn_obj, iip_name): @@ -239,18 +240,7 @@ def validate_network_config(self, st, si): user_visible = True itf_type = st_if.get('service_interface_type') vn_fq_str = si_if.get('virtual_network', None) - if (itf_type == svc_info.get_left_if_str() and - (st.params.get('service_type') == - svc_info.get_snat_service_type())): - vn_id = self._create_snat_vn(si, vn_fq_str, index) - user_visible = False - elif (itf_type == svc_info.get_right_if_str() and - (st.params.get('service_type') == - svc_info.get_lb_service_type())): - iip_id, vn_id = self._get_vip_vmi_iip(si) - nic['iip-id'] = iip_id - user_visible = False - elif not vn_fq_str or vn_fq_str == '': + if not vn_fq_str: vn_id = self._check_create_service_vn(itf_type, si) else: try: @@ -259,7 +249,7 @@ def validate_network_config(self, st, si): except NoIdError: config_complete = False - nic['type'] = st_if.get('service_interface_type') + nic['type'] = itf_type nic['index'] = str(index + 1) nic['net-id'] = vn_id nic['shared-ip'] = st_if.get('shared_ip') @@ -298,6 +288,9 @@ def cleanup_svc_vm_ports(self, vmi_list, port_delete=True): pass def _check_create_netns_vm(self, instance_index, si, st, vm): + # notify all the agents + self._agent_manager.pre_create_service_vm(instance_index, si, st, vm) + instance_name = self._get_instance_name(si, instance_index) vm_obj = VirtualMachine(instance_name) vm_obj.set_display_name(instance_name + '__' + st.virtualization_type) @@ -319,6 +312,9 @@ def _check_create_netns_vm(self, instance_index, si, st, vm): local_preference=si.local_preference[instance_index], vm_obj=vm_obj) + # notify all the agents + self._agent_manager.post_create_service_vm(instance_index, si, st, vm) + return vm def _create_svc_vm_port(self, nic, instance_name, si, st, @@ -343,7 +339,7 @@ def _create_svc_vm_port(self, nic, instance_name, si, st, vmi_create = False vmi_updated = False if_properties = None - + port_name = ('__').join([instance_name, nic['type'], nic['index']]) port_fq_name = proj_obj.fq_name + [port_name] vmi_obj = VirtualMachineInterface(parent_obj=proj_obj, name=port_name) @@ -595,51 +591,6 @@ def create_service(self, st, si): status='CREATE', vms=instances, st_name=(':').join(st.fq_name)) - def _create_snat_vn(self, si, vn_fq_str, index): - vn_name = '%s_%s' % (svc_info.get_snat_left_vn_prefix(), - si.name) - vn_fq_name = si.fq_name[:-1] + [vn_name] - try: - vn_id = self._vnc_lib.fq_name_to_id( - 'virtual-network', vn_fq_name) - except NoIdError: - snat_subnet = svc_info.get_snat_left_subnet() - vn_id = self.create_service_vn(vn_name, snat_subnet, - si.fq_name[:-1], user_visible=False) - - if vn_fq_str != ':'.join(vn_fq_name): - si_obj = ServiceInstance() - si_obj.uuid = si.uuid - si_obj.fq_name = si.fq_name - si_props = ServiceInstanceType(**si.params) - left_if = ServiceInstanceInterfaceType( - virtual_network=':'.join(vn_fq_name)) - si_props.insert_interface_list(index, left_if) - si_obj.set_service_instance_properties(si_props) - self._vnc_lib.service_instance_update(si_obj) - self.logger.log_info("SI %s updated with left vn %s" % - (si_obj.get_fq_name_str(), vn_fq_str)) - - return vn_id - - def _get_vip_vmi_iip(self, si): - if not si.loadbalancer_pool: - return None, None - - pool = LoadbalancerPoolSM.get(si.loadbalancer_pool) - if not pool.virtual_ip: - return None, None - - vip = VirtualIpSM.get(pool.virtual_ip) - if not vip.virtual_machine_interface: - return None, None - - vmi = VirtualMachineInterfaceSM.get(vip.virtual_machine_interface) - if not vmi.instance_ip or not vmi.virtual_network: - return None, None - - return vmi.instance_ip, vmi.virtual_network - def add_fip_to_vip_vmi(self, vmi, fip): iip = InstanceIpSM.get(vmi.instance_ip) if not iip: diff --git a/src/config/svc-monitor/svc_monitor/loadbalancer_agent.py b/src/config/svc-monitor/svc_monitor/loadbalancer_agent.py index a61ec2a684e..7dacf04a3c4 100644 --- a/src/config/svc-monitor/svc_monitor/loadbalancer_agent.py +++ b/src/config/svc-monitor/svc_monitor/loadbalancer_agent.py @@ -2,14 +2,20 @@ from cfgm_common import importutils from cfgm_common import exceptions as vnc_exc +from cfgm_common import svc_info + +from agent import Agent from config_db import ServiceApplianceSM, ServiceApplianceSetSM, \ - LoadbalancerPoolSM, InstanceIpSM, VirtualMachineInterfaceSM + LoadbalancerPoolSM, InstanceIpSM, VirtualMachineInterfaceSM, \ + VirtualIpSM -class LoadbalancerAgent(object): +class LoadbalancerAgent(Agent): - def __init__(self, svc_mon, vnc_lib, config_section): + def __init__(self, svc_mon, vnc_lib, cassandra, config_section): # Loadbalancer + super(LoadbalancerAgent, self).__init__(svc_mon, vnc_lib, + cassandra, config_section) self._vnc_lib = vnc_lib self._svc_mon = svc_mon self._cassandra = self._svc_mon._cassandra @@ -24,6 +30,34 @@ def __init__(self, svc_mon, vnc_lib, config_section): self._default_provider = "opencontrail" # end __init__ + def handle_service_type(self): + return svc_info.get_lb_service_type() + + def pre_create_service_vm(self, instance_index, si, st, vm): + for nic in si.vn_info: + if nic['type'] == svc_info.get_right_if_str(): + iip_id, vn_id = self._get_vip_vmi_iip(si) + nic['iip-id'] = iip_id + nic['user-visible'] = False + + def _get_vip_vmi_iip(self, si): + if not si.loadbalancer_pool: + return None, None + + pool = LoadbalancerPoolSM.get(si.loadbalancer_pool) + if not pool.virtual_ip: + return None, None + + vip = VirtualIpSM.get(pool.virtual_ip) + if not vip.virtual_machine_interface: + return None, None + + vmi = VirtualMachineInterfaceSM.get(vip.virtual_machine_interface) + if not vmi.instance_ip or not vmi.virtual_network: + return None, None + + return vmi.instance_ip, vmi.virtual_network + # create default loadbalancer driver def _create_default_service_appliance_set(self, sa_set_name, driver_name): default_gsc_name = "default-global-system-config" diff --git a/src/config/svc-monitor/svc_monitor/snat_agent.py b/src/config/svc-monitor/svc_monitor/snat_agent.py index e3985bbd088..a922f4e2cb7 100644 --- a/src/config/svc-monitor/svc_monitor/snat_agent.py +++ b/src/config/svc-monitor/svc_monitor/snat_agent.py @@ -1,16 +1,19 @@ +import copy + from vnc_api.vnc_api import * +from agent import Agent from cfgm_common import exceptions as vnc_exc -from config_db import VirtualNetworkSM, LogicalRouterSM, VirtualMachineInterfaceSM, ServiceInstanceSM, ServiceTemplateSM +from cfgm_common import svc_info +from config_db import VirtualNetworkSM, LogicalRouterSM, \ + VirtualMachineInterfaceSM, ServiceInstanceSM, ServiceTemplateSM, \ + ProjectSM + SNAT_SERVICE_TEMPLATE_FQ_NAME = ['default-domain', 'netns-snat-template'] -class SNATAgent(object): - def __init__(self, svc_mon, vnc_lib): - self._vnc_lib = vnc_lib - self._svc_mon = svc_mon - # end __init__ +class SNATAgent(Agent): def audit_snat_instances(self): for lr in LogicalRouterSM.values(): @@ -26,16 +29,124 @@ def audit_snat_instances(self): self.cleanup_snat_instance(lr_uuid, si.uuid) # end audit_snat_instances + def handle_service_type(self): + return svc_info.get_snat_service_type() + + def pre_create_service_vm(self, instance_index, si, st, vm): + for nic in si.vn_info: + if nic['type'] == svc_info.get_left_if_str(): + nic['user-visible'] = False + + def _create_snat_vn(self, si_obj, vn_name): + snat_subnet = svc_info.get_snat_left_subnet() + self._svc_mon.netns_manager.create_service_vn( + vn_name, snat_subnet, si_obj.fq_name[:-1], + user_visible=False) + + def _get_snat_vn(self, project_obj, si_obj): + vn_name = '%s_%s' % (svc_info.get_snat_left_vn_prefix(), + si_obj.name) + vn_fq_name = si_obj.fq_name[:-1] + [vn_name] + try: + self._cassandra.fq_name_to_uuid('virtual-network', vn_fq_name) + except NoIdError: + self._create_snat_vn(si_obj, vn_name) + + return ':'.join(vn_fq_name) + def update_snat_instance(self, router_obj): - if router_obj.virtual_network: + if (router_obj.virtual_network and + router_obj.virtual_machine_interfaces): if router_obj.service_instance is None: - self.add_snat_instance(router_obj) + self._add_snat_instance(router_obj) + else: + self._update_snat_instance(router_obj) else: if router_obj.service_instance: - self.delete_snat_instance(router_obj) + self._delete_snat_instance(router_obj) + + router_obj.last_virtual_machine_interfaces = copy.copy( + router_obj.virtual_machine_interfaces) + return router_obj # end update_snat_instance - - def add_snat_instance(self, router_obj): + + def _diff_virtual_interfaces(self, router_obj): + uuids = set([uuid for uuid in + router_obj.virtual_machine_interfaces]) + + to_del = router_obj.last_virtual_machine_interfaces - uuids + to_add = uuids - router_obj.last_virtual_machine_interfaces + + return to_del, to_add + + def _get_net_uuids(self, vmi_uuids): + return [ + VirtualMachineInterfaceSM.get(uuid).virtual_network + for uuid in vmi_uuids] + + def _virtual_network_read(self, net_uuid): + (ok, result) = self._cassandra._cassandra_virtual_network_read( + [net_uuid]) + if not ok: + return + return VirtualNetwork.from_dict(**result[0]) + + def _add_route_table(self, net_uuid, rt_obj): + net_obj = self._virtual_network_read(net_uuid) + if not net_obj: + return + net_obj.set_route_table(rt_obj) + self._vnc_lib.virtual_network_update(net_obj) + + def _add_route_tables(self, net_uuids, rt_obj): + for net_uuid in net_uuids: + self._add_route_table(net_uuid, rt_obj) + + def _del_route_table(self, net_uuid, rt_obj): + net_obj = self._virtual_network_read(net_uuid) + if not net_obj: + return + net_obj.del_route_table(rt_obj) + self._vnc_lib.virtual_network_update(net_obj) + + def _del_route_tables(self, net_uuids, rt_obj): + for net_uuid in net_uuids: + self._del_route_table(net_uuid, rt_obj) + + def _update_snat_instance(self, router_obj): + to_del, to_add = self._diff_virtual_interfaces(router_obj) + if to_del or to_add: + project_obj = ProjectSM.get(router_obj.parent_uuid) + + rt_obj = self._get_route_table(router_obj, project_obj) + if not rt_obj: + return + + if to_add: + net_uuids = self._get_net_uuids(to_add) + self._add_route_tables(net_uuids, rt_obj) + + if to_del: + net_uuids = self._get_net_uuids(to_del) + self._del_route_tables(net_uuids, rt_obj) + + def _get_route_table(self, router_obj, project_obj): + rt_name = 'rt_' + router_obj.uuid + rt_fq_name = project_obj.fq_name + [rt_name] + try: + rt_uuid = self._cassandra.fq_name_to_uuid('route-table', + rt_fq_name) + except NoIdError: + return + + (ok, result) = self._cassandra._cassandra_route_table_read( + [rt_uuid]) + if not ok: + return + + return RouteTable.from_dict(**result[0]) + + def _add_snat_instance(self, router_obj): try: vnc_rtr_obj = self._vnc_lib.logical_router_read(id=router_obj.uuid) except vnc_exc.NoIdError: @@ -61,18 +172,11 @@ def add_snat_instance(self, router_obj): si_fq_name = project_obj.fq_name + [si_name] try: si_obj = self._vnc_lib.service_instance_read(fq_name=si_fq_name) - si_uuid = si_obj.uuid except vnc_exc.NoIdError: si_obj = None # Get route table for default route it it exists - rt_name = 'rt_' + router_obj.uuid - rt_fq_name = project_obj.fq_name + [rt_name] - try: - rt_obj = self._vnc_lib.route_table_read(fq_name=rt_fq_name) - rt_uuid = rt_obj.uuid - except vnc_exc.NoIdError: - rt_obj = None + rt_obj = self._get_route_table(router_obj, project_obj) # Set the service instance si_created = False @@ -85,7 +189,8 @@ def add_snat_instance(self, router_obj): auto_policy=True) # set right interface in order of [right, left] to match template - left_if = ServiceInstanceInterfaceType() + vn_left_fq_name = self._get_snat_vn(project_obj, si_obj) + left_if = ServiceInstanceInterfaceType(virtual_network=vn_left_fq_name) virtual_network = router_obj.virtual_network vn_obj = VirtualNetworkSM.get(virtual_network) right_if = ServiceInstanceInterfaceType( @@ -95,8 +200,9 @@ def add_snat_instance(self, router_obj): si_obj.set_service_instance_properties(si_prop_obj) si_obj.set_service_template(st_obj) + if si_created: - si_uuid = self._vnc_lib.service_instance_create(si_obj) + self._vnc_lib.service_instance_create(si_obj) else: self._vnc_lib.service_instance_update(si_obj) @@ -105,32 +211,26 @@ def add_snat_instance(self, router_obj): next_hop=si_obj.get_fq_name_str()) rt_created = False if not rt_obj: + rt_name = 'rt_' + router_obj.uuid rt_obj = RouteTable(name=rt_name, parent_obj=project_obj) rt_created = True rt_obj.set_routes(RouteTableType.factory([route_obj])) if rt_created: - rt_uuid = self._vnc_lib.route_table_create(rt_obj) + self._vnc_lib.route_table_create(rt_obj) else: self._vnc_lib.route_table_update(rt_obj) # Associate route table to all private networks connected onto # that router - for intf in router_obj.virtual_machine_interfaces or []: - vmi_obj = VirtualMachineInterfaceSM.locate(intf) - net_id = vmi_obj.virtual_network - try: - net_obj = self._vnc_lib.virtual_network_read(id=net_id) - except vnc_exc.NoIdError: - continue - net_obj.set_route_table(rt_obj) - self._vnc_lib.virtual_network_update(net_obj) + net_uuids = self._get_net_uuids(router_obj.virtual_machine_interfaces) + self._add_route_tables(net_uuids, rt_obj) # Add logical gateway virtual network vnc_rtr_obj.set_service_instance(si_obj) self._vnc_lib.logical_router_update(vnc_rtr_obj) # end add_snat_instance - def delete_snat_instance(self, router_obj): + def _delete_snat_instance(self, router_obj): try: vnc_rtr_obj = self._vnc_lib.logical_router_read(id=router_obj.uuid) except vnc_exc.NoIdError: @@ -152,26 +252,17 @@ def delete_snat_instance(self, router_obj): si_obj = None # Get route table for default route it it exists - rt_name = 'rt_' + router_obj.uuid - rt_fq_name = project_obj.get_fq_name() + [rt_name] - try: - rt_obj = self._vnc_lib.route_table_read(fq_name=rt_fq_name) - rt_uuid = rt_obj.uuid - except vnc_exc.NoIdError: - rt_obj = None + rt_obj = self._get_route_table(router_obj, project_obj) # Delete route table if rt_obj: - # Disassociate route table to all private networks connected - # onto that router - for net_ref in rt_obj.get_virtual_network_back_refs() or []: - try: - net_obj = self._vnc_lib.virtual_network_read( - id=net_ref['uuid']) - except vnc_exc.NoIdError: - continue - net_obj.del_route_table(rt_obj) - self._vnc_lib.virtual_network_update(net_obj) + if (hasattr(rt_obj, 'virtual_network_back_refs') and + rt_obj.virtual_network_back_refs): + # Disassociate route table to all private networks connected + # onto that router + uuids = [ref['uuid'] for ref in + rt_obj.virtual_network_back_refs] + self._del_route_tables(uuids, rt_obj) self._vnc_lib.route_table_delete(id=rt_obj.uuid) if vnc_rtr_obj: @@ -188,11 +279,6 @@ def delete_snat_instance(self, router_obj): # end delete_snat_instance def cleanup_snat_instance(self, lr_id, si_id): - try: - vnc_rtr_obj = self._vnc_lib.logical_router_read(id=lr_id) - except vnc_exc.NoIdError: - vnc_rtr_obj = None - # Get the service instance if it exists try: si_obj = self._vnc_lib.service_instance_read(id=si_id) @@ -204,7 +290,6 @@ def cleanup_snat_instance(self, lr_id, si_id): rt_fq_name = si_obj.get_fq_name()[0:2] + [rt_name] try: rt_obj = self._vnc_lib.route_table_read(fq_name=rt_fq_name) - rt_uuid = rt_obj.uuid except vnc_exc.NoIdError: rt_obj = None @@ -212,18 +297,11 @@ def cleanup_snat_instance(self, lr_id, si_id): if rt_obj: # Disassociate route table to all private networks connected # onto that router - for net_ref in rt_obj.get_virtual_network_back_refs() or []: - try: - net_obj = self._vnc_lib.virtual_network_read( - id=net_ref['uuid']) - except vnc_exc.NoIdError: - continue - net_obj.del_route_table(rt_obj) - self._vnc_lib.virtual_network_update(net_obj) + uuids = [ref['uuid'] for ref in + rt_obj.virtual_network_back_refs] + self._del_route_tables(uuids, rt_obj) self._vnc_lib.route_table_delete(id=rt_obj.uuid) + # Delete service instance - if si_obj: - self._vnc_lib.service_instance_delete(id=si_id) + self._vnc_lib.service_instance_delete(id=si_id) # end cleanup_snat_instance - - diff --git a/src/config/svc-monitor/svc_monitor/svc_monitor.py b/src/config/svc-monitor/svc_monitor/svc_monitor.py index b6c50704b7b..f71f080011d 100644 --- a/src/config/svc-monitor/svc_monitor/svc_monitor.py +++ b/src/config/svc-monitor/svc_monitor/svc_monitor.py @@ -44,6 +44,7 @@ import discoveryclient.client as client +from agent_manager import AgentManager from db import ServiceMonitorDB from logger import ServiceMonitorLogger from loadbalancer_agent import LoadbalancerAgent @@ -130,6 +131,9 @@ class SvcMonitor(object): "project": { 'self': [], }, + "logical_router": { + 'self': [], + }, } def __init__(self, args=None): @@ -295,6 +299,9 @@ def post_init(self, vnc_lib, args=None): 'svc_monitor.nova_client.ServiceMonitorNovaClient', self._args, self.logger) + # agent manager + self._agent_manager = AgentManager() + # load vrouter scheduler self.vrouter_scheduler = importutils.import_object( self._args.si_netns_scheduler_driver, @@ -305,23 +312,32 @@ def post_init(self, vnc_lib, args=None): self.vm_manager = importutils.import_object( 'svc_monitor.virtual_machine_manager.VirtualMachineManager', self._vnc_lib, self._cassandra, self.logger, - self.vrouter_scheduler, self._nova_client, self._args) + self.vrouter_scheduler, self._nova_client, self._agent_manager, + self._args) # load network namespace instance manager self.netns_manager = importutils.import_object( 'svc_monitor.instance_manager.NetworkNamespaceManager', self._vnc_lib, self._cassandra, self.logger, - self.vrouter_scheduler, self._nova_client, self._args) + self.vrouter_scheduler, self._nova_client, self._agent_manager, + self._args) # load a vrouter instance manager self.vrouter_manager = importutils.import_object( 'svc_monitor.vrouter_instance_manager.VRouterInstanceManager', self._vnc_lib, self._cassandra, self.logger, - self.vrouter_scheduler, self._nova_client, self._args) + self.vrouter_scheduler, self._nova_client, + self._agent_manager, self._args) # load a loadbalancer agent - self.loadbalancer_agent = LoadbalancerAgent(self, self._vnc_lib, self._args) - self.snat_agent = SNATAgent(self, self._vnc_lib) + self.loadbalancer_agent = LoadbalancerAgent(self, self._vnc_lib, + self._cassandra, self._args) + self._agent_manager.register_agent(self.loadbalancer_agent) + + # load a snat agent + self.snat_agent = SNATAgent(self, self._vnc_lib, + self._cassandra, self._args) + self._agent_manager.register_agent(self.snat_agent) # Read the cassandra and populate the entry in ServiceMonitor DB self.sync_sm() @@ -567,13 +583,12 @@ def sync_sm(self): continue self.check_link_si_to_vm(vm, vmi) - ok, lr_list = self._cassandra._cassandra_logical_router_list() if not ok: pass else: for fq_name, uuid in lr_list: - lr = LogicalRouterSM.locate(uuid) + LogicalRouterSM.locate(uuid) # Load the loadbalancer driver self.loadbalancer_agent.load_drivers() diff --git a/src/config/svc-monitor/svc_monitor/tests/test_snat.py b/src/config/svc-monitor/svc_monitor/tests/test_snat.py index d8c342b1dfd..95ccb869c1c 100644 --- a/src/config/svc-monitor/svc_monitor/tests/test_snat.py +++ b/src/config/svc-monitor/svc_monitor/tests/test_snat.py @@ -98,38 +98,41 @@ def vr_read(vm_id): self.mocked_args = mock.MagicMock() self.mocked_args.availability_zone = None + self.mocked_manager = mock.MagicMock() + self.netns_manager = NetworkNamespaceManager( db=self.mocked_db, logger=mock.MagicMock(), vnc_lib=self.mocked_vnc, vrouter_scheduler=mock.MagicMock(), - nova_client=self.nova_mock, args=self.mocked_args) + nova_client=self.nova_mock, agent_manager=self.mocked_manager, + args=self.mocked_args) def tearDown(self): ServiceTemplateSM.delete('fake-st-uuid') ServiceInstanceSM.delete('fake-si-uuid') pass - def create_test_project(self, fq_name_str): + def _create_test_project(self, fq_name_str): proj_obj = {} proj_obj['fq_name'] = fq_name_str.split(':') proj_obj['uuid'] = fq_name_str proj_obj['id_perms'] = 'fake-id-perms' ProjectSM.locate(proj_obj['uuid'], proj_obj) - def create_test_virtual_network(self, fq_name_str): + def _create_test_virtual_network(self, fq_name_str): vn_obj = {} vn_obj['fq_name'] = fq_name_str.split(':') vn_obj['uuid'] = fq_name_str vn_obj['id_perms'] = 'fake-id-perms' VirtualNetworkSM.locate(vn_obj['uuid'], vn_obj) - def create_test_security_group(self, fq_name_str): + def _create_test_security_group(self, fq_name_str): sg_obj = {} sg_obj['fq_name'] = fq_name_str.split(':') sg_obj['uuid'] = fq_name_str sg_obj['id_perms'] = 'fake-id-perms' SecurityGroupSM.locate(sg_obj['uuid'], sg_obj) - def create_test_virtual_machine(self, fq_name_str): + def _create_test_virtual_machine(self, fq_name_str): vm_obj = {} vm_obj['fq_name'] = fq_name_str.split(':') vm_obj['uuid'] = fq_name_str @@ -139,9 +142,10 @@ def create_test_virtual_machine(self, fq_name_str): return vm def test_snat_instance_create(self): - self.create_test_project('fake-domain:fake-project') - self.create_test_virtual_network('fake-domain:fake-project:public-vn') - self.create_test_security_group('fake-domain:fake-project:default') + self._create_test_project('fake-domain:fake-project') + self._create_test_virtual_network('fake-domain:fake-project:public-vn') + self._create_test_virtual_network('fake-domain:fake-project:fake-vn-uuid') + self._create_test_security_group('fake-domain:fake-project:default') st_obj = {} st_obj['fq_name'] = ['fake-domain', 'fake-snat-template'] @@ -164,7 +168,7 @@ def test_snat_instance_create(self): si_props = {} si_props['scale_out'] = {'max_instances': 2} si_props['interface_list'] = [{'virtual_network': 'fake-domain:fake-project:public-vn'}, - {'virtual_network': ''}] + {'virtual_network': 'fake-domain:fake-project:fake-vn-uuid'}] si_obj['service_instance_properties'] = si_props st = ServiceTemplateSM.locate('fake-st-uuid', st_obj) @@ -173,7 +177,7 @@ def test_snat_instance_create(self): self.netns_manager.create_service(st, si) self.mocked_vnc.virtual_machine_create.assert_any_call(VMObjMatcher(1)) self.mocked_vnc.virtual_machine_create.assert_any_call(VMObjMatcher(2)) - self.assertEqual(si.vn_info[1]['net-id'], 'fake-vn-uuid') + self.assertEqual(si.vn_info[1]['net-id'], 'fake-domain:fake-project:fake-vn-uuid') def test_snat_instance_delete(self): def create_fake_virtual_machine(fq_name_str): diff --git a/src/config/svc-monitor/svc_monitor/tests/test_snat_agent.py b/src/config/svc-monitor/svc_monitor/tests/test_snat_agent.py new file mode 100644 index 00000000000..8b09d15e9f5 --- /dev/null +++ b/src/config/svc-monitor/svc_monitor/tests/test_snat_agent.py @@ -0,0 +1,480 @@ +import copy +import json +import mock +import unittest + +from cfgm_common.vnc_db import DBBase +from svc_monitor import config_db +from svc_monitor import instance_manager +from svc_monitor import snat_agent +from vnc_api.vnc_api import * + + +ROUTER_1 = { + 'fq_name': ['default-domain', 'demo', 'router1'], + 'parent_uuid': 'a8d55cfc-c66a-4eeb-82f8-d144fe74c46b', + 'uuid': '8e9b4859-d4c2-4ed5-9468-4809b1a926f3', + 'virtual_machine_interface_refs': [ + {'attr': None, + 'to': ['default-domain', + 'demo', + 'ccc56e1c-a749-4147-9f2f-a04b32bd658d'], + 'uuid': 'ccc56e1c-a749-4147-9f2f-a04b32bd658d'}], + 'virtual_network_refs': [ + {'attr': None, + 'to': ['default-domain', 'demo', 'public'], + 'uuid': '4f60e029-6029-4039-ad3a-4e4eb0e89407'}] +} + + +class RouteTableMatcher(object): + + def __init__(self, prefix): + self._prefix = prefix + + def __eq__(self, rt_obj): + prefix = rt_obj.get_routes().route[0].prefix + return self._prefix == prefix + + +class VirtualNetworkRouteTableMatcher(object): + + def __init__(self, net_name, rt_name): + self._net_name = net_name + self._rt_name = rt_name + + def __eq__(self, net_obj): + if self._rt_name: + return (net_obj.fq_name[-1] == self._net_name and + net_obj.get_route_table_refs()[0]['to'][-1] == + self._rt_name) + else: + return (net_obj.fq_name[-1] == self._net_name and + not net_obj.get_route_table_refs()) + + +class VirtualNetworkMatcher(object): + + def __init__(self, name, user_visible): + self._name = name + self._user_visible = user_visible + + def __eq__(self, net_obj): + user_visible = net_obj.get_id_perms().get_user_visible() + return (net_obj.get_fq_name_str() == self._name and + user_visible == self._user_visible) + + +class ServiceInstanceMatcher(object): + + def __init__(self, name, left, right, mode): + self._name = name + self._left = left + self._right = right + self._mode = mode + + def __eq__(self, si_obj): + si_props = si_obj.get_service_instance_properties() + mode = si_props.get_ha_mode() + right = si_props.get_interface_list()[0].get_virtual_network() + left = si_props.get_interface_list()[1].get_virtual_network() + + return (si_obj.fq_name[-1] == self._name and + mode == self._mode and + left == self._left and + right == self._right) + + +class LogicalRouterMatcher(object): + + def __init__(self, si_name): + self._si_name = si_name + + def __eq__(self, rtr_obj): + if self._si_name: + return (rtr_obj.get_service_instance_refs()[0]['to'][-1] == + self._si_name) + else: + return not rtr_obj.get_service_instance_refs() + + +class SnatAgentTest(unittest.TestCase): + + def setUp(self): + self.vnc_lib = mock.Mock() + + self.cassandra = mock.Mock() + self.logger = mock.Mock() + + self.svc = mock.Mock() + self.svc.netns_manager = instance_manager.NetworkNamespaceManager( + self.vnc_lib, self.cassandra, self.logger, None, None, None) + + self.snat_agent = snat_agent.SNATAgent(self.svc, self.vnc_lib, + self.cassandra, None) + DBBase.init(self, None, self.cassandra) + + # register the project + proj_fq_name = ['default-domain', 'demo'] + config_db.ProjectSM.locate( + ROUTER_1['parent_uuid'], + {'fq_name': proj_fq_name}) + + project = Project(name=proj_fq_name[-1]) + self.vnc_lib.project_read = mock.Mock( + return_value=project) + + # register the public network + config_db.VirtualNetworkSM.locate( + ROUTER_1['virtual_network_refs'][0]['uuid'], + {'fq_name': ROUTER_1['virtual_network_refs'][0]['to']}) + + # register interfaces + config_db.VirtualMachineInterfaceSM.locate( + ROUTER_1['virtual_machine_interface_refs'][0]['uuid'], + {'fq_name': ROUTER_1['virtual_machine_interface_refs'][0]['to'], + 'virtual_network_refs': [{'uuid': 'private1-uuid'}]}) + + def tearDown(self): + config_db.LogicalRouterSM.reset() + config_db.VirtualNetworkSM.reset() + config_db.VirtualMachineInterfaceSM.reset() + + def obj_to_dict(self, obj): + def to_json(obj): + if hasattr(obj, 'serialize_to_json'): + return obj.serialize_to_json(obj.get_pending_updates()) + else: + return dict((k, v) for k, v in obj.__dict__.iteritems()) + + return json.loads(json.dumps(obj, default=to_json)) + + def test_gateway_set(self): + router_obj = LogicalRouter('rtr1-name') + self.vnc_lib.logical_router_read = mock.Mock(return_value=router_obj) + + # will return the private virtual network, and will return + # an error when trying to read the service snat VN + def vn_read_side_effect(uuids): + if 'private1-uuid' in uuids: + return (True, [{'fq_name': ['default-domain', + 'demo', + 'private1-name'], + 'uuid': 'private1-uuid'}]) + elif 'snat-vn-uuid' in uuids: + return (True, [{'fq_name': ['default-domain', + 'demo', + 'snat-si-left_si_' + ROUTER_1['uuid']], + 'uuid': 'snat-vn-uuid'}]) + return (False, None) + + self.cassandra._cassandra_virtual_network_read = mock.Mock( + side_effect=vn_read_side_effect) + + def vn_create_side_effect(vn_obj): + if vn_obj.name == ('snat-si-left_si_' + ROUTER_1['uuid']): + vn_obj.uuid = 'snat-vn-uuid' + + self.vnc_lib.virtual_network_create = mock.Mock( + side_effect=vn_create_side_effect) + + self.vnc_lib.service_instance_read = mock.Mock(return_value=None) + self.vnc_lib.route_table_read = mock.Mock(return_value=None) + + def no_id_side_effect(type, fq_name): + if type == 'network-ipam': + return 'fake-uuid' + + raise NoIdError("xxx") + + self.cassandra.fq_name_to_uuid = mock.Mock(side_effect=no_id_side_effect) + + self.vnc_lib.route_table_create = mock.Mock() + self.vnc_lib.virtual_network_update = mock.Mock() + + router = config_db.LogicalRouterSM.locate(ROUTER_1['uuid'], + ROUTER_1) + self.snat_agent.update_snat_instance(router) + + # check that the correct private network is read + self.cassandra._cassandra_virtual_network_read.assert_called_with( + ['private1-uuid']) + + # check that the snat service network is created + left = ('default-domain:demo:snat-si-left_si_' + + ROUTER_1['uuid']) + self.vnc_lib.virtual_network_create.assert_called_with( + VirtualNetworkMatcher(left, False)) + + # route table that is going to be set for each interface + self.vnc_lib.route_table_create.assert_called_with( + RouteTableMatcher('0.0.0.0/0')) + + # check that the route table is applied to the network + rt_name = 'rt_' + ROUTER_1['uuid'] + self.vnc_lib.virtual_network_update.assert_called_with( + VirtualNetworkRouteTableMatcher('private1-name', rt_name)) + + # check that the SI is correctly set with the right interfaces + right = ':'.join(ROUTER_1['virtual_network_refs'][0]['to']) + self.vnc_lib.service_instance_create.assert_called_with( + ServiceInstanceMatcher('si_' + ROUTER_1['uuid'], + left, right, 'active-standby')) + + # check that the SI created is set to the logical router + self.vnc_lib.logical_router_update.assert_called_with( + LogicalRouterMatcher('si_' + ROUTER_1['uuid'])) + + def _test_snat_delete(self, router_dict): + self.test_gateway_set() + + # reset all calls + self.vnc_lib.virtual_network_update.reset_mock() + self.vnc_lib.service_instance_read.reset_mock() + + # now we have a route table + def no_id_side_effect(type, fq_name): + if type == 'route-table': + return 'fake-uuid' + + raise NoIdError("xxx") + + self.cassandra.fq_name_to_uuid = mock.Mock( + side_effect=no_id_side_effect) + + si_obj = ServiceInstance('si_' + ROUTER_1['uuid']) + si_obj.set_uuid('si-uuid') + self.vnc_lib.service_instance_read.return_value = si_obj + + # get and use the route table previously created + rt_obj = self.vnc_lib.route_table_create.mock_calls[0][1][0] + rt_dict = self.obj_to_dict(rt_obj) + rt_dict['virtual_network_back_refs'] = [{'uuid': 'private1-uuid'}] + self.cassandra._cassandra_route_table_read = mock.Mock( + return_value=(True, [rt_dict])) + + router = config_db.LogicalRouterSM.locate(ROUTER_1['uuid']) + router.update(router_dict) + self.snat_agent.update_snat_instance(router) + + self.vnc_lib.service_instance_read.assert_called_with( + fq_name=router_dict['service_instance_refs'][0]['to']) + + # check that the route table is removed from the networks + self.vnc_lib.virtual_network_update.assert_called_with( + VirtualNetworkRouteTableMatcher('private1-name', None)) + + # check that the route table is deleted + self.vnc_lib.route_table_delete.assert_called_with(id=rt_obj.uuid) + + # check that the SI is removed from the logical router + self.vnc_lib.logical_router_update.assert_called_with( + LogicalRouterMatcher(None)) + + # check that the SI is beeing to be deleted + self.vnc_lib.service_instance_delete.assert_called_with( + id=si_obj.get_uuid()) + + # Test cleanup of snat SI created without internat interfaces + def test_snat_delete_without_rt_net_back_refs(self): + self.test_gateway_set() + + # reset all calls + self.vnc_lib.virtual_network_update.reset_mock() + self.vnc_lib.service_instance_read.reset_mock() + + # now we have a route table + def no_id_side_effect(type, fq_name): + if type == 'route-table': + return 'fake-uuid' + + raise NoIdError("xxx") + + self.cassandra.fq_name_to_uuid = mock.Mock( + side_effect=no_id_side_effect) + + si_obj = ServiceInstance('si_' + ROUTER_1['uuid']) + si_obj.set_uuid('si-uuid') + self.vnc_lib.service_instance_read.return_value = si_obj + + # get and use the route table previously created, but without + # any back_refs to virtual networks + rt_obj = self.vnc_lib.route_table_create.mock_calls[0][1][0] + rt_dict = self.obj_to_dict(rt_obj) + self.cassandra._cassandra_route_table_read = mock.Mock( + return_value=(True, [rt_dict])) + + router_dict = copy.deepcopy(ROUTER_1) + router_dict['virtual_machine_interface_refs'] = [] + router_dict['service_instance_refs'] = [ + {'to': ['default-domain', + 'demo', + 'si_' + ROUTER_1['uuid']], + 'uuid': 'si-uuid'}] + + router = config_db.LogicalRouterSM.locate(ROUTER_1['uuid']) + router.update(router_dict) + self.snat_agent.update_snat_instance(router) + + self.vnc_lib.service_instance_read.assert_called_with( + fq_name=router_dict['service_instance_refs'][0]['to']) + + # check that the route table is deleted + self.vnc_lib.route_table_delete.assert_called_with(id=rt_obj.uuid) + + # check that the SI is removed from the logical router + self.vnc_lib.logical_router_update.assert_called_with( + LogicalRouterMatcher(None)) + + # check that the SI is beeing to be deleted + self.vnc_lib.service_instance_delete.assert_called_with( + id=si_obj.get_uuid()) + + def test_gateway_clear(self): + + # update the previous router by removing the ext net + router_dict = copy.deepcopy(ROUTER_1) + router_dict['virtual_network_refs'] = [] + router_dict['service_instance_refs'] = [ + {'to': ['default-domain', + 'demo', + 'si_' + ROUTER_1['uuid']], + 'uuid': 'si-uuid'}] + + self._test_snat_delete(router_dict) + + def test_no_more_interface(self): + + # update the previous router by removing all the interfaces + router_dict = copy.deepcopy(ROUTER_1) + router_dict['virtual_machine_interface_refs'] = [] + router_dict['service_instance_refs'] = [ + {'to': ['default-domain', + 'demo', + 'si_' + ROUTER_1['uuid']], + 'uuid': 'si-uuid'}] + + self._test_snat_delete(router_dict) + + def test_add_interface(self): + self.test_gateway_set() + + # update the previous router by removing all the interfaces + router_dict = copy.deepcopy(ROUTER_1) + router_dict['virtual_machine_interface_refs'].append( + {'attr': None, + 'to': ['default-domain', + 'demo', + 'd0022578-5b16-4da8-bd4d-5760faf134dc'], + 'uuid': 'd0022578-5b16-4da8-bd4d-5760faf134dc'}) + router_dict['service_instance_refs'] = [ + {'to': ['default-domain', + 'demo', + 'si_' + ROUTER_1['uuid']], + 'uuid': 'si-uuid'}] + + config_db.VirtualMachineInterfaceSM.locate( + router_dict['virtual_machine_interface_refs'][1]['uuid'], + {'fq_name': router_dict['virtual_machine_interface_refs'][1]['to'], + 'virtual_network_refs': [{'uuid': 'private2-uuid'}]}) + + # reset all calls + self.vnc_lib.virtual_network_update.reset_mock() + self.vnc_lib.service_instance_read.reset_mock() + self.vnc_lib.virtual_network_read.reset_mock() + + # now we have a route table + def no_id_side_effect(type, fq_name): + if type == 'route-table': + return 'fake-uuid' + + raise NoIdError("xxx") + + self.cassandra.fq_name_to_uuid = mock.Mock( + side_effect=no_id_side_effect) + + # get and use the route table previously created + rt_obj = self.vnc_lib.route_table_create.mock_calls[0][1][0] + rt_dict = self.obj_to_dict(rt_obj) + rt_dict['virtual_network_back_refs'] = [{'uuid': 'private1-uuid'}] + self.cassandra._cassandra_route_table_read = mock.Mock( + return_value=(True, [rt_dict])) + + def vn_read_side_effect(uuids): + if 'private2-uuid' in uuids: + return (True, [{'fq_name': ['default-domain', + 'demo', + 'private2-name'], + 'uuid': 'private2-uuid'}]) + return (False, None) + + self.cassandra._cassandra_virtual_network_read = mock.Mock( + side_effect=vn_read_side_effect) + + # generate an update on the router to add the interface + router = config_db.LogicalRouterSM.locate(ROUTER_1['uuid']) + router.update(router_dict) + self.snat_agent.update_snat_instance(router) + + # check that the correct private network is read + self.cassandra._cassandra_virtual_network_read.assert_called_with( + ['private2-uuid']) + + # check that the route table is applied to the network + rt_name = 'rt_' + ROUTER_1['uuid'] + self.vnc_lib.virtual_network_update.assert_called_with( + VirtualNetworkRouteTableMatcher('private2-name', rt_name)) + + def test_del_interface(self): + self.test_add_interface() + + # update the previous router by removing all the interfaces + router_dict = copy.deepcopy(ROUTER_1) + router_dict['virtual_machine_interface_refs'] = [ + {'attr': None, + 'to': ['default-domain', + 'demo', + 'd0022578-5b16-4da8-bd4d-5760faf134dc'], + 'uuid': 'd0022578-5b16-4da8-bd4d-5760faf134dc'}] + router_dict['service_instance_refs'] = [ + {'to': ['default-domain', + 'demo', + 'si_' + ROUTER_1['uuid']], + 'uuid': 'si-uuid'}] + + # reset all calls + self.vnc_lib.virtual_network_update.reset_mock() + self.vnc_lib.service_instance_read.reset_mock() + self.vnc_lib.virtual_network_read.reset_mock() + + self.vnc_lib.virtual_network_read = mock.Mock( + return_value=VirtualNetwork(name='private1-name')) + + # get and use the route table previously created + rt_obj = self.vnc_lib.route_table_create.mock_calls[0][1][0] + self.cassandra._cassandra_route_table_read = mock.Mock( + return_value=(True, [self.obj_to_dict(rt_obj)])) + + def vn_read_side_effect(uuids): + if 'private1-uuid' in uuids: + return (True, [{'fq_name': ['default-domain', + 'demo', + 'private1-name'], + 'uuid': 'private1-uuid'}]) + return (False, None) + + self.cassandra._cassandra_virtual_network_read = mock.Mock( + side_effect=vn_read_side_effect) + + # generate an update on the router to remove the interface + router = config_db.LogicalRouterSM.locate(ROUTER_1['uuid']) + router.update(router_dict) + self.snat_agent.update_snat_instance(router) + + # check that the correct private network is read + self.cassandra._cassandra_virtual_network_read.assert_called_with( + ['private1-uuid']) + + # check that the route table is applied to the network + self.vnc_lib.virtual_network_update.assert_called_with( + VirtualNetworkRouteTableMatcher('private1-name', None)) diff --git a/src/config/svc-monitor/test-requirements.txt b/src/config/svc-monitor/test-requirements.txt index 3452a1d8527..1b32034192e 100644 --- a/src/config/svc-monitor/test-requirements.txt +++ b/src/config/svc-monitor/test-requirements.txt @@ -8,6 +8,7 @@ geventhttpclient psutil bottle distribute>=0.7.3 +subunit ../../../debug/config/common/dist/cfgm_common-0.1dev.tar.gz ../../../debug/api-lib/dist/vnc_api-0.1dev.tar.gz ../../../debug/discovery/client/dist/discoveryclient-0.1dev.tar.gz diff --git a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py index d7a1d425e31..79cd0f2f2ad 100644 --- a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py +++ b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py @@ -33,7 +33,6 @@ DELETE = 4 # SNAT defines -SNAT_SERVICE_TEMPLATE_FQ_NAME = ['default-domain', 'netns-snat-template'] _IFACE_ROUTE_TABLE_NAME_PREFIX = 'NEUTRON_IFACE_RT' class DBInterface(object): @@ -1891,14 +1890,14 @@ def _gw_port_vnc_to_neutron(self, port_obj, port_req_memo): vm_obj = self._vnc_lib.virtual_machine_read(id=vm_uuid) except NoIdError: return None - port_req_memo['virtual-machines'][vm_uuid] = vm_obj + port_req_memo['virtual-machines'][vm_uuid] = vm_obj si_refs = vm_obj.get_service_instance_refs() if not si_refs: return None try: - si_obj = self._vnc_lib.service_instance_read(id=si_refs[0]['uuid'], + si_obj = self._vnc_lib.service_instance_read(id=si_refs[0]['uuid'], fields=["logical_router_back_refs"]) except NoIdError: return None @@ -2889,7 +2888,7 @@ def policy_count(self, filters=None): return len(policy_info) #end policy_count - def _router_add_gateway(self, router_q, rtr_obj): + def _router_update_gateway(self, router_q, rtr_obj): ext_gateway = router_q.get('external_gateway_info', None) old_ext_gateway = self._get_external_gateway_info(rtr_obj) if ext_gateway or old_ext_gateway: @@ -2923,46 +2922,6 @@ def _router_clear_external_gateway(self, router_obj): router_obj.set_virtual_network_list([]) self._vnc_lib.logical_router_update(router_obj) - def _set_snat_routing_table(self, router_obj, network_id): - project_obj = self._project_read(proj_id=router_obj.parent_uuid) - rt_name = 'rt_' + router_obj.uuid - rt_fq_name = project_obj.get_fq_name() + [rt_name] - - try: - rt_obj = self._vnc_lib.route_table_read(fq_name=rt_fq_name) - rt_uuid = rt_obj.uuid - except NoIdError: - # No route table set with that router ID, the gateway is not set - return - - try: - net_obj = self._vnc_lib.virtual_network_read(id=network_id) - except NoIdError: - self._raise_contrail_exception( - 'NetworkNotFound', net_id=network_id) - net_obj.set_route_table(rt_obj) - self._vnc_lib.virtual_network_update(net_obj) - - def _clear_snat_routing_table(self, router_obj, network_id): - project_obj = self._project_read(proj_id=router_obj.parent_uuid) - rt_name = 'rt_' + router_obj.uuid - rt_fq_name = project_obj.get_fq_name() + [rt_name] - - try: - rt_obj = self._vnc_lib.route_table_read(fq_name=rt_fq_name) - rt_uuid = rt_obj.uuid - except NoIdError: - # No route table set with that router ID, the gateway is not set - return - - try: - net_obj = self._vnc_lib.virtual_network_read(id=network_id) - except NoIdError: - self._raise_contrail_exception( - 'NetworkNotFound', net_id=network_id) - net_obj.del_route_table(rt_obj) - self._vnc_lib.virtual_network_update(net_obj) - # router api handlers def router_create(self, router_q): #self._ensure_project_exists(router_q['tenant_id']) @@ -2971,7 +2930,7 @@ def router_create(self, router_q): rtr_uuid = self._resource_create('logical_router', rtr_obj) # read it back to update id perms rtr_obj = self._logical_router_read(rtr_uuid) - self._router_add_gateway(router_q, rtr_obj) + self._router_update_gateway(router_q, rtr_obj) ret_router_q = self._router_vnc_to_neutron(rtr_obj, rtr_repr='SHOW') return ret_router_q @@ -2996,7 +2955,7 @@ def router_update(self, rtr_id, router_q): router_q['id'] = rtr_id rtr_obj = self._router_neutron_to_vnc(router_q, UPDATE) self._logical_router_update(rtr_obj) - self._router_add_gateway(router_q, rtr_obj) + self._router_update_gateway(router_q, rtr_obj) ret_router_q = self._router_vnc_to_neutron(rtr_obj, rtr_repr='SHOW') return ret_router_q @@ -3188,7 +3147,6 @@ def add_router_interface(self, context, router_id, port_id=None, subnet_id=None) 'BadRequest', resource='router', msg='Either port or subnet must be specified') - self._set_snat_routing_table(router_obj, subnet['network_id']) vmi_obj = self._vnc_lib.virtual_machine_interface_read(id=port_id) vmi_obj.set_virtual_machine_interface_device_owner( constants.DEVICE_OWNER_ROUTER_INTF) @@ -3235,7 +3193,6 @@ def remove_router_interface(self, router_id, port_id=None, subnet_id=None): self._raise_contrail_exception('BadRequest', resource='router', msg=msg) - self._clear_snat_routing_table(router_obj, subnet['network_id']) port_obj = self._virtual_machine_interface_read(port_id) router_obj.del_virtual_machine_interface(port_obj) self._vnc_lib.logical_router_update(router_obj)