diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-07-29 03:47:23 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-07-29 03:47:23 +0000 |
commit | 3b592e27f440f096d212b814ff57b22dea17d18c (patch) | |
tree | 728af8d5ed5a4b7eb50a77ffb6deaf30b2ac2d9c | |
parent | 6b7e0338fe7438ab5982218871254499ceba1ceb (diff) | |
parent | 8d753d71145c38cee042db587605787b0b2dc2ea (diff) | |
download | neutron-3b592e27f440f096d212b814ff57b22dea17d18c.tar.gz |
Merge "Update ml2 delete_subnet to deallocate via ipam" into stable/liberty
-rw-r--r-- | neutron/plugins/ml2/plugin.py | 77 | ||||
-rw-r--r-- | neutron/tests/unit/plugins/ml2/test_plugin.py | 6 |
2 files changed, 50 insertions, 33 deletions
diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 56b4ec47a7..01fd1a6c6b 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -879,6 +879,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, LOG.debug("Deleting subnet %s", id) session = context.session + deallocated = set() while True: with session.begin(subtransactions=True): record = self._get_subnet(context, id) @@ -897,43 +898,52 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, qry_allocated = ( qry_allocated.filter(models_v2.Port.device_owner. in_(db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS))) - allocated = qry_allocated.all() - # Delete all the IPAllocation that can be auto-deleted - if allocated: - for x in allocated: - session.delete(x) + allocated = set(qry_allocated.all()) LOG.debug("Ports to auto-deallocate: %s", allocated) - # Check if there are more IP allocations, unless - # is_auto_address_subnet is True. In that case the check is - # unnecessary. This additional check not only would be wasteful - # for this class of subnet, but is also error-prone since when - # the isolation level is set to READ COMMITTED allocations made - # concurrently will be returned by this query if not is_auto_addr_subnet: - alloc = self._subnet_check_ip_allocations(context, id) - if alloc: - user_alloc = self._subnet_get_user_allocation( - context, id) - if user_alloc: - LOG.info(_LI("Found port (%(port_id)s, %(ip)s) " - "having IP allocation on subnet " - "%(subnet)s, cannot delete"), - {'ip': user_alloc.ip_address, - 'port_id': user_alloc.port_id, - 'subnet': id}) - raise exc.SubnetInUse(subnet_id=id) - else: - # allocation found and it was DHCP port - # that appeared after autodelete ports were - # removed - need to restart whole operation - raise os_db_exception.RetryRequest( - exc.SubnetInUse(subnet_id=id)) + user_alloc = self._subnet_get_user_allocation( + context, id) + if user_alloc: + LOG.info(_LI("Found port (%(port_id)s, %(ip)s) " + "having IP allocation on subnet " + "%(subnet)s, cannot delete"), + {'ip': user_alloc.ip_address, + 'port_id': user_alloc.port_id, + 'subnet': id}) + raise exc.SubnetInUse(subnet_id=id) db_base_plugin_v2._check_subnet_not_used(context, id) - # If allocated is None, then all the IPAllocation were - # correctly deleted during the previous pass. - if not allocated: + # SLAAC allocations currently can not be removed using + # update_port workflow, and will persist in 'allocated'. + # So for now just make sure update_port is called once for + # them so MechanismDrivers is aware of the change. + # This way SLAAC allocation is deleted by FK on subnet deletion + # TODO(pbondar): rework update_port workflow to allow deletion + # of SLAAC allocation via update_port. + to_deallocate = allocated - deallocated + + # If to_deallocate is blank, then all known IPAllocations + # (except SLAAC allocations) were correctly deleted + # during the previous pass. + # Check if there are more IP allocations, unless + # is_auto_address_subnet is True. If transaction isolation + # level is set to READ COMMITTED allocations made + # concurrently will be returned by this query and transaction + # will be restarted. It works for REPEATABLE READ isolation + # level too because this query is executed only once during + # transaction, and if concurrent allocations are detected + # transaction gets restarted. Executing this query second time + # in transaction would result in not seeing allocations + # committed by concurrent transactions. + if not to_deallocate: + if (not is_auto_addr_subnet and + self._subnet_check_ip_allocations(context, id)): + # allocation found and it was DHCP port + # that appeared after autodelete ports were + # removed - need to restart whole operation + raise os_db_exception.RetryRequest( + exc.SubnetInUse(subnet_id=id)) network = self.get_network(context, subnet['network_id']) mech_context = driver_context.SubnetContext(self, context, subnet, @@ -951,7 +961,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, LOG.debug("Committing transaction") break - for a in allocated: + for a in to_deallocate: + deallocated.add(a) if a.port: # calling update_port() for each allocation to remove the # IP from the port and call the MechanismDrivers diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index 03c0b40936..619855597a 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -431,6 +431,12 @@ class TestMl2SubnetsV2(test_plugin.TestSubnetsV2, req = self.new_delete_request('subnets', subnet_id) res = req.get_response(self.api) self.assertEqual(204, res.status_int) + # Validate chat check is called twice, i.e. after the + # first check transaction gets restarted. + calls = [mock.call(mock.ANY, subnet_id), + mock.call(mock.ANY, subnet_id)] + plugin._subnet_check_ip_allocations.assert_has_calls = ( + calls) class TestMl2DbOperationBounds(test_plugin.DbOperationBoundMixin, |