From e74b5b75de8ad58263dc253a48668626485b3f36 Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Wed, 15 Jun 2016 17:39:52 -0400 Subject: [PATCH] Don't attempt to lazy-load tags on a deleted instance Since we don't have a specific handler for lazy-loading tags on an Instance object it loads generically but that will fail with an InstanceNotFound on a deleted instance, so just handle this in obj_load_attr like we do for 'services'. Note we can't call the TagList object to load the tags for us since the DB API will fail if the instance is deleted too. Change-Id: If3580dcc3e83f612b96a2c3ad893a5045ee6100a Related-Bug: #1592963 --- nova/objects/instance.py | 5 +++++ nova/tests/unit/objects/test_instance.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 0c3a30ecc625..4a97a3fd445e 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -980,6 +980,11 @@ class Instance(base.NovaPersistentObject, base.NovaObject, # filters on instances.deleted == 0, so if the instance is deleted # don't attempt to even load services since we'll fail. self.services = objects.ServiceList(self._context) + elif attrname == 'tags' and self.deleted: + # NOTE(mriedem): Same story as services, the DB API query + # in instance_tag_get_by_instance_uuid will fail if the instance + # has been deleted so just return an empty tag list here. + self.tags = objects.TagList(self._context) else: # FIXME(comstud): This should be optimized to only load the attr. self._load_generic(attrname) diff --git a/nova/tests/unit/objects/test_instance.py b/nova/tests/unit/objects/test_instance.py index b58b11586340..f54695238f97 100644 --- a/nova/tests/unit/objects/test_instance.py +++ b/nova/tests/unit/objects/test_instance.py @@ -208,6 +208,13 @@ class _TestInstanceObject(object): deleted=True) self.assertEqual(0, len(instance.services)) + def test_lazy_load_tags_on_deleted_instance(self): + # We should avoid trying to hit the database to reload the instance + # and just set the tags attribute to an empty list. + instance = objects.Instance(self.context, uuid=uuids.instance, + deleted=True) + self.assertEqual(0, len(instance.tags)) + @mock.patch.object(db, 'instance_get') def test_get_by_id(self, mock_get): mock_get.return_value = self.fake_instance