Put account in glance.conf.sample's swift_store_auth_address, use real swift.common.client.ClientException, ensure tests work with older installed versions of Swift (which do not have, for example, swift.common.client.Connection.get_auth method)

This commit is contained in:
jaypipes@gmail.com 2011-03-04 19:02:26 -05:00
parent a6dcd64d69
commit ee74c26dbd
6 changed files with 59 additions and 141 deletions

View File

@ -73,7 +73,7 @@ Debian/Ubuntu
1. Install Bazaar and build dependencies::
$> sudo apt-get install bzr python-eventlet python-routes python-greenlet
$> sudo apt-get install bzr python-eventlet python-routes python-greenlet swift
$> sudo apt-get install python-argparse python-sqlalchemy python-wsgiref python-pastedeploy
.. note::

View File

@ -34,7 +34,9 @@ filesystem_store_datadir=/var/lib/glance/images/
# ============ Swift Store Options =============================
# Address where the Swift authentication service lives
swift_store_auth_address = 127.0.0.1:8080
# The auth address should be in the form:
# <DOMAIN>[:<PORT>]/<VERSION>/<ACCOUNT>
swift_store_auth_address = 127.0.0.1:8080/v1.0/glance-account
# User to authenticate against the Swift authentication service
swift_store_user = jdoe
@ -43,10 +45,6 @@ swift_store_user = jdoe
# Swift authentication service
swift_store_key = a86850deb2742ec3cb41518e26aa2d89
# Account to use for the user:key Swift auth combination
# for storing images in Swift
swift_store_account = glance
# Container within the account that the account should use
# for storing images in Swift
swift_store_container = glance

View File

@ -17,10 +17,14 @@
"""Storage backend for SWIFT"""
from __future__ import absolute_import
import httplib
import logging
import urllib
from swift.common.client import Connection, ClientException
from glance.common import config
from glance.common import exception
import glance.store
@ -54,18 +58,13 @@ class SwiftBackend(glance.store.Backend):
# TODO(sirp): snet=False for now, however, if the instance of
# swift we're talking to is within our same region, we should set
# snet=True
connection_class = get_connection_class(conn_class)
swift_conn = connection_class(
swift_conn = Connection(
authurl=authurl, user=user, key=key, snet=False)
try:
(resp_headers, resp_body) = swift_conn.get_object(
container=container, obj=obj, resp_chunk_size=cls.CHUNKSIZE)
# TODO(jaypipes) use real exceptions when remove all the cruft
# around importing Swift stuff...
except Exception, e:
except ClientException, e:
if e.http_status == httplib.NOT_FOUND:
location = "swift://%s:%s@%s/%s/%s" % (user, key, authurl,
container, obj)
@ -139,35 +138,14 @@ class SwiftBackend(glance.store.Backend):
"options.")
raise glance.store.BackendException(msg)
connection_class = get_connection_class(conn_class)
swift_conn = connection_class(authurl=full_auth_address, user=user,
swift_conn = Connection(authurl=full_auth_address, user=user,
key=key, snet=False)
logger.debug("Adding image object to Swift using "
"(auth_address=%(auth_address)s, user=%(user)s, "
"key=%(key)s)")
"key=%(key)s)" % locals())
try:
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)
create_container_if_missing(container, swift_conn, options)
obj_name = str(id)
try:
@ -190,10 +168,7 @@ class SwiftBackend(glance.store.Backend):
if 'content-length' in resp_headers:
size = int(resp_headers['content-length'])
return (location, size)
# TODO(jaypipes) use real exceptions when remove all the cruft
# around importing Swift stuff...
except Exception, e:
except ClientException, e:
if e.http_status == httplib.CONFLICT:
location = "swift://%s:%s@%s/%s/%s" % (user, key, auth_address,
container, id)
@ -214,17 +189,12 @@ class SwiftBackend(glance.store.Backend):
# TODO(sirp): snet=False for now, however, if the instance of
# swift we're talking to is within our same region, we should set
# snet=True
connection_class = get_connection_class(conn_class)
swift_conn = connection_class(
swift_conn = Connection(
authurl=authurl, user=user, key=key, snet=False)
try:
swift_conn.delete_object(container, obj)
# TODO(jaypipes) use real exceptions when remove all the cruft
# around importing Swift stuff...
except Exception, e:
except ClientException, e:
if e.http_status == httplib.NOT_FOUND:
location = "swift://%s:%s@%s/%s/%s" % (user, key, authurl,
container, obj)
@ -266,8 +236,33 @@ class SwiftBackend(glance.store.Backend):
return user, key, authurl, container, obj
def get_connection_class(conn_class):
if not conn_class:
import swift.common.client
conn_class = swift.common.client.Connection
return conn_class
def create_container_if_missing(container, swift_conn, options):
"""
Creates a missing container in Swift if the
``swift_store_create_container_on_put`` option is set.
:param container: Name of container to create
:param swift_conn: Connection to Swift
:param options: Option mapping
"""
try:
swift_conn.head_container(container)
except ClientException, 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 ClientException, 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)

View File

@ -33,7 +33,6 @@ from glance import server
import glance.store
import glance.store.filesystem
import glance.store.http
import glance.store.swift
import glance.registry.db.api
@ -109,7 +108,7 @@ def stub_out_filesystem_backend():
def stub_out_s3_backend(stubs):
""" Stubs out the S3 Backend with fake data and calls.
The stubbed swift backend provides back an iterator over
The stubbed s3 backend provides back an iterator over
the data ""
:param stubs: Set of stubout stubs
@ -139,49 +138,9 @@ def stub_out_s3_backend(stubs):
yield cls.DATA[i:i + cls.CHUNK_SIZE]
return chunk_it()
fake_swift_backend = FakeS3Backend()
fake_s3_backend = FakeS3Backend()
stubs.Set(glance.store.s3.S3Backend, 'get',
fake_swift_backend.get)
def stub_out_swift_backend(stubs):
"""Stubs out the Swift Glance backend with fake data
and calls.
The stubbed swift backend provides back an iterator over
the data "I am a teapot, short and stout\n"
:param stubs: Set of stubout stubs
"""
class FakeSwiftAuth(object):
pass
class FakeSwiftConnection(object):
pass
class FakeSwiftBackend(object):
CHUNK_SIZE = 2
DATA = 'I am a teapot, short and stout\n'
@classmethod
def get(cls, parsed_uri, expected_size, conn_class=None):
SwiftBackend = glance.store.swift.SwiftBackend
# raise BackendException if URI is bad.
(user, key, authurl, container, obj) = \
SwiftBackend._parse_swift_tokens(parsed_uri)
def chunk_it():
for i in xrange(0, len(cls.DATA), cls.CHUNK_SIZE):
yield cls.DATA[i:i + cls.CHUNK_SIZE]
return chunk_it()
fake_swift_backend = FakeSwiftBackend()
stubs.Set(glance.store.swift.SwiftBackend, 'get',
fake_swift_backend.get)
fake_s3_backend.get)
def stub_out_registry_and_store_server(stubs):

View File

@ -22,7 +22,6 @@ import unittest
import urlparse
from glance.store.s3 import S3Backend
from glance.store.swift import SwiftBackend
from glance.store import Backend, BackendException, get_from_backend
from tests import stubs

View File

@ -25,19 +25,11 @@ import unittest
import urlparse
import stubout
import swift.common.client
from glance.common import exception
import glance.store.swift
SwiftBackend = glance.store.swift.SwiftBackend
SWIFT_INSTALLED = False
try:
import swift.common.client
SWIFT_INSTALLED = True
except ImportError:
print "Skipping Swift store tests since Swift is not installed."
from glance.store import BackendException
from glance.store.swift import SwiftBackend
FIVE_KB = (5 * 1024)
SWIFT_OPTIONS = {'verbose': True,
@ -123,13 +115,10 @@ def stub_out_swift_common_client(stubs):
del fixture_headers[fixture_key]
del fixture_objects[fixture_key]
def fake_get_connection_class(*args):
return swift.common.client.Connection
def fake_http_connection(self):
def fake_http_connection(*args, **kwargs):
return None
def fake_get_auth(self):
def fake_get_auth(*args, **kwargs):
return None, None
stubs.Set(swift.common.client,
@ -144,12 +133,10 @@ def stub_out_swift_common_client(stubs):
'head_object', fake_head_object)
stubs.Set(swift.common.client,
'get_object', fake_get_object)
stubs.Set(swift.common.client.Connection,
stubs.Set(swift.common.client,
'get_auth', fake_get_auth)
stubs.Set(swift.common.client.Connection,
stubs.Set(swift.common.client,
'http_connection', fake_http_connection)
stubs.Set(glance.store.swift,
'get_connection_class', fake_get_connection_class)
class TestSwiftBackend(unittest.TestCase):
@ -157,8 +144,7 @@ class TestSwiftBackend(unittest.TestCase):
def setUp(self):
"""Establish a clean test environment"""
self.stubs = stubout.StubOutForTesting()
if SWIFT_INSTALLED:
stub_out_swift_common_client(self.stubs)
stub_out_swift_common_client(self.stubs)
def tearDown(self):
"""Clear the test environment"""
@ -166,8 +152,6 @@ class TestSwiftBackend(unittest.TestCase):
def test_get(self):
"""Test a "normal" retrieval of an image in chunks"""
if not SWIFT_INSTALLED:
return
url_pieces = urlparse.urlparse(
"swift://user:key@auth_address/glance/2")
image_swift = SwiftBackend.get(url_pieces)
@ -184,11 +168,9 @@ class TestSwiftBackend(unittest.TestCase):
Test retrieval of an image with wrong expected_size param
raises an exception
"""
if not SWIFT_INSTALLED:
return
url_pieces = urlparse.urlparse(
"swift://user:key@auth_address/glance/2")
self.assertRaises(glance.store.BackendException,
self.assertRaises(BackendException,
SwiftBackend.get,
url_pieces,
{'expected_size': 42})
@ -198,8 +180,6 @@ class TestSwiftBackend(unittest.TestCase):
Test that trying to retrieve a swift that doesn't exist
raises an error
"""
if not SWIFT_INSTALLED:
return
url_pieces = urlparse.urlparse(
"swift://user:key@auth_address/noexist")
self.assertRaises(exception.NotFound,
@ -208,8 +188,6 @@ class TestSwiftBackend(unittest.TestCase):
def test_add(self):
"""Test that we can add an image via the swift backend"""
if not SWIFT_INSTALLED:
return
expected_image_id = 42
expected_swift_size = 1024 * 5 # 5K
expected_swift_contents = "*" * expected_swift_size
@ -239,8 +217,6 @@ class TestSwiftBackend(unittest.TestCase):
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'
@ -252,7 +228,7 @@ class TestSwiftBackend(unittest.TestCase):
exception_caught = False
try:
SwiftBackend.add(3, image_swift, options)
except glance.store.BackendException, e:
except BackendException, e:
exception_caught = True
self.assertTrue("container noexist does not exist "
"in Swift" in str(e))
@ -263,8 +239,6 @@ class TestSwiftBackend(unittest.TestCase):
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'
@ -297,9 +271,6 @@ class TestSwiftBackend(unittest.TestCase):
Tests that adding an image with an existing identifier
raises an appropriate exception
"""
if not SWIFT_INSTALLED:
return
image_swift = StringIO.StringIO("nevergonnamakeit")
self.assertRaises(exception.Duplicate,
SwiftBackend.add,
@ -309,8 +280,6 @@ class TestSwiftBackend(unittest.TestCase):
"""
Test we can delete an existing image in the swift store
"""
if not SWIFT_INSTALLED:
return
url_pieces = urlparse.urlparse(
"swift://user:key@auth_address/glance/2")
@ -325,8 +294,6 @@ class TestSwiftBackend(unittest.TestCase):
Test that trying to delete a swift that doesn't exist
raises an error
"""
if not SWIFT_INSTALLED:
return
url_pieces = urlparse.urlparse("swift://user:key@auth_address/noexist")
self.assertRaises(exception.NotFound,
SwiftBackend.delete,