From 19b8fbbf8c5b58928b6b70d4eeecb34dbe16b0f6 Mon Sep 17 00:00:00 2001 From: Stuart McLaren Date: Tue, 3 Dec 2013 11:26:12 +0000 Subject: [PATCH] Prevent E500 when delayed delete is enabled If delayed delete is enabled the user token was not being propagated properly to the registry in all cases. This resulted in an authentication error when the API attempted to connect to the registry, which in turn caused a 500 error from the API. Fix for bug 1238604. Also, place a restriction on the highest version of python-swiftclient for the havana stable branch. Change-Id: Ifafc1613db034508abfce7ba5e4df582e6056c10 --- glance/store/__init__.py | 7 +++- glance/store/scrubber.py | 16 ++++++-- glance/tests/functional/store/test_swift.py | 42 +++++++++++++++++++++ requirements.txt | 2 +- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/glance/store/__init__.py b/glance/store/__init__.py index fa80b15236..fa17f4b973 100644 --- a/glance/store/__init__.py +++ b/glance/store/__init__.py @@ -59,6 +59,9 @@ store_opts = [ 'glance-scrubber.conf')), cfg.BoolOpt('delayed_delete', default=False, help=_('Turn on/off delayed delete.')), + cfg.BoolOpt('use_user_token', default=True, + help=_('Whether to pass through the user token when ' + 'making requests to the registry.')), cfg.IntOpt('scrub_time', default=0, help=_('The amount of time in seconds to delay before ' 'performing a delete.')), @@ -290,7 +293,9 @@ def schedule_delayed_delete_from_backend(context, uri, image_id, **kwargs): # In future we can change it using DB based queued instead, # such as using image location's status to saving pending delete flag # when that property be added. - file_queue.add_location(image_id, uri) + if CONF.use_user_token is False: + context = None + file_queue.add_location(image_id, uri, user_context=context) def delete_image_from_backend(context, store_api, image_id, uri): diff --git a/glance/store/scrubber.py b/glance/store/scrubber.py index 33caab46f4..2aa14c76ba 100644 --- a/glance/store/scrubber.py +++ b/glance/store/scrubber.py @@ -70,11 +70,12 @@ class ScrubQueue(object): self.registry = registry.get_registry_client(context.RequestContext()) @abc.abstractmethod - def add_location(self, image_id, uri): + def add_location(self, image_id, uri, user_context=None): """Adding image location to scrub queue. :param image_id: The opaque image identifier :param uri: The opaque image location uri + :param user_context: The user's request context """ pass @@ -159,12 +160,18 @@ class ScrubFileQueue(ScrubQueue): except Exception: LOG.error(_("%s file can not be wrote.") % file_path) - def add_location(self, image_id, uri): + def add_location(self, image_id, uri, user_context=None): """Adding image location to scrub queue. :param image_id: The opaque image identifier :param uri: The opaque image location uri + :param user_context: The user's request context """ + if user_context is not None: + registry_client = registry.get_registry_client(user_context) + else: + registry_client = self.registry + with lockutils.lock("scrubber-%s" % image_id, lock_file_prefix='glance-', external=True): @@ -172,7 +179,7 @@ class ScrubFileQueue(ScrubQueue): # 'pending_delete' images concurrently before the code # get lock and reach here. try: - image = self.registry.get_image(image_id) + image = registry_client.get_image(image_id) if image['status'] == 'deleted': return except exception.NotFound as e: @@ -271,11 +278,12 @@ class ScrubDBQueue(ScrubQueue): super(ScrubDBQueue, self).__init__() self.cleanup_scrubber_time = CONF.cleanup_scrubber_time - def add_location(self, image_id, uri): + def add_location(self, image_id, uri, user_context=None): """Adding image location to scrub queue. :param image_id: The opaque image identifier :param uri: The opaque image location uri + :param user_context: The user's request context """ raise NotImplementedError diff --git a/glance/tests/functional/store/test_swift.py b/glance/tests/functional/store/test_swift.py index 07ff7eac1b..634d484355 100644 --- a/glance/tests/functional/store/test_swift.py +++ b/glance/tests/functional/store/test_swift.py @@ -369,3 +369,45 @@ class TestSwiftStore(store_tests.BaseTestCase, testtools.TestCase): self.assertEqual('XXX', ''.join(get_iter)) store.delete(location) + + def test_delayed_delete_with_auth(self): + """Ensure delete works with delayed delete and auth + + Reproduces LP bug 1238604. + """ + swift_store_user = self.swift_config['swift_store_user'] + tenant_name, username = swift_store_user.split(':') + tenant_id, auth_token, service_catalog = keystone_authenticate( + self.swift_config['swift_store_auth_address'], + self.swift_config['swift_store_auth_version'], + tenant_name, + username, + self.swift_config['swift_store_key']) + + context = glance.context.RequestContext( + tenant=tenant_id, + service_catalog=service_catalog, + auth_tok=auth_token) + store = self.get_store(context=context) + + image_id = uuidutils.generate_uuid() + image_data = StringIO.StringIO('data') + uri, _, _, _ = store.add(image_id, image_data, 4) + + location = glance.store.location.Location( + self.store_name, + store.get_store_location_class(), + uri=uri, + image_id=image_id) + + container_name = location.store_location.container + container, _ = swift_get_container(self.swift_client, container_name) + + (get_iter, get_size) = store.get(location) + self.assertEqual(4, get_size) + self.assertEqual('data', ''.join(get_iter)) + + glance.store.schedule_delayed_delete_from_backend(context, + uri, + image_id) + store.delete(location) diff --git a/requirements.txt b/requirements.txt index 5cae74e9dc..ae73e26b17 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ iso8601>=0.1.8 oslo.config>=1.2.0 # For Swift storage backend. -python-swiftclient>=1.5 +python-swiftclient>=1.5,<2.0.0 # Note you will need gcc buildtools installed and must # have installed libxml headers for lxml to be successfully