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:
parent
a6dcd64d69
commit
ee74c26dbd
@ -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::
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user