Fixes from Rick's review #1
This commit is contained in:
@@ -51,6 +51,9 @@ swift_store_account = glance
|
||||
# for storing images in Swift
|
||||
swift_store_container = glance
|
||||
|
||||
# Do we create the container if it does not exist?
|
||||
swift_store_create_container_on_put = False
|
||||
|
||||
[app:glance-registry]
|
||||
paste.app_factory = glance.registry.server:app_factory
|
||||
|
||||
|
||||
@@ -148,7 +148,30 @@ class SwiftBackend(glance.store.Backend):
|
||||
"key=%(key)s)")
|
||||
|
||||
try:
|
||||
obj_etag = swift_conn.put_object(container, id, data)
|
||||
swift_conn.head_container(container)
|
||||
except Exception, e:
|
||||
if e.http_status == httplib.NOT_FOUND:
|
||||
add_container = config.get_option(options,
|
||||
'swift_store_create_container_on_put',
|
||||
type='bool', default=False)
|
||||
if add_container:
|
||||
try:
|
||||
swift_conn.put_container(container)
|
||||
except Exception, e:
|
||||
msg = ("Failed to add container to Swift.\n"
|
||||
"Got error from Swift: %(e)s" % locals())
|
||||
raise glance.store.BackendException(msg)
|
||||
else:
|
||||
msg = ("The container %(container)s does not exist in "
|
||||
"Swift. Please set the "
|
||||
"swift_store_create_container_on_put option"
|
||||
"to add container to Swift automatically."
|
||||
% locals())
|
||||
raise glance.store.BackendException(msg)
|
||||
|
||||
obj_name = str(id)
|
||||
try:
|
||||
obj_etag = swift_conn.put_object(container, obj_name, data)
|
||||
|
||||
# NOTE: We return the user and key here! Have to because
|
||||
# location is used by the API server to return the actual
|
||||
@@ -156,12 +179,12 @@ class SwiftBackend(glance.store.Backend):
|
||||
# the location attribute from GET /images/<ID> and
|
||||
# GET /images/details
|
||||
location = "swift://%(user)s:%(key)s@%(auth_address)s/"\
|
||||
"%(container)s/%(id)s" % locals()
|
||||
"%(container)s/%(obj_name)s" % locals()
|
||||
|
||||
# We do a HEAD on the newly-added image to determine the size
|
||||
# of the image. A bit slow, but better than taking the word
|
||||
# of the user adding the image with size attribute in the metadata
|
||||
resp_headers = swift_conn.head_object(container, id)
|
||||
resp_headers = swift_conn.head_object(container, obj_name)
|
||||
size = 0
|
||||
# header keys are lowercased by Swift
|
||||
if 'content-length' in resp_headers:
|
||||
@@ -175,7 +198,7 @@ class SwiftBackend(glance.store.Backend):
|
||||
location = "swift://%s:%s@%s/%s/%s" % (user, key, auth_address,
|
||||
container, id)
|
||||
raise exception.Duplicate("Swift already has an image at "
|
||||
"location %(location)s" % locals())
|
||||
"location %(location)s" % locals())
|
||||
msg = ("Failed to add object to Swift.\n"
|
||||
"Got error from Swift: %(e)s" % locals())
|
||||
raise glance.store.BackendException(msg)
|
||||
|
||||
@@ -42,7 +42,7 @@ except ImportError:
|
||||
FIVE_KB = (5 * 1024)
|
||||
SWIFT_OPTIONS = {'verbose': True,
|
||||
'debug': True,
|
||||
'swift_store_user': 'glance',
|
||||
'swift_store_user': 'user',
|
||||
'swift_store_key': 'key',
|
||||
'swift_store_auth_address': 'localhost:8080',
|
||||
'swift_store_container': 'glance'}
|
||||
@@ -53,12 +53,22 @@ SWIFT_OPTIONS = {'verbose': True,
|
||||
# thoroughly
|
||||
def stub_out_swift_common_client(stubs):
|
||||
|
||||
fixture_containers = ['glance']
|
||||
fixture_headers = {'glance/2':
|
||||
{'content-length': FIVE_KB,
|
||||
'etag': 'c2e5db72bd7fd153f53ede5da5a06de3'}}
|
||||
fixture_objects = {'glance/2':
|
||||
StringIO.StringIO("*" * FIVE_KB)}
|
||||
|
||||
def fake_head_container(url, token, container, **kwargs):
|
||||
if container not in fixture_containers:
|
||||
msg = "No container %s found" % container
|
||||
raise swift.common.client.ClientException(msg,
|
||||
http_status=httplib.NOT_FOUND)
|
||||
|
||||
def fake_put_container(url, token, container, **kwargs):
|
||||
fixture_containers.append(container)
|
||||
|
||||
def fake_put_object(url, token, container, name, contents, **kwargs):
|
||||
# PUT returns the ETag header for the newly-added object
|
||||
fixture_key = "%s/%s" % (container, name)
|
||||
@@ -122,6 +132,10 @@ def stub_out_swift_common_client(stubs):
|
||||
def fake_get_auth(self):
|
||||
return None, None
|
||||
|
||||
stubs.Set(swift.common.client,
|
||||
'head_container', fake_head_container)
|
||||
stubs.Set(swift.common.client,
|
||||
'put_container', fake_put_container)
|
||||
stubs.Set(swift.common.client,
|
||||
'put_object', fake_put_object)
|
||||
stubs.Set(swift.common.client,
|
||||
@@ -212,8 +226,65 @@ class TestSwiftBackend(unittest.TestCase):
|
||||
self.assertEquals(expected_location, location)
|
||||
self.assertEquals(expected_swift_size, size)
|
||||
|
||||
url_pieces = urlparse.urlparse(
|
||||
"swift://user:key@auth_address/glance/42")
|
||||
url_pieces = urlparse.urlparse(expected_location)
|
||||
new_image_swift = SwiftBackend.get(url_pieces)
|
||||
new_image_contents = new_image_swift.getvalue()
|
||||
new_image_swift_size = new_image_swift.len
|
||||
|
||||
self.assertEquals(expected_swift_contents, new_image_contents)
|
||||
self.assertEquals(expected_swift_size, new_image_swift_size)
|
||||
|
||||
def test_add_no_container_no_create(self):
|
||||
"""
|
||||
Tests that adding an image with a non-existing container
|
||||
raises an appropriate exception
|
||||
"""
|
||||
if not SWIFT_INSTALLED:
|
||||
return
|
||||
options = SWIFT_OPTIONS.copy()
|
||||
options['swift_store_create_container_on_put'] = 'False'
|
||||
options['swift_store_container'] = 'noexist'
|
||||
image_swift = StringIO.StringIO("nevergonnamakeit")
|
||||
|
||||
# We check the exception text to ensure the container
|
||||
# missing text is found in it, otherwise, we would have
|
||||
# simply used self.assertRaises here
|
||||
exception_caught = False
|
||||
try:
|
||||
SwiftBackend.add(3, image_swift, options)
|
||||
except glance.store.BackendException, e:
|
||||
exception_caught = True
|
||||
self.assertTrue("container noexist does not exist "
|
||||
"in Swift" in str(e))
|
||||
self.assertTrue(exception_caught)
|
||||
|
||||
def test_add_no_container_and_create(self):
|
||||
"""
|
||||
Tests that adding an image with a non-existing container
|
||||
creates the container automatically if flag is set
|
||||
"""
|
||||
if not SWIFT_INSTALLED:
|
||||
return
|
||||
options = SWIFT_OPTIONS.copy()
|
||||
options['swift_store_create_container_on_put'] = 'True'
|
||||
options['swift_store_container'] = 'noexist'
|
||||
expected_image_id = 42
|
||||
expected_swift_size = 1024 * 5 # 5K
|
||||
expected_swift_contents = "*" * expected_swift_size
|
||||
expected_location = "swift://%s:%s@%s/%s/%s" % (
|
||||
options['swift_store_user'],
|
||||
options['swift_store_key'],
|
||||
options['swift_store_auth_address'],
|
||||
options['swift_store_container'],
|
||||
expected_image_id)
|
||||
image_swift = StringIO.StringIO(expected_swift_contents)
|
||||
|
||||
location, size = SwiftBackend.add(42, image_swift, options)
|
||||
|
||||
self.assertEquals(expected_location, location)
|
||||
self.assertEquals(expected_swift_size, size)
|
||||
|
||||
url_pieces = urlparse.urlparse(expected_location)
|
||||
new_image_swift = SwiftBackend.get(url_pieces)
|
||||
new_image_contents = new_image_swift.getvalue()
|
||||
new_image_swift_size = new_image_swift.len
|
||||
@@ -228,6 +299,7 @@ class TestSwiftBackend(unittest.TestCase):
|
||||
"""
|
||||
if not SWIFT_INSTALLED:
|
||||
return
|
||||
|
||||
image_swift = StringIO.StringIO("nevergonnamakeit")
|
||||
self.assertRaises(exception.Duplicate,
|
||||
SwiftBackend.add,
|
||||
|
||||
Reference in New Issue
Block a user