Ejemplo n.º 1
0
    def create_network_postcommit(self, context):
        super(KaloomOVSMechanismDriver,
              self).create_network_postcommit(context)

        network_id = context.current.get('id')
        nw_name = utils._kaloom_nw_name(self.prefix, network_id,
                                        context.current.get('name'))
        #force clean if vfabric network already exists, probably of unsuccessful delete_network_postcommit
        knid_mapping = kaloom_db.get_knid_mapping(network_id=network_id)
        if knid_mapping:
            try:
                self._clean_local_vlan_mappings(network_id)
                kaloom_db.delete_knid_mapping(network_id)
                self.kaloom.delete_l2_network(knid_mapping.network_name)
            except Exception as e:
                #forced clean: no error raise
                LOG.warning(
                    "create_network_postcommit: Error on clearing overlapping vfabric network=%s errors: %s",
                    knid_mapping.network_name, e)
        #create nw in vfabric
        try:
            knid = self.kaloom.create_l2_network(
                nw_name, kconst.DEFAULT_VLAN_ID).get('kaloom_knid')
        except Exception as e:
            LOG.error("errors: %s", e)
            #raising an exception will result in rollback of the transaction
            raise ml2_exc.MechanismDriverError(
                method='create_network_postcommit', errors=e)
        LOG.info("Created Kaloom network with KNID %d " % knid)
        kaloom_db.create_knid_mapping(kaloom_knid=knid,
                                      network_id=network_id,
                                      network_name=nw_name)
Ejemplo n.º 2
0
    def _set_external_gateway(self, context, router_id, network_id,
                             original_router, new_router):
        try:
            nw_name = utils._kaloom_nw_name(self.prefix, network_id)
        except n_exc.NetworkNotFound as e:
            msg = ('can not _set_external_gateway as no such network=%s, msg:%s' % (network_id, e))
            LOG.error(msg)
            return

        core = directory.get_plugin()

        ip_address = new_router['external_gateway_info']['external_fixed_ips'][0]['ip_address']
        subnet_id = new_router['external_gateway_info']['external_fixed_ips'][0]['subnet_id']
        subnet = core.get_subnet(context, subnet_id)

        # Package all the info needed for vFabric programming
        router_info = copy.deepcopy(new_router)
        router_info['nw_name'] = nw_name
        router_info['subnet_id'] = subnet_id
        router_info['ip_address'] = ip_address
        router_info['cidr'] = subnet['cidr']
        router_info['gip'] = subnet['gateway_ip']
        router_info['ip_version'] = subnet['ip_version']

        self.driver.add_router_interface(context, router_info)
        self._update_port_up(context, new_router['gw_port_id'])
Ejemplo n.º 3
0
    def _unset_external_gateway(self, context, router_id, router_unset_ext_gw):
        # Get ip_address info for the subnet that is being deleted from the router.
        original_router = self.get_router(context, router_id)
        core = directory.get_plugin()

        if original_router['external_gateway_info'] is None or len(original_router['external_gateway_info']['external_fixed_ips']) == 0: ##nothing to unset
            new_router = super(KaloomL3ServicePlugin, self).update_router(context, router_id, router_unset_ext_gw)
            return new_router

        ip_address = original_router['external_gateway_info']['external_fixed_ips'][0]['ip_address']
        subnet_id = original_router['external_gateway_info']['external_fixed_ips'][0]['subnet_id']
        subnet = core.get_subnet(context, subnet_id)

        # Update router DB
        new_router = super(KaloomL3ServicePlugin, self).update_router(context, router_id, router_unset_ext_gw)

        # Get network information of the gateway subnet that is being removed for vFabric programming
        network_id = subnet['network_id']
        try:
            nw_name = utils._kaloom_nw_name(self.prefix, network_id)
        except n_exc.NetworkNotFound as e:
            LOG.warning('can not _unset_external_gateway as no such network=%s, msg:%s', network_id, e)
            return new_router

        router_info = copy.deepcopy(new_router)
        router_info['nw_name'] = nw_name
        router_info['subnet_id'] = subnet_id
        router_info['ip_address'] = ip_address
        router_info['ip_version'] = subnet['ip_version']

        self.driver.remove_router_interface(context, router_info)
        return new_router
Ejemplo n.º 4
0
    def create_network_postcommit(self, context):
        super(KaloomOVSMechanismDriver,
              self).create_network_postcommit(context)
        #not allowed network_type
        if not self._is_network_type_allowed(context):
            return

        network_id = context.current.get('id')
        nw_name = utils._kaloom_nw_name(self.prefix, network_id)
        #create nw in vfabric
        gui_nw_name = utils._kaloom_gui_nw_name(self.prefix, network_id,
                                                context.current.get('name'))
        try:
            knid = self.vfabric.create_l2_network(
                nw_name, gui_nw_name,
                kconst.DEFAULT_VLAN_ID).get('kaloom_knid')
        except Exception as e:
            ##duplicate should not raise error (TYPE_KNID is used by both kaloom_ovs and kaloom_kvs mech driver)
            if "unique duplicate constraint" in str(e):
                return
            else:
                LOG.error("errors: %s", e)
                #raising an exception will result in rollback of the transaction
                raise ml2_exc.MechanismDriverError(
                    method='create_network_postcommit', errors=e)
        LOG.info("Created Kaloom network with KNID %d " % knid)
        kaloom_db.create_knid_mapping(kaloom_knid=knid, network_id=network_id)
Ejemplo n.º 5
0
    def cleanup(self):
        LOG.debug('cleanup..')
        #clean stranded networks in vfabric, that does not exist in openstack: e.g. created after netconf timeout, manually created.
        try:
            networks = kaloom_db.get_networks()
            openstack_nw_names = []
            for network in networks:
                nw_name = utils._kaloom_nw_name(self.prefix, network.id)
                openstack_nw_names.append(nw_name)
            vfabric_nw_names = self.vfabric.get_l2_network_names(self.prefix)
            stranded_nw_names = set(vfabric_nw_names) - set(openstack_nw_names)
            if len(stranded_nw_names) > 0:
                LOG.info("cleanup found stranded networks: %s, cleaning up..",
                         stranded_nw_names)
            for stranded_nw_name in stranded_nw_names:
                try:
                    network_id = stranded_nw_name.split(self.prefix)[1].split(
                        '_')[0]  #network_id is in between of prefix and _
                    knid_mapping = kaloom_db.get_knid_mapping(
                        network_id=network_id)
                    if knid_mapping:
                        kaloom_db.delete_knid_mapping(network_id)
                        clean_local_vlan_mappings(network_id)

                    self.vfabric.delete_l2_network(stranded_nw_name)
                except Exception as e:
                    LOG.warning(
                        "cleanup failed to delete stranded l2_network:%s in vfabric, err:%s",
                        stranded_nw_name, e)
        except Exception as e:
            LOG.warning("cleanup stranded networks: error caught err_msg:%s",
                        e)

        #clean stranded tp-attachment
        try:
            all_stale_vlan_mappings = kaloom_db.get_stale_vlan_mappings(
                self.creating_seconds, self.deleting_seconds)
        except Exception as e:
            LOG.warning(
                "cleanup stranded tp-attachment: error caught err_msg:%s", e)
            return

        if all_stale_vlan_mappings:
            ctx = nctx.get_admin_context()
            for m in all_stale_vlan_mappings:
                try:
                    LOG.info(
                        'Cleaning.. for host=%s network=%s vlan=%s state=%s timestamp:%s',
                        m.host, m.network_id, m.vlan_id, m.state, m.timestamp)
                    tp = self.vfabric.get_tp_by_annotation(m.host)
                    if tp:
                        self.vfabric.detach_tp_from_l2_network(
                            m.network_name, tp.get('id'))
                    remove_local_segment(ctx, m.segment_id)
                    remove_local_vlan_mapping(m)
                except Exception as e:
                    LOG.warning(
                        "cleanup: error caught for host=%s, network=%s err_msg:%s",
                        m.host, m.network_id, e)
Ejemplo n.º 6
0
    def _create_local_vlan_mapping(self, context, call_from):
        try:
            network_id = context.current.get('network_id')
            host = context.host
            getattr(super(KaloomOVSMechanismDriver, self), call_from)(context)
            kvs_present = self._is_kvs_agent_present(context)
            ovs_present = self._is_ovs_agent_present(context)
            if kvs_present:  #kaloom_ovs plugin found kvs_present, nothing to do.
                return
            if not ovs_present:
                LOG.warning(
                    "%s: KVS/OVS agent is not alive on host=%s, nothing to do.",
                    call_from, host)
                #don't raise to pass tempest test_portbinding_bumps_revision
                return
            #in case of ovs node binding.
            LOG.info("%s: Found OVS type agent, Using OVS specific logic",
                     call_from)
            nw_name = utils._kaloom_nw_name(self.prefix, network_id)
            local_vlan_mapping = kaloom_db.get_vlan_mapping_for_network_and_host(
                network_id, host)
            if local_vlan_mapping is None:
                physical_network = kaloom_db.get_segment_for_network(
                    network_id
                ).physical_network  #None segment raises exception
                #There is no possibility of concurrent tp_detach on delete_port_postcommit, as there is no remaining local_vlan_mapping.
                #lock concurrent attach/detach for vfabric TP
                if not utils.tp_operation_lock(host, network_id):
                    raise ValueError('Could not get lock.')
                try:
                    #default is state: 'CREATING'
                    local_vlan_mapping = self._allocate_local_vlan_mapping(
                        context, network_id, host, physical_network, nw_name)
                except:
                    pass
                finally:
                    utils.tp_operation_unlock(host, network_id)  #release lock

                if local_vlan_mapping is None:
                    msg = 'Vlan could not be allocated.'
                    raise ValueError(msg)
            #There could be concurrent ports deletion leading to tp_detach.
            elif local_vlan_mapping.state == 'DELETING':
                #DELETING: deletion ongoing or never finished.
                msg = 'vlan mapping state:%s exists, another concurrent tp_detach ongoing' % local_vlan_mapping.state
                raise ValueError(msg)
            #or concurrent ports creation leading to tp_attach.
            elif local_vlan_mapping.state == 'CREATING':
                #CREATING: another concurrent tp_attach not finished yet or never finished: try_to_bind anyway (duplicate tp_attach will be handeled.)
                pass
            return
        except Exception as e:
            LOG.error("Error during %s on host=%s, network=%s, err_msg:%s",
                      call_from, host, network_id, e)
            raise ml2_exc.MechanismDriverError(method=call_from,
                                               errors=e)  #rollback.
Ejemplo n.º 7
0
    def add_router_interface(self, context, router_id, interface_info):
        """Add a subnet of a network to an existing router."""
        router = self.get_router(context, router_id)
        # add_router_interface can't go in parallel with l3_sync_interface on same router
        # parallelism of router operations (on different router)
        # write (x) lock on "the router" during transaction.
        db_session = db_api.get_writer_session()
        with db_session.begin(subtransactions=True):
            caller_msg = 'add_router_interface on router id=%s name=%s' % (router_id, router['name'])
            kaloom_db.get_Lock(db_session, router_id, read=False, caller_msg = caller_msg)
            new_router_ifc = super(KaloomL3ServicePlugin, self).add_router_interface(
                context, router_id, interface_info)

            core = directory.get_plugin()

            # Get network info for the subnet that is being added to the router.
            # Check if the interface information is by port-id or subnet-id
            add_by_port, add_by_sub = self._validate_interface_info(interface_info)
            if add_by_sub:
                subnet = core.get_subnet(context, interface_info['subnet_id'])
                port = core.get_port(context, new_router_ifc['port_id'])
                #port has multiple (ip_address, subnet_id)
                ip_address = self._get_subnet_ip(port['fixed_ips'], interface_info['subnet_id'])
            elif add_by_port:
                port = core.get_port(context, interface_info['port_id'])
                ip_address = port['fixed_ips'][0]['ip_address']
                subnet_id = port['fixed_ips'][0]['subnet_id']
                subnet = core.get_subnet(context, subnet_id)

            # Package all the info needed for vFabric programming
            network_id = subnet['network_id']
            try:
                nw_name = utils._kaloom_nw_name(self.prefix, network_id)
            except n_exc.NetworkNotFound as e:
                LOG.warning('Nothing to do in add_router_interface as no such network=%s, msg:%s', network_id, e)
                return new_router_ifc

            router_info = copy.deepcopy(new_router_ifc)
            router_info['nw_name'] = nw_name
            router_info['ip_address'] = ip_address
            router_info['name'] = router['name']
            router_info['cidr'] = subnet['cidr']
            router_info['gip'] = subnet['gateway_ip']
            router_info['ip_version'] = subnet['ip_version']

            try:
                self.driver.add_router_interface(context, router_info)
                self._update_port_up(context, port['id'])
                return new_router_ifc
            except Exception:
                with excutils.save_and_reraise_exception():
                    super(KaloomL3ServicePlugin, self).remove_router_interface(
                        context,
                        router_id,
                        interface_info)
Ejemplo n.º 8
0
    def remove_router_interface(self, context, router_id, interface_info):
        """Remove a subnet of a network from an existing router."""
        router = self.get_router(context, router_id)
        # remove_router_interface can't go in parallel with l3_sync_interface on same router
        # parallelism of router operations (on different router)
        # write (x) lock on "the router" during transaction.
        db_session = db_api.get_writer_session()
        with db_session.begin(subtransactions=True):
            caller_msg = 'remove_router_interface on router id=%s name=%s' % (router_id, router['name'])
            kaloom_db.get_Lock(db_session, router_id, read=False, caller_msg = caller_msg)
            # Get ip_address info for the subnet that is being deleted from the router.
            # Check if the interface information is by port-id or subnet-id
            core = directory.get_plugin()
            add_by_port, add_by_sub = self._validate_interface_info(interface_info)
            if add_by_sub:
                subnet = core.get_subnet(context, interface_info['subnet_id'])
                ip_address = self._get_subnet_ip_from_router_info(router, interface_info['subnet_id'], subnet['network_id'], subnet['gateway_ip'])
            elif add_by_port:
                port = core.get_port(context, interface_info['port_id'])
                ip_address = port['fixed_ips'][0]['ip_address']
                subnet_id = port['fixed_ips'][0]['subnet_id']
                subnet = core.get_subnet(context, subnet_id)

            router_ifc_to_del = (
                super(KaloomL3ServicePlugin, self).remove_router_interface(
                    context,
                    router_id,
                    interface_info)
                )

            # Get network information of the subnet that is being removed
            network_id = subnet['network_id']
            try:
                nw_name = utils._kaloom_nw_name(self.prefix, network_id)
            except n_exc.NetworkNotFound as e:
                LOG.warning('Nothing to do in remove_router_interface as no such network=%s, msg:%s', network_id, e)
                return

            router_info = copy.deepcopy(router_ifc_to_del)
            router_info['nw_name'] = nw_name
            router_info['name'] = router['name']
            router_info['ip_address'] = ip_address
            router_info['ip_version'] = subnet['ip_version']

            try:
                self.driver.remove_router_interface(context, router_info)
                return router_ifc_to_del
            except Exception as e:
                msg = "remove_router_interface (router %s -- IP %s subnet_id %s) failed in vfabric: %s" % (router['name'], ip_address, subnet['id'], e)
                LOG.error(msg)
Ejemplo n.º 9
0
 def update_network_postcommit(self, context):
     super(KaloomOVSMechanismDriver,
           self).update_network_postcommit(context)
     #not allowed network_type
     if not self._is_network_type_allowed(context):
         return
     original_name = context.original.get('name')
     current_name = context.current.get('name')
     if current_name != original_name:  #nw renamed
         #rename vfabric network gui-name.
         network_id = context.current.get('id')
         nw_name = utils._kaloom_nw_name(self.prefix, network_id)
         current_gui_nw_name = utils._kaloom_gui_nw_name(
             self.prefix, network_id, current_name)
         try:
             self.vfabric.rename_l2_network(nw_name, current_gui_nw_name)
         except Exception as e:
             LOG.error("errors: %s", e)
Ejemplo n.º 10
0
    def delete_network_postcommit(self, context):
        super(KaloomOVSMechanismDriver,
              self).delete_network_postcommit(context)
        # don't check allowed network_type, as network's segments are deleted before this, resulting network_type=None.
        network_id = context.current.get('id')
        nw_name = utils._kaloom_nw_name(self.prefix, network_id)

        try:
            knid_mapping = kaloom_db.get_knid_mapping(network_id=network_id)
            if knid_mapping:  #rollback on create_network_postcommit calls delete_network so the knid_mapping may not exist
                kaloom_db.delete_knid_mapping(network_id)
                clean_local_vlan_mappings(network_id)
            #vfabric network could have been created after netconf timeout on create_l2_network i.e. even in case of non-existing knid_mapping.
            self.vfabric.delete_l2_network(
                nw_name
            )  #if this fails, cleanup process will take care of stranded vfabric networks.
        except Exception as e:
            LOG.warning("delete_network_postcommit network:%s err:%s", nw_name,
                        e)
        return
Ejemplo n.º 11
0
 def get_router_interfaces(self, r):
     core = directory.get_plugin()
     ctx = nctx.get_admin_context()
     grouped_router_interfaces = {}
     ports = core.get_ports(ctx, filters={'device_id': [r['id']]}) or []
     for p in ports:
         for fixed_ip in p['fixed_ips']:
             router_interface = r.copy()
             subnet_id = fixed_ip['subnet_id']
             subnet = core.get_subnet(ctx, subnet_id)
             network_id = p['network_id']
             nw_name = utils._kaloom_nw_name(self.prefix, network_id)
             router_interface['nw_name'] = nw_name
             router_interface['ip_address'] = fixed_ip['ip_address']
             router_interface['cidr'] = subnet['cidr']
             router_interface['gip'] = subnet['gateway_ip']
             router_interface['ip_version'] = subnet['ip_version']
             router_interface['subnet_id'] = subnet_id
             if nw_name in grouped_router_interfaces:
                 grouped_router_interfaces[nw_name].append(router_interface)
             else:
                 grouped_router_interfaces[nw_name] = [router_interface]
     return grouped_router_interfaces
Ejemplo n.º 12
0
    def _try_to_bind_segment_ovs_agent(self, context, segment, agent):
        network_id = segment.get('network_id')
        try:
            nw_name = utils._kaloom_nw_name(
                self.prefix, network_id, utils._get_network_name(network_id))
        except NetworkNotFound as e:
            LOG.error(e)
            return False
        host = context.current.get('binding:host_id')

        #lock concurrent attach/detach for vfabric TP
        if not utils.tp_operation_lock(host, network_id):
            return False

        try:
            local_vlan_mapping = kaloom_db.get_vlan_mapping_for_network_and_host(
                network_id, host)
            if local_vlan_mapping:
                if local_vlan_mapping.stale:
                    LOG.info(
                        'stale vlan=%s mapping found on host=%s, network=%s, reusing the same',
                        local_vlan_mapping.vlan_id, host, network_id)
                    kaloom_db.update_network_host_vlan_mapping(
                        network_id=network_id, host=host,
                        stale=False)  #no more stale

            else:  #in case of None
                try:
                    tp_id = self.kaloom.get_tp_by_annotation(host).get('id')
                except Exception as e:
                    msg = "Error on get_tp_by_annotation for host %s: %s" % (
                        host, e)
                    raise ValueError(msg)
                attach_name = '%s:%s' % (network_id, tp_id)
                local_vlan_mapping = self._allocate_local_vlan_mapping(
                    context, network_id, host, segment, nw_name)
                if local_vlan_mapping is None:
                    msg = 'Vlan could not be allocated.'
                    raise ValueError(msg)

                local_vlan_id = local_vlan_mapping.vlan_id
                try:
                    self.kaloom.attach_tp_to_l2_network(
                        nw_name, attach_name, tp_id, local_vlan_id)
                except Exception as e:
                    msg = "Error on attach_tp_to_l2_network for tpid %s vlan %s nw %s: %s" % (
                        tp_id, local_vlan_id, nw_name, e)
                    # release vlan and segment that was just created.
                    self._remove_local_segment(context._plugin_context,
                                               local_vlan_mapping.segment_id)
                    self._remove_local_vlan_mapping(local_vlan_mapping)
                    raise ValueError(msg)

            local_vlan_id = local_vlan_mapping.vlan_id
            local_seg_id = local_vlan_mapping.segment_id
            context.set_binding(local_seg_id,
                                self.get_vif_type(context, agent, segment),
                                self.get_vif_details(context, agent, segment))
            LOG.info("BINDED SEGMENT VLAN %d host %s segment %s " %
                     (local_vlan_id, host, local_seg_id))
            return True
        except Exception as e:
            LOG.error(
                "Error during bind_port on host=%s, network=%s, err_msg:%s",
                host, network_id, e)
            return False
        finally:
            utils.tp_operation_unlock(host, network_id)  #release lock
Ejemplo n.º 13
0
    def _try_to_bind_segment_ovs_agent(self, context, segment, agent):
        network_id = segment.get('network_id')
        host = context.current.get('binding:host_id')
        try:
            nw_name = utils._kaloom_nw_name(self.prefix, network_id)
            local_vlan_mapping = kaloom_db.get_vlan_mapping_for_network_and_host(
                network_id, host)
            #There could be concurrent ports deletion leading to tp_detach
            if local_vlan_mapping is None:  ## None implicitly means 'DELETED' state or doesnot exist
                msg = 'can not bind as vlan mapping doesnot exist.'
                raise ValueError(msg)
            if local_vlan_mapping.state == 'DELETING':
                #DELETING: deletion ongoing or never finished.
                msg = 'can not bind as vlan mapping state: %s, deletion ongoing' % local_vlan_mapping.state
                raise ValueError(msg)
            if local_vlan_mapping.state == 'CREATING':  #concurrent tp_attach has been allowed.
                try:
                    tp_id = self.vfabric.get_tp_by_annotation(host).get('id')
                except Exception as e:
                    msg = "Error on get_tp_by_annotation for host %s: %s" % (
                        host, e)
                    raise ValueError(msg)
                attach_name = '%s:%s' % (network_id, tp_id)
                local_vlan_id = local_vlan_mapping.vlan_id
                try:
                    self.vfabric.attach_tp_to_l2_network(
                        nw_name, attach_name, tp_id, local_vlan_id)
                except Exception as e:
                    ##duplicate should not raise error.
                    if "unique duplicate constraint" not in str(e):
                        msg = "Error on attach_tp_to_l2_network for tpid %s vlan %s nw %s: %s" % (
                            tp_id, local_vlan_id, nw_name, e)
                        raise ValueError(msg)

            local_vlan_id = local_vlan_mapping.vlan_id
            local_seg_id = local_vlan_mapping.segment_id
            original_state = local_vlan_mapping.state
            if original_state == 'CREATING':
                new_state = 'CREATED'
            else:
                new_state = original_state
            if new_state != original_state:
                status = kaloom_db.update_state_on_network_host_vlan_mapping(
                    network_id=network_id, host=host, state=new_state)
                if not status:  # concurrent deletion of "last port" already happened.
                    #rollback and raise error
                    self.vfabric.detach_tp_from_l2_network(nw_name, tp_id)
                    raise ValueError('concurrent deletion happened.')
            ##
            context.set_binding(local_seg_id,
                                self.get_vif_type(context, agent, segment),
                                self.get_vif_details(context, agent, segment))
            LOG.info(
                "state: %s -> %s, PORT BINDED on SEGMENT=%s, VLAN=%d of host=%s, network=%s"
                % (original_state, new_state, local_seg_id, local_vlan_id,
                   host, network_id))
            return True
        except Exception as e:
            LOG.error(
                "Error during bind_port on OVS host=%s, network=%s, err_msg:%s",
                host, network_id, e)
            return False
Ejemplo n.º 14
0
class KaloomL3DriverTestCase(base.BaseTestCase):
    PREFIX = '__OpenStack__'
    DB_CONTEXT = neutron_context.get_admin_context()
    ROUTER_INFO = {'id': uuidutils.generate_uuid(), 
                'name': 'router1',
                'nw_name': utils._kaloom_nw_name(PREFIX, uuidutils.generate_uuid()),
                'subnet_id': uuidutils.generate_uuid(),
                'ip_address': '192.168.1.15',
                'cidr':'192.168.1.15/24',
                'ip_version':'4',
                'gip': '192.168.1.1'}
    ROUTER_NODE_ID = uuidutils.generate_uuid()
    ROUTER_INTERFACE_INFO_FIRST_TIME = {'node_id': ROUTER_NODE_ID, 'interface': None, 'cidrs': []}
    ROUTER_INTERFACE_INFO_EXACT_STALE = {'node_id': ROUTER_NODE_ID, 'interface': 'net1', 'cidrs': ['192.168.1.15/24']}
    ROUTER_INTERFACE_INFO_NON_EXACT_OVERLAPPING = {'node_id': ROUTER_NODE_ID, 'interface': 'net1', 'cidrs': ['192.168.1.16/24']}

    @patch('networking_kaloom.services.l3.driver.KaloomNetconf',autospec=True)
    def setUp(self, mock_KaloomNetconf):
        super(KaloomL3DriverTestCase, self).setUp()
        self.driver = kaloom_l3_driver.KaloomL3Driver(self.PREFIX)
        self.mock_KaloomNetconf_instance = mock_KaloomNetconf.return_value

    def tearDown(self):
        super(KaloomL3DriverTestCase, self).tearDown()
        self.mock_KaloomNetconf_instance.reset_mock()
        LOG.error.reset_mock()
    
    def test_add_router_interface_first_time(self):
        self.mock_KaloomNetconf_instance.get_router_interface_info = Mock(return_value = self.ROUTER_INTERFACE_INFO_FIRST_TIME)
        self.driver.add_router_interface(self.DB_CONTEXT, self.ROUTER_INFO)

        self.mock_KaloomNetconf_instance.attach_router.assert_called_once()
        self.mock_KaloomNetconf_instance.delete_ipaddress_from_interface.assert_not_called()
        self.mock_KaloomNetconf_instance.add_ipaddress_to_interface.assert_called_once()
        LOG.error.assert_not_called
 
    def test_add_router_interface_exact_stale(self):
        self.mock_KaloomNetconf_instance.get_router_interface_info = Mock(return_value = self.ROUTER_INTERFACE_INFO_EXACT_STALE)
        self.driver.add_router_interface(self.DB_CONTEXT, self.ROUTER_INFO)

        self.mock_KaloomNetconf_instance.attach_router.assert_not_called()
        self.mock_KaloomNetconf_instance.delete_ipaddress_from_interface.assert_not_called()
        self.mock_KaloomNetconf_instance.add_ipaddress_to_interface.assert_not_called()
        LOG.error.assert_not_called

    def test_add_router_interface_non_exact_overlapping(self):
        self.mock_KaloomNetconf_instance.get_router_interface_info = Mock(return_value = self.ROUTER_INTERFACE_INFO_NON_EXACT_OVERLAPPING)
        self.driver.add_router_interface(self.DB_CONTEXT, self.ROUTER_INFO)

        self.mock_KaloomNetconf_instance.attach_router.assert_not_called()
        self.mock_KaloomNetconf_instance.delete_ipaddress_from_interface.assert_called_once()
        self.mock_KaloomNetconf_instance.add_ipaddress_to_interface.assert_called_once()
        LOG.error.assert_not_called

    def test_add_router_interface_undo_attach_router(self):
        self.mock_KaloomNetconf_instance.get_router_interface_info = Mock(return_value = self.ROUTER_INTERFACE_INFO_FIRST_TIME)
        self.mock_KaloomNetconf_instance.add_ipaddress_to_interface = Mock(side_effect = Exception('Boom!'))
        try:
           self.driver.add_router_interface(self.DB_CONTEXT, self.ROUTER_INFO)
        except:
           pass
        self.mock_KaloomNetconf_instance.attach_router.assert_called_once()
        self.mock_KaloomNetconf_instance.detach_router.assert_called_once()