Guard __getattr__ on QuotaImageTagsProxy

In the related bug (below) we can see getting tags from a
QuotaImageTagsProxy can sometimes cause an infinite loop, presumably
because of bizarre threading circumstances. To at least provide a bit
more information when this bizarre circumstance happens, instead
of looping, resulting in a stackoverflow and the processing being
terminated without a traceback, now raise a TypeError. This should
help figure out what may be going on in the rare times this happens.

Also, it is generally a healthy idea to always have a guard like this
in a __getattr__ that uses an attr.

Change-Id: Ib4ad119a838d5b06372d9302dc6608da1772eed6
Related-Bug: #1808063
This commit is contained in:
Chris Dent 2018-12-13 18:59:39 +00:00
parent 8d1beed2a8
commit 044d6b45f9
2 changed files with 18 additions and 1 deletions

View File

@ -165,7 +165,14 @@ class QuotaImageTagsProxy(object):
return self.tags.__len__(*args, **kwargs)
def __getattr__(self, name):
return getattr(self.tags, name)
# Use TypeError here, not AttributeError, as the latter is how we
# know a tag is not present. TypeError says "this object is not
# what it claims to be".
try:
tags = self.__getattribute__('tags')
except AttributeError:
raise TypeError('QuotaImageTagsProxy has no tags.')
return getattr(tags, name)
class ImageMemberFactoryProxy(glance.domain.proxy.ImageMembershipFactory):

View File

@ -596,6 +596,16 @@ class TestQuotaImageTagsProxy(test_utils.BaseTestCase):
items.remove(item)
self.assertEqual(0, len(items))
def test_tags_attr_exception(self):
proxy = glance.quota.QuotaImageTagsProxy(None)
self.assertRaises(AttributeError, lambda: proxy.foo)
# Remove tags to cause the object to be broken. If tags
# is not there and we weren't raising TypeError, we'd
# get an infinite loop when calling 'proxy.foo'.
del proxy.tags
self.assertRaises(TypeError, lambda: proxy.foo)
class TestImageMemberQuotas(test_utils.BaseTestCase):