From 3c6ecad76674e20cfa5e89ec32160acdc84f9329 Mon Sep 17 00:00:00 2001 From: Weiguo Sun Date: Fri, 16 Feb 2018 14:24:19 -0500 Subject: [PATCH] Adds provisioning block to APIC_AIM mech driver This is per design from: https://docs.openstack.org/neutron/pike/contributor/internals/provisioning_blocks.html Change-Id: Ie5e866cc65235f4775fd076fc4bfcf1f73fce928 --- .../drivers/apic_aim/mechanism_driver.py | 33 ++++++++++++++++-- .../unit/plugins/ml2plus/test_apic_aim.py | 34 +++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) 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 50844ce85..6b0d0717f 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py @@ -26,6 +26,7 @@ from aim.common import utils from aim import context as aim_context from aim import utils as aim_utils from neutron.agent import securitygroups_rpc +from neutron.callbacks import resources from neutron.common import rpc as n_rpc from neutron.common import topics as n_topics from neutron.db import api as db_api @@ -35,6 +36,7 @@ from neutron.db.models import l3 as l3_db from neutron.db.models import securitygroup as sg_models from neutron.db.models import segment as segments_model from neutron.db import models_v2 +from neutron.db import provisioning_blocks from neutron.db import rbac_db_models from neutron.db import segments_db from neutron.extensions import external_net @@ -83,6 +85,9 @@ L3OUT_NODE_PROFILE_NAME = 'NodeProfile' L3OUT_IF_PROFILE_NAME = 'IfProfile' L3OUT_EXT_EPG = 'ExtEpg' +SUPPORTED_VNIC_TYPES = [portbindings.VNIC_NORMAL, + portbindings.VNIC_DIRECT] + AGENT_TYPE_DVS = 'DVS agent' VIF_TYPE_DVS = 'dvs' PROMISCUOUS_TYPES = [n_constants.DEVICE_OWNER_DHCP, @@ -1500,8 +1505,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver, # Check the VNIC type. vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL) - if vnic_type not in [portbindings.VNIC_NORMAL, - portbindings.VNIC_DIRECT]: + if vnic_type not in SUPPORTED_VNIC_TYPES: LOG.debug("Refusing to bind due to unsupported vnic_type: %s", vnic_type) return @@ -1593,6 +1597,30 @@ class ApicMechanismDriver(api_plus.MechanismDriver, port = context.current self._really_update_sg_rule_with_remote_group_set( context, port, port['security_groups'], is_delete=False) + self._insert_provisioning_block(context) + + def _insert_provisioning_block(self, context): + # we insert a status barrier to prevent the port from transitioning + # to active until the agent reports back that the wiring is done + port = context.current + if (not context.host or + port['status'] == n_constants.PORT_STATUS_ACTIVE): + # no point in putting in a block if the status is already ACTIVE + return + + # Check the VNIC type. + vnic_type = port.get(portbindings.VNIC_TYPE, + portbindings.VNIC_NORMAL) + if vnic_type not in SUPPORTED_VNIC_TYPES: + LOG.debug("No provisioning_block due to unsupported vnic_type: %s", + vnic_type) + return + + if (context.host_agents(ofcst.AGENT_TYPE_OPFLEX_OVS) or + context.host_agents(AGENT_TYPE_DVS)): + provisioning_blocks.add_provisioning_component( + context._plugin_context, port['id'], resources.PORT, + provisioning_blocks.L2_AGENT_ENTITY) def update_port_precommit(self, context): port = context.current @@ -1612,6 +1640,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver, context.bottom_bound_segment[api.NETWORK_TYPE])): self._associate_domain(context, is_vmm=True) self._update_sg_rule_with_remote_group_set(context, port) + self._insert_provisioning_block(context) def update_port_postcommit(self, context): port = context.current 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 9d88b9bbc..49c8a551c 100644 --- a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py +++ b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py @@ -34,7 +34,9 @@ from aim import utils as aim_utils from keystoneclient.v3 import client as ksc_client from neutron.api import extensions from neutron.db import api as db_api +from neutron.db import provisioning_blocks from neutron.db import segments_db +from neutron.plugins.ml2 import driver_context from neutron.tests.unit.api import test_extensions from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin from neutron.tests.unit.extensions import test_address_scope @@ -2893,6 +2895,38 @@ class TestAimMapping(ApicAimTestCase): is_implicit=True)['subnetpool'] self.assertTrue(sp3['is_implicit']) + def test_dhcp_provisioning_blocks_inserted_on_update(self): + ctx = n_context.get_admin_context() + plugin = directory.get_plugin() + + def _fake_dhcp_agent(): + agent = mock.Mock() + plugin = directory.get_plugin() + return mock.patch.object( + plugin, 'get_dhcp_agents_hosting_networks', + return_value=[agent]).start() + + dhcp_agt_mock = _fake_dhcp_agent() + update_dict = {'binding:host_id': 'newhost'} + + def _host_agents(self, agent_type): + if agent_type == ofcst.AGENT_TYPE_OPFLEX_OVS: + fake_agent = {"alive": False} + return [fake_agent] + + orig_host_agents = getattr(driver_context.PortContext, "host_agents") + setattr(driver_context.PortContext, "host_agents", _host_agents) + + with self.port() as port: + with mock.patch.object(provisioning_blocks, + 'add_provisioning_component') as ap: + port['port'].update(update_dict) + plugin.update_port(ctx, port['port']['id'], port) + ap.assert_called() + + setattr(driver_context.PortContext, "host_agents", orig_host_agents) + dhcp_agt_mock.stop() + class TestSyncState(ApicAimTestCase): @staticmethod