summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@gmail.com>2012-08-17 15:03:46 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2012-08-17 16:12:28 -0700
commit1f98e28a80077760394201f79de04a0924b9ad3f (patch)
treea8a53d561827363a3e7f67773f4a06f92e556d91
parenta10be151ad9f62bb916498c8dae42e4b54dfc779 (diff)
downloadnova-1f98e28a80077760394201f79de04a0924b9ad3f.tar.gz
nova-1f98e28a80077760394201f79de04a0924b9ad3f.tar.xz
nova-1f98e28a80077760394201f79de04a0924b9ad3f.zip
Makes sure instance deletion ok with deleted data
Commit 5ad1dea4 added changed the network deallocation code to work with deleted instances. This was done by setting the context to read deleted records. Unfortunately this was done a little too broadly, leading to a new bug where a deleted floating_ip will cause an instance to not be able to be deleted. This fixes the issue by limiting the use of read_deleted context to only the places it is trying to access the instance record. It adds a test to verify that the code works with a duplicate deleted floating_ip and updates the existing test for a deleted instance to exercise the entire code path. Fixes bug 1038266 Change-Id: I1aef94369e5bcf951e78e89b1eded5305cf36b53
-rw-r--r--nova/db/sqlalchemy/api.py6
-rw-r--r--nova/network/manager.py18
-rw-r--r--nova/tests/network/test_manager.py55
3 files changed, 58 insertions, 21 deletions
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index d15b7b353..8867d3dc2 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1170,7 +1170,8 @@ def fixed_ip_get(context, id, session=None):
# FIXME(sirp): shouldn't we just use project_only here to restrict the
# results?
if is_user_context(context) and result['instance_uuid'] is not None:
- instance = instance_get_by_uuid(context, result['instance_uuid'],
+ instance = instance_get_by_uuid(context.elevated(read_deleted='yes'),
+ result['instance_uuid'],
session)
authorize_project_context(context, instance.project_id)
@@ -1199,7 +1200,8 @@ def fixed_ip_get_by_address(context, address, session=None):
# NOTE(sirp): shouldn't we just use project_only here to restrict the
# results?
if is_user_context(context) and result['instance_uuid'] is not None:
- instance = instance_get_by_uuid(context, result['instance_uuid'],
+ instance = instance_get_by_uuid(context.elevated(read_deleted='yes'),
+ result['instance_uuid'],
session)
authorize_project_context(context, instance.project_id)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 470a186ee..c1f3a6418 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -353,14 +353,11 @@ class FloatingIP(object):
# NOTE(francois.charlier): in some cases the instance might be
# deleted before the IPs are released, so we need to get deleted
# instances too
- read_deleted_context = context.elevated(read_deleted='yes')
- instance = self.db.instance_get(read_deleted_context, instance_id)
-
- LOG.debug(_("floating IP deallocation for instance |%s|"),
- instance=instance, context=read_deleted_context)
+ instance = self.db.instance_get(
+ context.elevated(read_deleted='yes'), instance_id)
try:
- fixed_ips = self.db.fixed_ip_get_by_instance(read_deleted_context,
+ fixed_ips = self.db.fixed_ip_get_by_instance(context,
instance['uuid'])
except exception.FixedIpNotFoundForInstance:
fixed_ips = []
@@ -374,14 +371,14 @@ class FloatingIP(object):
for floating_ip in floating_ips:
address = floating_ip['address']
try:
- self.disassociate_floating_ip(read_deleted_context,
+ self.disassociate_floating_ip(context,
address,
affect_auto_assigned=True)
except exception.FloatingIpNotAssociated:
LOG.exception(_("Floating IP is not associated. Ignore."))
# deallocate if auto_assigned
if floating_ip['auto_assigned']:
- self.deallocate_floating_ip(read_deleted_context, address,
+ self.deallocate_floating_ip(context, address,
affect_auto_assigned=True)
# call the next inherited class's deallocate_for_instance()
@@ -1276,8 +1273,9 @@ class NetworkManager(manager.SchedulerDependentManager):
"""Returns a fixed ip to the pool."""
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
vif_id = fixed_ip_ref['virtual_interface_id']
- instance = self.db.instance_get_by_uuid(context,
- fixed_ip_ref['instance_uuid'])
+ instance = self.db.instance_get_by_uuid(
+ context.elevated(read_deleted='yes'),
+ fixed_ip_ref['instance_uuid'])
self._do_trigger_security_group_members_refresh_for_instance(
instance['uuid'])
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index 9c53525f4..5ae8cf81c 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -1042,12 +1042,14 @@ class VlanNetworkTestCase(test.TestCase):
fixed = db.fixed_ip_get_by_address(elevated, fix_addr)
network = db.network_get(elevated, fixed['network_id'])
- db.instance_destroy(self.context.elevated(), instance['uuid'])
- self.assertRaises(exception.InstanceNotFound,
- self.network.deallocate_fixed_ip,
- context1,
- fix_addr,
- 'fake')
+ def fake_refresh(instance_uuid):
+ raise test.TestingException()
+ self.stubs.Set(self.network,
+ '_do_trigger_security_group_members_refresh_for_instance',
+ fake_refresh)
+ self.assertRaises(test.TestingException,
+ self.network.deallocate_fixed_ip,
+ context1, fix_addr, 'fake')
fixed = db.fixed_ip_get_by_address(elevated, fix_addr)
self.assertTrue(fixed['allocated'])
@@ -1541,10 +1543,45 @@ class FloatingIPTestCase(test.TestCase):
instance_id=instance_ref['id'])
def test_deallocation_deleted_instance(self):
- instance_ref = db.api.instance_create(self.context,
- {"project_id": self.project_id, "deleted": True})
+ self.stubs.Set(self.network, '_teardown_network_on_host',
+ lambda *args, **kwargs: None)
+ instance = db.api.instance_create(self.context, {
+ 'project_id': self.project_id, 'deleted': True})
+ network = db.api.network_create_safe(self.context.elevated(), {
+ 'project_id': self.project_id})
+ addr = db.fixed_ip_create(self.context, {'allocated': True,
+ 'instance_uuid': instance['uuid'], 'address': '10.1.1.1',
+ 'network_id': network['id']})
+ fixed = db.fixed_ip_get_by_address(
+ self.context.elevated(read_deleted='yes'), addr)
+ db.api.floating_ip_create(self.context, {
+ 'address': '10.10.10.10', 'instance_uuid': instance['uuid'],
+ 'fixed_ip_id': fixed['id'],
+ 'project_id': self.project_id})
self.network.deallocate_for_instance(self.context,
- instance_id=instance_ref['id'])
+ instance_id=instance['id'])
+
+ def test_deallocation_duplicate_floating_ip(self):
+ self.stubs.Set(self.network, '_teardown_network_on_host',
+ lambda *args, **kwargs: None)
+ instance = db.api.instance_create(self.context, {
+ 'project_id': self.project_id})
+ network = db.api.network_create_safe(self.context.elevated(), {
+ 'project_id': self.project_id})
+ addr = db.fixed_ip_create(self.context, {'allocated': True,
+ 'instance_uuid': instance['uuid'], 'address': '10.1.1.1',
+ 'network_id': network['id']})
+ fixed = db.fixed_ip_get_by_address(
+ self.context.elevated(read_deleted='yes'), addr)
+ db.api.floating_ip_create(self.context, {
+ 'address': '10.10.10.10',
+ 'deleted': True})
+ db.api.floating_ip_create(self.context, {
+ 'address': '10.10.10.10', 'instance_uuid': instance['uuid'],
+ 'fixed_ip_id': fixed['id'],
+ 'project_id': self.project_id})
+ self.network.deallocate_for_instance(self.context,
+ instance_id=instance['id'])
def test_floating_dns_create_conflict(self):
zone = "example.org"