diff --git a/gbpservice/neutron/plugins/ml2/drivers/grouppolicy/apic/driver.py b/gbpservice/neutron/plugins/ml2/drivers/grouppolicy/apic/driver.py index 0a08bbf00..cdcd7eaf5 100644 --- a/gbpservice/neutron/plugins/ml2/drivers/grouppolicy/apic/driver.py +++ b/gbpservice/neutron/plugins/ml2/drivers/grouppolicy/apic/driver.py @@ -26,10 +26,10 @@ from oslo_log import log from oslo_utils import importutils from gbpservice._i18n import _LW +from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import ( + nova_client as nclient) from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( apic_mapping as amap) -from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( - nova_client as nclient) LOG = log.getLogger(__name__) diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/db.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/db.py index 6486a9408..80a5339c6 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/db.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/db.py @@ -87,6 +87,9 @@ class VMNameUpdate(model_base.BASEV2): class DbMixin(object): + + # AddressScopeMapping functions. + def _add_address_scope_mapping(self, session, scope_id, vrf, vrf_owned=True, update_scope=True): mapping = AddressScopeMapping( @@ -151,6 +154,8 @@ class DbMixin(object): tenant_name=mapping.vrf_tenant_name, name=mapping.vrf_name) + # NetworkMapping functions. + def _add_network_mapping(self, session, network_id, bd, epg, vrf, ext_net=None, update_network=True): if not ext_net: @@ -302,6 +307,8 @@ class DbMixin(object): mapping.vrf_tenant_name = vrf.tenant_name mapping.vrf_name = vrf.name + # VMName functions. + def _get_vm_name(self, session, device_id, is_detailed=False): if is_detailed: query = BAKERY(lambda s: s.query(VMName)) @@ -334,6 +341,8 @@ class DbMixin(object): if db_obj: session.delete(db_obj) + # VMNameUpdate functions. + def _get_vm_name_update(self, session): query = BAKERY(lambda s: s.query(VMNameUpdate)) return query(session).one_or_none() diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py index bd8ce1c5b..d9d821a10 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py @@ -86,10 +86,9 @@ from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import config # noqa from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import db from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import exceptions from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import extension_db +from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import nova_client from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import rpc from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import trunk_driver -from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( - nova_client as nclient) LOG = log.getLogger(__name__) @@ -284,7 +283,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver, self.apic_nova_vm_name_cache_update_interval * 10): is_full_update = False - nova_vms = nclient.NovaClient().get_servers( + nova_vms = nova_client.NovaClient().get_servers( is_full_update, self.apic_nova_vm_name_cache_update_interval * 10) # This means Nova API has thrown an exception if nova_vms is None: diff --git a/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/nova_client.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/nova_client.py similarity index 100% rename from gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/nova_client.py rename to gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/nova_client.py diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py index cfba85d67..5ba676157 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py @@ -45,7 +45,8 @@ from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import constants from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import db from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import extension_db -# REVISIT: This should be moved to the mechanism driver. +# REVISIT: This has been moved to the mechanism driver in stable/ocata +# and newer, but not yet in stable/newton. from apic_ml2.neutron.db import port_ha_ipaddress_binding as ha_ip_db LOG = log.getLogger(__name__) @@ -204,14 +205,6 @@ class ApicRpcHandlerMixin(object): return conn.consume_in_threads() # The following five methods handle RPCs from the Opflex agent. - # - # REVISIT: These handler methods are currently called by - # corresponding handler methods in the aim_mapping_rpc - # module. Once these RPC handlers are all fully implemented and - # tested, move the instantiation of the - # opflexagent.rpc.GBPServerRpcCallback class from aim_mapping_rpc - # to this module and eliminate the other RPC handler - # implementations. def get_gbp_details(self, context, **kwargs): LOG.debug("APIC AIM MD handling get_gbp_details for: %s", kwargs) @@ -285,9 +278,15 @@ class ApicRpcHandlerMixin(object): def ip_address_owner_update(self, context, **kwargs): LOG.debug("APIC AIM MD handling ip_address_owner_update for: %s", kwargs) - # REVISIT: Move actual handler implementation to this class. - if self.gbp_driver: - self.gbp_driver.ip_address_owner_update(context, **kwargs) + if not kwargs.get('ip_owner_info'): + return + if not self.gbp_driver: + return + ports_to_update = self.gbp_driver.update_ip_owner( + kwargs['ip_owner_info']) + for p in ports_to_update: + LOG.debug("APIC ownership update for port %s", p) + self._notify_port_update(context, p) @db_api.retry_if_session_inactive() def _get_vrf_details(self, context, vrf_id): diff --git a/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/aim_mapping.py b/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/aim_mapping.py index a9587cb23..5fcf8f834 100644 --- a/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/aim_mapping.py +++ b/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/aim_mapping.py @@ -48,6 +48,7 @@ from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import ( from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import ( mechanism_driver as md) from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import apic_mapper +from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import nova_client from gbpservice.neutron.services.grouppolicy.common import ( constants as gp_const) from gbpservice.neutron.services.grouppolicy.common import constants as g_const @@ -61,8 +62,6 @@ from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( aim_validation) from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( apic_mapping_lib as alib) -from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( - nova_client as nclient) from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import config # noqa from gbpservice.neutron.services.grouppolicy import plugin as gbp_plugin @@ -1153,7 +1152,7 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin): context._plugin_context, l2p['l3_policy_id']) if l3p.get('allowed_vm_names'): ok_to_bind = False - vm = nclient.NovaClient().get_server(port['device_id']) + vm = nova_client.NovaClient().get_server(port['device_id']) for allowed_vm_name in l3p['allowed_vm_names']: match = re.search(allowed_vm_name, vm.name) if match: diff --git a/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/apic_mapping.py b/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/apic_mapping.py index b423867c7..5c684f7f9 100644 --- a/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/apic_mapping.py +++ b/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/apic_mapping.py @@ -53,6 +53,8 @@ from gbpservice.network.neutronv2 import local_api from gbpservice.neutron.db.grouppolicy.extensions import apic_reuse_bd_db from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpdb from gbpservice.neutron.extensions import group_policy as gpolicy +from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import ( + nova_client as nclient) from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import cache from gbpservice.neutron.services.grouppolicy.common import constants as g_const from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc @@ -63,8 +65,6 @@ from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( apic_mapping_lib as alib) from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( name_manager as name_manager) -from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import ( - nova_client as nclient) from gbpservice.neutron.services.grouppolicy import group_policy_context from gbpservice.neutron.services.grouppolicy import plugin as gbp_plugin diff --git a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py index cded0526f..613f2fa29 100644 --- a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py +++ b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py @@ -246,8 +246,8 @@ class ApicAimTestCase(test_address_scope.AddressScopeTestCase, def setUp(self, mechanism_drivers=None, tenant_network_types=None, plugin=None, ext_mgr=None): self.nova_client = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_servers').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_servers').start() self.nova_client.return_value = [] # Enable the test mechanism driver to ensure that # we can successfully call through to all mechanism @@ -8522,3 +8522,48 @@ class TestOpflexRpc(ApicAimTestCase): # REVISIT: Test with missing request, missing device, invalid # device prefix, unbindable port, port bound to wrong host. + + # REVISIT: This test cannot be enabled in stable/newton until the + # HAIP code is moved to the MD, as the PD is not configured in + # these tests. + # + # def test_ip_address_owner_update(self): + # self._register_agent('h1', AGENT_CONF_OPFLEX) + # self._register_agent('h2', AGENT_CONF_OPFLEX) + # + # net = self._make_network(self.fmt, 'net1', True) + # net_id = net['network']['id'] + # + # self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24') + # + # port1_id = self._make_port(self.fmt, net_id)['port']['id'] + # port2_id = self._make_port(self.fmt, net_id)['port']['id'] + # + # self._bind_port_to_host(port1_id, 'h1') + # self._bind_port_to_host(port2_id, 'h2') + # + # ip_owner_info = {'port': port1_id, 'ip_address_v4': '1.2.3.4'} + # self.driver._notify_port_update = mock.Mock() + # + # # Set new owner and check. + # self.driver.ip_address_owner_update( + # n_context.get_admin_context(), ip_owner_info=ip_owner_info, + # host='h1') + # obj = self.driver.get_port_for_ha_ipaddress('1.2.3.4', net_id) + # self.assertEqual(port1_id, obj['port_id']) + # self.driver._notify_port_update.assert_called_with( + # mock.ANY, port1_id) + # + # # Update existing owner and check. + # self.driver._notify_port_update.reset_mock() + # ip_owner_info['port'] = port2_id + # self.driver.ip_address_owner_update( + # n_context.get_admin_context(), ip_owner_info=ip_owner_info, + # host='h2') + # obj = self.driver.get_port_for_ha_ipaddress('1.2.3.4', net_id) + # self.assertEqual(port2_id, obj['port_id']) + # exp_calls = [ + # mock.call(mock.ANY, port1_id), + # mock.call(mock.ANY, port2_id)] + # self._check_call_list(exp_calls, + # self.driver._notify_port_update.call_args_list) diff --git a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_db_apic_aim.py b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_db_apic_aim.py new file mode 100644 index 000000000..560ad617e --- /dev/null +++ b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_db_apic_aim.py @@ -0,0 +1,14 @@ +# 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. + +# REVISIT: Copy the PortToHAIPAddressBindingTestCase class here from +# stable/ocata when moving/copying the HAIP code to the MD. diff --git a/gbpservice/neutron/tests/unit/services/grouppolicy/test_aim_mapping_driver.py b/gbpservice/neutron/tests/unit/services/grouppolicy/test_aim_mapping_driver.py index 6dd2852bd..9157c2f60 100644 --- a/gbpservice/neutron/tests/unit/services/grouppolicy/test_aim_mapping_driver.py +++ b/gbpservice/neutron/tests/unit/services/grouppolicy/test_aim_mapping_driver.py @@ -124,8 +124,8 @@ class AIMBaseTestCase(test_nr_base.CommonNeutronBaseTestCase, def setUp(self, policy_drivers=None, core_plugin=None, ml2_options=None, l3_plugin=None, sc_plugin=None, trunk_plugin=None, **kwargs): self.nova_client1 = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_servers').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_servers').start() self.nova_client1.return_value = [] core_plugin = core_plugin or ML2PLUS_PLUGIN if not l3_plugin: @@ -186,8 +186,8 @@ class AIMBaseTestCase(test_nr_base.CommonNeutronBaseTestCase, self._name_mapper = None self._driver = None nova_client = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_server').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_server').start() vm = mock.Mock() vm.name = 'someid' nova_client.return_value = vm @@ -3844,8 +3844,8 @@ class TestPolicyTarget(AIMBaseTestCase, policy_target_group_id=ptg['id'])['policy_target'] nova_client = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_server').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_server').start() vm = mock.Mock() vm.name = 'secure_vm1' nova_client.return_value = vm diff --git a/gbpservice/neutron/tests/unit/services/grouppolicy2/test_apic_mapping.py b/gbpservice/neutron/tests/unit/services/grouppolicy2/test_apic_mapping.py index 8dd677a60..e62a138af 100644 --- a/gbpservice/neutron/tests/unit/services/grouppolicy2/test_apic_mapping.py +++ b/gbpservice/neutron/tests/unit/services/grouppolicy2/test_apic_mapping.py @@ -134,8 +134,8 @@ class ApicMappingTestCase( 'apic.apic_mapping.ApicMappingDriver.' '_setup_keystone_notification_listeners').start() nova_client = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_server').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_server').start() vm = mock.Mock() vm.name = 'someid' nova_client.return_value = vm @@ -1880,8 +1880,8 @@ class TestPolicyTargetDvs(ApicMappingTestCase): policy_target_group_id=ptg['id'])['policy_target'] nova_client = mock.patch( - 'gbpservice.neutron.services.grouppolicy.drivers.cisco.' - 'apic.nova_client.NovaClient.get_server').start() + 'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.' + 'nova_client.NovaClient.get_server').start() vm = mock.Mock() vm.name = 'secure_vm1' nova_client.return_value = vm