diff --git a/networking_bgpvpn/neutron/services/service_drivers/bagpipe/bagpipe.py b/networking_bgpvpn/neutron/services/service_drivers/bagpipe/bagpipe.py index f6549ac6..475c0a72 100644 --- a/networking_bgpvpn/neutron/services/service_drivers/bagpipe/bagpipe.py +++ b/networking_bgpvpn/neutron/services/service_drivers/bagpipe/bagpipe.py @@ -89,16 +89,15 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver): def service_type(self): return BAGPIPE_BGPVPN - def _format_bgpvpn(self, bgpvpn): + def _format_bgpvpn(self, bgpvpn, network_id): """JSON-format BGPVPN BGPVPN, network identifiers, and route targets. """ formatted_bgpvpn = {'id': bgpvpn['id'], - 'network_id': bgpvpn['network_id']} + 'network_id': network_id} formatted_bgpvpn.update( - self._format_bgpvpn_network_route_targets([bgpvpn]) - ) + self._format_bgpvpn_network_route_targets([bgpvpn])) return formatted_bgpvpn @@ -123,7 +122,6 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver): """ bgpvpn_rts = {} - LOG.debug('BGPVPN to format %s' % bgpvpns) for bgpvpn in bgpvpns: # Add necessary keys to BGP VPN route targets dictionary if bgpvpn['type'] + 'vpn' not in bgpvpn_rts: @@ -222,76 +220,36 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver): return (added, removed, changed) - def create_bgpvpn_postcommit(self, context, bgpvpn): - # Notify only if BGPVPN associated to a network - # and network has already plugged ports - if (bgpvpn['network_id'] is not None and - get_network_ports(context, bgpvpn['network_id'])): - # Format BGPVPN before sending notification - self.agent_rpc.create_bgpvpn( - context, - self._format_bgpvpn(bgpvpn) - ) - def delete_bgpvpn_postcommit(self, context, bgpvpn): - # Notify only if BGPVPN associated to a network - # and network has already plugged ports - # In the case it was dissociated before delete, update notification - # will do the job (all ports are detached) - if (bgpvpn['network_id'] is not None and - get_network_ports(context, bgpvpn['network_id'])): - # Format BGPVPN before sending notification - self.agent_rpc.delete_bgpvpn( + for net_id in bgpvpn['networks']: + if get_network_ports(context, net_id): + # Format BGPVPN before sending notification + self.agent_rpc.delete_bgpvpn( + context, + self._format_bgpvpn(bgpvpn, net_id)) + + def associate_network_postcommit(self, context, bgpvpn_id, network_id): + if get_network_ports(context, + network_id): + bgpvpn = self.get_bgpvpn(context, bgpvpn_id) + formated_bgpvpn = self._format_bgpvpn(bgpvpn, network_id) + self.agent_rpc.update_bgpvpn( context, - self._format_bgpvpn(bgpvpn) - ) + formated_bgpvpn) + + def disassociate_network_postcommit(self, context, bgpvpn_id, network_id): + if get_network_ports(context, + network_id): + LOG.debug("bagpipe disassoc") + bgpvpn = self.get_bgpvpn(context, bgpvpn_id) + formated_bgpvpn = self._format_bgpvpn(bgpvpn, network_id) + self.agent_rpc.delete_bgpvpn(context, formated_bgpvpn) def update_bgpvpn_postcommit(self, context, old_bgpvpn, bgpvpn): (added_keys, removed_keys, changed_keys) = ( self._get_bgpvpn_differences(bgpvpn, old_bgpvpn)) - - if 'network_id' in changed_keys: - formated_bgpvpn = ( - self._format_bgpvpn(bgpvpn) - ) - formated_bgpvpn.update( - {'old_network_id': old_bgpvpn['network_id']} - ) - - # BGPVPN is dissociated from a network - if bgpvpn['network_id'] is None: - # Check if dissociated network has already plugged ports - if get_network_ports(context, - old_bgpvpn['network_id']): - self.agent_rpc.update_bgpvpn( - context, - formated_bgpvpn - ) - else: - # Network association to BGPVPN - if old_bgpvpn['network_id'] is None: - # Check if associated network has already plugged ports - if get_network_ports(context, - bgpvpn['network_id']): - self.agent_rpc.update_bgpvpn( - context, - formated_bgpvpn - ) - else: - # Association to a different network - # Check if one of the 2 networks has already plugged ports - if (get_network_ports(context, - old_bgpvpn['network_id']) - or get_network_ports(context, - bgpvpn['network_id'])): - self.agent_rpc.update_bgpvpn( - context, - formated_bgpvpn - ) - else: - if (bgpvpn['network_id'] is not None and - get_network_ports(context, - bgpvpn['network_id'])): + for net_id in bgpvpn['networks']: + if (get_network_ports(context, net_id)): if ((key in added_keys for key in ('route_targets', 'import_targets', 'export_targets')) or @@ -303,7 +261,7 @@ class BaGPipeBGPVPNDriver(driver_api.BGPVPNDriver): 'export_targets'))): self.agent_rpc.update_bgpvpn( context, - self._format_bgpvpn(bgpvpn) + self._format_bgpvpn(bgpvpn, net_id) ) def _get_port_host(self, port_id): diff --git a/networking_bgpvpn/tests/unit/services/bagpipe/__init__.py b/networking_bgpvpn/tests/unit/services/bagpipe/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/networking_bgpvpn/tests/unit/services/bagpipe/test_bagpipe.py b/networking_bgpvpn/tests/unit/services/bagpipe/test_bagpipe.py new file mode 100644 index 00000000..cb608866 --- /dev/null +++ b/networking_bgpvpn/tests/unit/services/bagpipe/test_bagpipe.py @@ -0,0 +1,112 @@ +# Copyright (c) 2015 Orange. +# 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. + +import mock +import webob.exc + +from networking_bgpvpn.tests.unit.services import test_plugin + + +class TestBagpipeServiceDriver(test_plugin.BgpvpnTestCaseMixin): + + def setUp(self): + self.mocked_bagpipeAPI = mock.patch( + 'networking_bagpipe_l2.agent.bgpvpn.rpc_client' + '.BGPVPNAgentNotifyApi').start().return_value + + provider = ('networking_bgpvpn.neutron.services.service_drivers.' + 'bagpipe.bagpipe.BaGPipeBGPVPNDriver') + super(TestBagpipeServiceDriver, self).setUp(service_provider=provider) + + def test_bagpipe_associate_net(self): + mocked_update = self.mocked_bagpipeAPI.update_bgpvpn + with self.port() as port1: + net_id = port1['port']['network_id'] + with self.bgpvpn() as bgpvpn: + id = bgpvpn['bgpvpn']['id'] + rt = bgpvpn['bgpvpn']['route_targets'] + mocked_update.reset_mock() + with self.assoc_net(id, net_id): + formatted_bgpvpn = {'id': id, + 'network_id': net_id, + 'l3vpn': + {'import_rt': rt, + 'export_rt': rt}} + mocked_update.assert_called_once_with(mock.ANY, + formatted_bgpvpn) + + def test_bagpipe_disassociate_net(self): + mocked_delete = self.mocked_bagpipeAPI.delete_bgpvpn + with self.port() as port1: + net_id = port1['port']['network_id'] + with self.bgpvpn() as bgpvpn: + id = bgpvpn['bgpvpn']['id'] + rt = bgpvpn['bgpvpn']['route_targets'] + with self.assoc_net(id, net_id, do_disassociate=False): + net_body = {'network_id': net_id} + mocked_delete.reset_mock() + disassoc_req = self._req('PUT', 'bgpvpn/bgpvpns', + data=net_body, fmt=self.fmt, + id=id, + action='disassociate_network') + res = disassoc_req.get_response(self.ext_api) + if res.status_int>= 400: + raise webob.exc.HTTPClientError(code=res.status_int) + formatted_bgpvpn = {'id': id, + 'network_id': net_id, + 'l3vpn': + {'import_rt': rt, + 'export_rt': rt}} + mocked_delete.assert_called_once_with(mock.ANY, + formatted_bgpvpn) + + def test_bagpipe_update_bgpvpn_rt(self): + mocked_update = self.mocked_bagpipeAPI.update_bgpvpn + with self.port() as port1: + net_id = port1['port']['network_id'] + with self.bgpvpn() as bgpvpn: + id = bgpvpn['bgpvpn']['id'] + rt = ['6543:21'] + with self.assoc_net(id, net_id): + formatted_bgpvpn = {'id': id, + 'network_id': net_id, + 'l3vpn': + {'import_rt': rt, + 'export_rt': rt}} + update_data = {'bgpvpn': {'route_targets': ['6543:21']}} + mocked_update.reset_mock() + self._update('bgpvpn/bgpvpns', + bgpvpn['bgpvpn']['id'], + update_data) + mocked_update.assert_called_once_with(mock.ANY, + formatted_bgpvpn) + + def test_bagpipe_delete_bgpvpn(self): + mocked_delete = self.mocked_bagpipeAPI.delete_bgpvpn + with self.port() as port1: + net_id = port1['port']['network_id'] + with self.bgpvpn(do_delete=False) as bgpvpn: + id = bgpvpn['bgpvpn']['id'] + rt = bgpvpn['bgpvpn']['route_targets'] + mocked_delete.reset_mock() + with self.assoc_net(id, net_id, do_disassociate=False): + self._delete('bgpvpn/bgpvpns', id) + formatted_bgpvpn = {'id': id, + 'network_id': net_id, + 'l3vpn': + {'import_rt': rt, + 'export_rt': rt}} + mocked_delete.assert_called_once_with(mock.ANY, + formatted_bgpvpn) diff --git a/networking_bgpvpn/tests/unit/services/test_plugin.py b/networking_bgpvpn/tests/unit/services/test_plugin.py index dcfaf9f1..389ef490 100644 --- a/networking_bgpvpn/tests/unit/services/test_plugin.py +++ b/networking_bgpvpn/tests/unit/services/test_plugin.py @@ -35,10 +35,14 @@ _uuid = uuidutils.generate_uuid class BgpvpnTestCaseMixin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): - def setUp(self): - provider = (constants.BGPVPN + - ':dummy:networking_bgpvpn.neutron.services.' - 'service_drivers.driver_api.BGPVPNDriver:default') + def setUp(self, service_provider=None): + if not service_provider: + provider = (constants.BGPVPN + + ':dummy:networking_bgpvpn.neutron.services.' + 'service_drivers.driver_api.BGPVPNDriver:default') + else: + provider = (constants.BGPVPN + ':test:' + service_provider + + ':default') bits = provider.split(':') provider = { diff --git a/test-requirements.txt b/test-requirements.txt index d4614d20..508d02f2 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -15,3 +15,5 @@ oslotest>=1.10.0 # Apache-2.0 testrepository>=0.0.18 testscenarios>=0.4 testtools>=1.4.0 + +-e git+https://git.openstack.org/stackforge/networking-bagpipe-l2#egg=networking-bagpipe-l2