diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 4a97a3fd445e..68f1a0cc3665 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -882,6 +882,10 @@ class Instance(base.NovaPersistentObject, base.NovaObject, jsonutils.loads(db_keypairs)) self.obj_reset_changes(['keypairs']) + def _load_tags(self): + self.tags = objects.TagList.get_by_resource_id( + self._context, self.uuid) + def apply_migration_context(self): if self.migration_context: self._set_migration_context_to_instance(prefix='new_') @@ -980,11 +984,14 @@ 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) + elif attrname == 'tags': + if 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. + self.tags = objects.TagList(self._context) + else: + self._load_tags() 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 f54695238f97..f701437f2f7b 100644 --- a/nova/tests/unit/objects/test_instance.py +++ b/nova/tests/unit/objects/test_instance.py @@ -215,6 +215,17 @@ class _TestInstanceObject(object): deleted=True) self.assertEqual(0, len(instance.tags)) + def test_lazy_load_tags(self): + instance = objects.Instance(self.context, uuid=uuids.instance, + user_id=self.context.user_id, + project_id=self.context.project_id) + instance.create() + tag = objects.Tag(self.context, resource_id=instance.uuid, tag='foo') + tag.create() + self.assertNotIn('tags', instance) + self.assertEqual(1, len(instance.tags)) + self.assertEqual('foo', instance.tags[0].tag) + @mock.patch.object(db, 'instance_get') def test_get_by_id(self, mock_get): mock_get.return_value = self.fake_instance