diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-03-05 17:00:26 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-03-05 17:00:26 +0000 |
commit | c1e8697f124006ea9096c9a29613ac03a92fbc1b (patch) | |
tree | 6da83e44d8e2f06188c8f82729640de1436f9033 | |
parent | 547dc2fcfbd49d1e220b6c2d71d26a6a14b457bd (diff) | |
parent | 9221e44182dee1198e323e91a78c157988f99fda (diff) | |
download | glance_store-c1e8697f124006ea9096c9a29613ac03a92fbc1b.tar.gz |
Merge "Support for deleting images stored as SLO in Swift"0.2.0
-rw-r--r-- | glance_store/_drivers/swift/store.py | 27 | ||||
-rw-r--r-- | tests/unit/test_swift_store.py | 49 |
2 files changed, 69 insertions, 7 deletions
diff --git a/glance_store/_drivers/swift/store.py b/glance_store/_drivers/swift/store.py index 9f1995c..30b69f3 100644 --- a/glance_store/_drivers/swift/store.py +++ b/glance_store/_drivers/swift/store.py @@ -22,6 +22,7 @@ import math from oslo.config import cfg from oslo.utils import excutils +import six import six.moves.urllib.parse as urlparse import swiftclient import urllib @@ -373,6 +374,14 @@ def Store(conf): Store.OPTIONS = _SWIFT_OPTS + sutils.swift_opts +def _is_slo(slo_header): + if (slo_header is not None and isinstance(slo_header, six.string_types) + and slo_header.lower() == 'true'): + return True + + return False + + class BaseStore(driver.Store): _CAPABILITIES = capabilities.BitMasks.RW_ACCESS @@ -612,17 +621,27 @@ class BaseStore(driver.Store): # that means the object was uploaded in chunks/segments, # and we need to delete all the chunks as well as the # manifest. - manifest = None + dlo_manifest = None + slo_manifest = None try: headers = connection.head_object( location.container, location.obj) - manifest = headers.get('x-object-manifest') + dlo_manifest = headers.get('x-object-manifest') + slo_manifest = headers.get('x-static-large-object') except swiftclient.ClientException as e: if e.http_status != httplib.NOT_FOUND: raise - if manifest: + + if _is_slo(slo_manifest): + # Delete the manifest as well as the segments + query_string = 'multipart-manifest=delete' + connection.delete_object(location.container, location.obj, + query_string=query_string) + return + + if dlo_manifest: # Delete all the chunks before the object manifest itself - obj_container, obj_prefix = manifest.split('/', 1) + obj_container, obj_prefix = dlo_manifest.split('/', 1) segments = connection.get_container( obj_container, prefix=obj_prefix)[1] for segment in segments: diff --git a/tests/unit/test_swift_store.py b/tests/unit/test_swift_store.py index 3f4ba8c..8a541a4 100644 --- a/tests/unit/test_swift_store.py +++ b/tests/unit/test_swift_store.py @@ -49,6 +49,7 @@ from tests.unit import test_store_capabilities CONF = cfg.CONF FAKE_UUID = lambda: str(uuid.uuid4()) +FAKE_UUID2 = lambda: str(uuid.uuid4()) Store = swift.Store FIVE_KB = 5 * units.Ki @@ -76,10 +77,11 @@ def stub_out_swiftclient(stubs, swift_store_auth_version): 'glance/%s' % FAKE_UUID: { 'content-length': FIVE_KB, 'etag': 'c2e5db72bd7fd153f53ede5da5a06de3' - } + }, + 'glance/%s' % FAKE_UUID2: {'x-static-large-object': 'true', }, } - fixture_objects = {'glance/%s' % FAKE_UUID: - six.StringIO("*" * FIVE_KB)} + fixture_objects = {'glance/%s' % FAKE_UUID: six.StringIO("*" * FIVE_KB), + 'glance/%s' % FAKE_UUID2: six.StringIO("*" * FIVE_KB), } def fake_head_container(url, token, container, **kwargs): if container not in fixture_containers: @@ -810,6 +812,47 @@ class SwiftTests(object): self.assertRaises(exceptions.NotFound, self.store.get, loc) + @mock.patch.object(swiftclient.client, 'delete_object') + def test_delete_slo(self, mock_del_obj): + """ + Test we can delete an existing image stored as SLO, static large object + """ + conf = copy.deepcopy(SWIFT_CONF) + self.config(**conf) + reload(swift) + self.store = Store(self.conf) + self.store.configure() + + uri = "swift://%s:key@authurl/glance/%s" % (self.swift_store_user, + FAKE_UUID2) + loc = location.get_location_from_uri(uri, conf=self.conf) + self.store.delete(loc) + + mock_del_obj.assert_called_once() + _, kwargs = mock_del_obj.call_args + self.assertEqual('multipart-manifest=delete', + kwargs.get('query_string')) + + @mock.patch.object(swiftclient.client, 'delete_object') + def test_delete_nonslo_not_deleted_as_slo(self, mock_del_obj): + """ + Test that non-SLOs are not being deleted the SLO way + """ + conf = copy.deepcopy(SWIFT_CONF) + self.config(**conf) + reload(swift) + self.store = Store(self.conf) + self.store.configure() + + uri = "swift://%s:key@authurl/glance/%s" % (self.swift_store_user, + FAKE_UUID) + loc = location.get_location_from_uri(uri, conf=self.conf) + self.store.delete(loc) + + mock_del_obj.assert_called_once() + _, kwargs = mock_del_obj.call_args + self.assertEqual(None, kwargs.get('query_string')) + def test_delete_with_reference_params(self): """ Test we can delete an existing image in the swift store |