From aa60d6e83760cee0fccdf3925329858aa3c85903 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 (cherry picked from commit d0c172afa6ea38e94563afb4994471420b27cddf) --- 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 e1d2f5c3994..4890d7cf46e 100644 --- a/neutron/db/db_base_plugin_common.py +++ b/neutron/db/db_base_plugin_common.py @@ -215,7 +215,7 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin): "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 50704966f4b..37f7b3f9452 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 753147f0405..0065af4acd1 100644 --- a/neutron/db/securitygroups_db.py +++ b/neutron/db/securitygroups_db.py @@ -771,7 +771,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 e9fd72b3a3b..9c370bda36e 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -1401,11 +1401,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'), @@ -1413,7 +1420,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. @@ -1434,6 +1441,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, @@ -1441,27 +1449,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) @@ -1475,6 +1498,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 6dd9ecea9b8..8dfba817e23 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -586,6 +586,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 8f5245ea52a..e07682dfe46 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 9667fd8bcb9..ac4d4a5c89d 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 @@ -69,6 +69,7 @@ class FakeL3PluginWithAgents(common_db_mixin.CommonDbMixin, class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): _mechanism_drivers = ['openvswitch', 'fake_agent', 'l2population'] + tenant = 'tenant' def setUp(self): super(TestL2PopulationRpcTestCase, self).setUp() @@ -366,13 +367,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(