summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-03-05 17:00:26 +0000
committerGerrit Code Review <review@openstack.org>2015-03-05 17:00:26 +0000
commitc1e8697f124006ea9096c9a29613ac03a92fbc1b (patch)
tree6da83e44d8e2f06188c8f82729640de1436f9033
parent547dc2fcfbd49d1e220b6c2d71d26a6a14b457bd (diff)
parent9221e44182dee1198e323e91a78c157988f99fda (diff)
downloadglance_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.py27
-rw-r--r--tests/unit/test_swift_store.py49
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