From d0c172afa6ea38e94563afb4994471420b27cddf Mon Sep 17 00:00:00 2001 From: Nate Johnston Date: Sat, 15 Jun 2019 10:14:58 -0400 Subject: [PATCH] Fix bulk port binding Bulk ports were not binding correctly when they were created. This is due to a few inconsistencies between the create_port code and the create_port_bulk code, mostly a result of the use of the Port object in the bulk code. Change-Id: I3bcd3cec12b1b6f6a568cda4bfeb569f636efb98 Closes-Bug: #1835209 --- neutron/db/db_base_plugin_common.py | 2 +- neutron/db/l3_db.py | 6 ++- neutron/db/securitygroups_db.py | 3 +- neutron/plugins/ml2/plugin.py | 43 +++++++++++++++---- .../tests/unit/db/test_db_base_plugin_v2.py | 3 ++ neutron/tests/unit/db/test_rbac_db_mixin.py | 1 + .../ml2/drivers/l2pop/test_mech_driver.py | 5 ++- 7 files changed, 50 insertions(+), 13 deletions(-) diff --git a/neutron/db/db_base_plugin_common.py b/neutron/db/db_base_plugin_common.py index 22a420c4ee0..de3ab8c18b4 100644 --- a/neutron/db/db_base_plugin_common.py +++ b/neutron/db/db_base_plugin_common.py @@ -213,7 +213,7 @@ class DbBasePluginCommon(object): "admin_state_up": port["admin_state_up"], "status": port["status"], "fixed_ips": [{'subnet_id': ip["subnet_id"], - 'ip_address': ip["ip_address"]} + 'ip_address': str(ip["ip_address"])} for ip in port["fixed_ips"]], "device_id": port["device_id"], "device_owner": port["device_owner"]} diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 5b72339e67d..41664f1ec5d 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -1418,8 +1418,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, floatingip_id=fip_id, floatingip_db=floatingip_db) - self._core_plugin.update_port(context.elevated(), external_port['id'], - {'port': {'device_id': fip_id}}) + self._core_plugin.update_port( + context.elevated(), external_port['id'], + {'port': {'device_id': fip_id, + 'project_id': fip['tenant_id']}}) registry.notify(resources.FLOATING_IP, events.AFTER_UPDATE, self._update_fip_assoc, diff --git a/neutron/db/securitygroups_db.py b/neutron/db/securitygroups_db.py index b5753b21cd8..d824f4028cc 100644 --- a/neutron/db/securitygroups_db.py +++ b/neutron/db/securitygroups_db.py @@ -774,7 +774,8 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase, tenant_id = kwargs['original_' + resource]['tenant_id'] else: tenant_id = kwargs[resource]['tenant_id'] - self._ensure_default_security_group(context, tenant_id) + if tenant_id: + self._ensure_default_security_group(context, tenant_id) def _ensure_default_security_group(self, context, tenant_id): """Create a default security group if one doesn't exist. diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index ce8b0743f13..e290954cc2c 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -1466,11 +1466,18 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, for port in port_list: # Set up the port request dict pdata = port.get('port') + project_id = pdata.get('project_id') or pdata.get('tenant_id') + security_group_ids = pdata.get('security_groups') + if security_group_ids is const.ATTR_NOT_SPECIFIED: + security_group_ids = None + else: + security_group_ids = set(security_group_ids) if pdata.get('device_owner'): self._enforce_device_owner_not_router_intf_or_device_id( context, pdata.get('device_owner'), - pdata.get('device_id'), pdata.get('tenant_id')) - bulk_port_data = dict(project_id=pdata.get('project_id'), + pdata.get('device_id'), project_id) + bulk_port_data = dict( + project_id=project_id, name=pdata.get('name'), network_id=pdata.get('network_id'), admin_state_up=pdata.get('admin_state_up'), @@ -1478,7 +1485,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, const.PORT_STATUS_ACTIVE), device_id=pdata.get('device_id'), device_owner=pdata.get('device_owner'), - security_groups=pdata.get('security_groups'), + security_group_ids=security_group_ids, description=pdata.get('description')) # Ensure that the networks exist. @@ -1499,6 +1506,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, mac=raw_mac_address) eui_mac_address = netaddr.EUI(raw_mac_address, dialect=eui48.mac_unix_expanded) + port['port']['mac_address'] = str(eui_mac_address) # Create the Port object db_port_obj = ports_obj.Port(context, @@ -1506,27 +1514,42 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, id=uuidutils.generate_uuid(), **bulk_port_data) db_port_obj.create() - port_dict = self._make_port_dict(db_port_obj, - process_extensions=False) - port_compat = {'port': port_dict} # Call IPAM to allocate IP addresses try: # TODO(njohnston): IPAM allocation needs to be revamped to # be bulk-friendly. - self.ipam.allocate_ips_for_port_and_store( - context, db_port_obj, db_port_obj['id']) + ips = self.ipam.allocate_ips_for_port_and_store( + context, port, db_port_obj['id']) + ipam_fixed_ips = [] + for ip in ips: + fixed_ip = ports_obj.IPAllocation( + port_id=db_port_obj['id'], + subnet_id=ip['subnet_id'], + network_id=network_id, + ip_address=ip['ip_address']) + ipam_fixed_ips.append(fixed_ip) + + db_port_obj['fixed_ips'] = ipam_fixed_ips db_port_obj['ip_allocation'] = (ipalloc_apidef. IP_ALLOCATION_IMMEDIATE) except ipam_exc.DeferIpam: db_port_obj['ip_allocation'] = (ipalloc_apidef. IP_ALLOCATION_DEFERRED) + fixed_ips = pdata.get('fixed_ips') if validators.is_attr_set(fixed_ips) and not fixed_ips: # [] was passed explicitly as fixed_ips: unaddressed port. db_port_obj['ip_allocation'] = (ipalloc_apidef. IP_ALLOCATION_NONE) + # Make port dict + port_dict = self._make_port_dict(db_port_obj, + process_extensions=False) + port_dict[portbindings.HOST_ID] = pdata.get( + portbindings.HOST_ID) + port_compat = {'port': port_dict} + # Activities immediately post-port-creation self.extension_manager.process_create_port(context, port_dict, db_port_obj) @@ -1540,6 +1563,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, # process port binding binding = db.add_port_binding(context, port_dict['id']) + binding_host = pdata.get( + portbindings.HOST_ID, const.ATTR_NOT_SPECIFIED) + if binding_host != const.ATTR_NOT_SPECIFIED: + binding["host"] = binding_host mech_context = driver_context.PortContext(self, context, port_dict, network, binding, None) diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index 41b82054911..cb181cb9a0a 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -594,6 +594,9 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase): if neutron_context: # create a specific auth context for this request req.environ['neutron.context'] = neutron_context + elif hasattr(self, 'tenant_id'): + req.environ['neutron.context'] = context.Context('', + self.tenant_id) return req.get_response(self._api_for_resource(resource)) def _show(self, resource, id, diff --git a/neutron/tests/unit/db/test_rbac_db_mixin.py b/neutron/tests/unit/db/test_rbac_db_mixin.py index 47b69392fbd..27899a7e14f 100644 --- a/neutron/tests/unit/db/test_rbac_db_mixin.py +++ b/neutron/tests/unit/db/test_rbac_db_mixin.py @@ -54,6 +54,7 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase): 'admin_state_up': True, 'device_id': 'device_id', 'device_owner': 'device_owner', + 'project_id': target_tenant, 'tenant_id': target_tenant}} port = self.plugin.create_port(self.context, test_port) diff --git a/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py b/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py index 8ac37313c94..97955292949 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py @@ -66,6 +66,7 @@ class FakeL3PluginWithAgents(l3_hamode_db.L3_HA_NAT_db_mixin, class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): _mechanism_drivers = ['openvswitch', 'fake_agent', 'l2population'] + tenant = 'tenant' def setUp(self): super(TestL2PopulationRpcTestCase, self).setUp() @@ -363,13 +364,15 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): enable_dhcp=False) as snet: with self.port( subnet=snet, + project_id=self.tenant, device_owner=constants.DEVICE_OWNER_DVR_INTERFACE)\ as port: port_id = port['port']['id'] plugin.update_distributed_port_binding(self.adminContext, port_id, {'port': {portbindings.HOST_ID: HOST_4, 'device_id': router['id']}}) - port = self._show('ports', port_id) + port = self._show('ports', port_id, + neutron_context=self.adminContext) self.assertEqual(portbindings.VIF_TYPE_DISTRIBUTED, port['port'][portbindings.VIF_TYPE]) self.callbacks.update_device_up(