summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app-admin/glance/files/glance-swift-authv2.patch')
-rw-r--r--app-admin/glance/files/glance-swift-authv2.patch914
1 files changed, 0 insertions, 914 deletions
diff --git a/app-admin/glance/files/glance-swift-authv2.patch b/app-admin/glance/files/glance-swift-authv2.patch
deleted file mode 100644
index 7c8f507..0000000
--- a/app-admin/glance/files/glance-swift-authv2.patch
+++ /dev/null
@@ -1,914 +0,0 @@
-diff -urN glance-2012.1.orig/Authors glance-2012.1/Authors
---- glance-2012.1.orig/Authors 2012-03-21 10:51:12.000000000 +0100
-+++ glance-2012.1/Authors 2012-03-28 17:48:31.000000000 +0200
-@@ -27,6 +27,7 @@
- Johannes Erdfelt <johannes.erdfelt@rackspace.com>
- Josh Durgin <josh.durgin@dreamhost.com>
- Josh Kearney <josh@jk0.org>
-+Juerg Haefliger <juerg.haefliger@hp.com>
- Justin Santa Barbara <justin@fathomdb.com>
- Justin Shepherd <jshepher@rackspace.com>
- Ken Pepple <ken.pepple@gmail.com>
-diff -urN glance-2012.1.orig/Authors.orig glance-2012.1/Authors.orig
---- glance-2012.1.orig/Authors.orig 1970-01-01 01:00:00.000000000 +0100
-+++ glance-2012.1/Authors.orig 2012-03-21 10:51:12.000000000 +0100
-@@ -0,0 +1,62 @@
-+Adam Gandelman <adam.gandelman@canonical.com>
-+Alex Meade <alex.meade@rackspace.com>
-+Andrew Hutchings <andrew@linuxjedi.co.uk>
-+Andrey Brindeyev <abrindeyev@griddynamics.com>
-+Brian Lamar <brian.lamar@rackspace.com>
-+Brian Waldon <brian.waldon@rackspace.com>
-+Chris Behrens <cbehrens@codestud.com>
-+Christopher MacGown <chris@pistoncloud.com>
-+Chuck Short <chuck.short@canonical.com>
-+Cory Wright <corywright@gmail.com>
-+Dan Prince <dprince@redhat.com>
-+Dean Troyer <dtroyer@gmail.com>
-+Derek Higgins <derekh@redhat.com>
-+Donal Lafferty <donal.lafferty@citrix.com>
-+Eldar Nugaev <enugaev@griddynamics.com>
-+Eoghan Glynn <eglynn@redhat.com>
-+Ewan Mellor <ewan.mellor@citrix.com>
-+Gabriel Hurley <gabriel@strikeawe.com>
-+Hengqing Hu <hudayou@hotmail.com>
-+Isaku Yamahata <yamahata@valinux.co.jp>
-+Jason Koelker <jason@koelker.net>
-+Jay Pipes <jaypipes@gmail.com>
-+James E. Blair <jeblair@hp.com>
-+Jesse Andrews <anotherjesse@gmail.com>
-+Jinwoo 'Joseph' Suh <jsuh@isi.edu>
-+Joe Gordon <jogo@cloudscaling.com>
-+Johannes Erdfelt <johannes.erdfelt@rackspace.com>
-+Josh Durgin <josh.durgin@dreamhost.com>
-+Josh Kearney <josh@jk0.org>
-+Justin Santa Barbara <justin@fathomdb.com>
-+Justin Shepherd <jshepher@rackspace.com>
-+Ken Pepple <ken.pepple@gmail.com>
-+Ken Thomas <krt@yahoo-inc.com>
-+Kevin L. Mitchell <kevin.mitchell@rackspace.com>
-+Lorin Hochstein <lorin@isi.edu>
-+Major Hayden <major@mhtx.net>
-+Mark McLoughlin <markmc@redhat.com>
-+Mark Washenberger <mark.washenberger@rackspace.com>
-+Maru Newby <mnewby@internap.com>
-+Matt Dietz <matt.dietz@rackspace.com>
-+Mike Lundy <mike@pistoncloud.com>
-+Monty Taylor <mordred@inaugust.com>
-+Pádraig Brady <P@draigBrady.com>
-+Paul Bourke <paul-david.bourke@hp.com>
-+Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
-+Peng Yong <ppyy@pubyun.com>
-+Pete Zaitcev <zaitcev@kotori.zaitcev.us>
-+Rick Clark <rick@openstack.org>
-+Rick Harris <rconradharris@gmail.com>
-+Reynolds Chin <benzwt@gmail.com>
-+Russell Bryant <rbryant@redhat.com>
-+Soren Hansen <soren.hansen@rackspace.com>
-+Stuart McLaren <stuart.mclaren@hp.com>
-+Taku Fukushima <tfukushima@dcl.info.waseda.ac.jp>
-+Thierry Carrez <thierry@openstack.org>
-+Tom Hancock <tom.hancock@hp.com>
-+Wayne A. Walls <wayne.walls@rackspace.com>
-+William Wolf <throughnothing@gmail.com>
-+Vishvananda Ishaya <vishvananda@gmail.com>
-+Yaguang Tang <heut2008@gmail.com>
-+Yuriy Taraday <yorik.sar@gmail.com>
-+Zhongyue Luo <lzyeval@gmail.com>
-diff -urN glance-2012.1.orig/etc/glance-api.conf glance-2012.1/etc/glance-api.conf
---- glance-2012.1.orig/etc/glance-api.conf 2012-03-21 10:51:12.000000000 +0100
-+++ glance-2012.1/etc/glance-api.conf 2012-03-28 17:48:31.000000000 +0200
-@@ -130,10 +130,15 @@
-
- # ============ Swift Store Options =============================
-
-+# Version of the authentication service to use
-+# Valid versions are '2' for keystone and '1' for swauth and rackspace
-+swift_store_auth_version = 2
-+
- # Address where the Swift authentication service lives
- # Valid schemes are 'http://' and 'https://'
- # If no scheme specified, default to 'https://'
--swift_store_auth_address = 127.0.0.1:8080/v1.0/
-+# For swauth, use something like '127.0.0.1:8080/v1.0/'
-+swift_store_auth_address = 127.0.0.1:35357/v2.0/
-
- # User to authenticate against the Swift authentication service
- # If you use Swift authentication service, set it to 'account':'user'
-diff -urN glance-2012.1.orig/glance/store/swift.py glance-2012.1/glance/store/swift.py
---- glance-2012.1.orig/glance/store/swift.py 2012-03-21 10:51:12.000000000 +0100
-+++ glance-2012.1/glance/store/swift.py 2012-03-28 17:50:34.000000000 +0200
-@@ -192,9 +192,10 @@
- cfg.StrOpt('swift_store_auth_address'),
- cfg.StrOpt('swift_store_user'),
- cfg.StrOpt('swift_store_key'),
-+ cfg.StrOpt('swift_store_auth_version', default='2'),
- cfg.StrOpt('swift_store_container',
- default=DEFAULT_CONTAINER),
-- cfg.IntOpt('swift_store_large_object_size',
-+ cfg.IntOpt('swift_store_large_object_size',
- default=DEFAULT_LARGE_OBJECT_SIZE),
- cfg.IntOpt('swift_store_large_object_chunk_size',
- default=DEFAULT_LARGE_OBJECT_CHUNK_SIZE),
-@@ -204,6 +205,7 @@
- def configure(self):
- self.conf.register_opts(self.opts)
- self.snet = self.conf.swift_enable_snet
-+ self.auth_version = self._option_get('swift_store_auth_version')
-
- def configure_add(self):
- """
-@@ -300,11 +302,14 @@
- Creates a connection using the Swift client library.
- """
- snet = self.snet
-+ auth_version = self.auth_version
- logger.debug(_("Creating Swift connection with "
- "(auth_address=%(auth_url)s, user=%(user)s, "
-- "snet=%(snet)s)") % locals())
-+ "snet=%(snet)s, auth_version=%(auth_version)s)") %
-+ locals())
- return swift_client.Connection(
-- authurl=auth_url, user=user, key=key, snet=snet)
-+ authurl=auth_url, user=user, key=key, snet=snet,
-+ auth_version=auth_version)
-
- def _option_get(self, param):
- result = getattr(self.conf, param)
-diff -urN glance-2012.1.orig/glance/store/swift.py.orig glance-2012.1/glance/store/swift.py.orig
---- glance-2012.1.orig/glance/store/swift.py.orig 1970-01-01 01:00:00.000000000 +0100
-+++ glance-2012.1/glance/store/swift.py.orig 2012-03-21 10:51:12.000000000 +0100
-@@ -0,0 +1,560 @@
-+# vim: tabstop=4 shiftwidth=4 softtabstop=4
-+
-+# Copyright 2010-2011 OpenStack, LLC
-+# All Rights Reserved.
-+#
-+# Licensed under the Apache License, Version 2.0 (the "License"); you may
-+# not use this file except in compliance with the License. You may obtain
-+# a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing, software
-+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-+# License for the specific language governing permissions and limitations
-+# under the License.
-+
-+"""Storage backend for SWIFT"""
-+
-+from __future__ import absolute_import
-+
-+import hashlib
-+import httplib
-+import logging
-+import math
-+import urlparse
-+
-+from glance.common import cfg
-+from glance.common import exception
-+import glance.store
-+import glance.store.base
-+import glance.store.location
-+
-+try:
-+ from swift.common import client as swift_client
-+except ImportError:
-+ pass
-+
-+DEFAULT_CONTAINER = 'glance'
-+DEFAULT_LARGE_OBJECT_SIZE = 5 * 1024 # 5GB
-+DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 # 200M
-+ONE_MB = 1000 * 1024
-+
-+logger = logging.getLogger('glance.store.swift')
-+
-+
-+class StoreLocation(glance.store.location.StoreLocation):
-+
-+ """
-+ Class describing a Swift URI. A Swift URI can look like any of
-+ the following:
-+
-+ swift://user:pass@authurl.com/container/obj-id
-+ swift://account:user:pass@authurl.com/container/obj-id
-+ swift+http://user:pass@authurl.com/container/obj-id
-+ swift+https://user:pass@authurl.com/container/obj-id
-+
-+ The swift+http:// URIs indicate there is an HTTP authentication URL.
-+ The default for Swift is an HTTPS authentication URL, so swift:// and
-+ swift+https:// are the same...
-+ """
-+
-+ def process_specs(self):
-+ self.scheme = self.specs.get('scheme', 'swift+https')
-+ self.user = self.specs.get('user')
-+ self.key = self.specs.get('key')
-+ self.authurl = self.specs.get('authurl')
-+ self.container = self.specs.get('container')
-+ self.obj = self.specs.get('obj')
-+
-+ def _get_credstring(self):
-+ if self.user:
-+ return '%s:%s@' % (self.user, self.key)
-+ return ''
-+
-+ def get_uri(self):
-+ authurl = self.authurl
-+ if authurl.startswith('http://'):
-+ authurl = authurl[7:]
-+ elif authurl.startswith('https://'):
-+ authurl = authurl[8:]
-+
-+ credstring = self._get_credstring()
-+ authurl = authurl.strip('/')
-+ container = self.container.strip('/')
-+ obj = self.obj.strip('/')
-+
-+ return '%s://%s%s/%s/%s' % (self.scheme, credstring, authurl,
-+ container, obj)
-+
-+ def parse_uri(self, uri):
-+ """
-+ Parse URLs. This method fixes an issue where credentials specified
-+ in the URL are interpreted differently in Python 2.6.1+ than prior
-+ versions of Python. It also deals with the peculiarity that new-style
-+ Swift URIs have where a username can contain a ':', like so:
-+
-+ swift://account:user:pass@authurl.com/container/obj
-+ """
-+ # Make sure that URIs that contain multiple schemes, such as:
-+ # swift://user:pass@http://authurl.com/v1/container/obj
-+ # are immediately rejected.
-+ if uri.count('://') != 1:
-+ reason = _(
-+ "URI cannot contain more than one occurrence of a scheme."
-+ "If you have specified a URI like "
-+ "swift://user:pass@http://authurl.com/v1/container/obj"
-+ ", you need to change it to use the swift+http:// scheme, "
-+ "like so: "
-+ "swift+http://user:pass@authurl.com/v1/container/obj"
-+ )
-+ raise exception.BadStoreUri(uri, reason)
-+
-+ pieces = urlparse.urlparse(uri)
-+ assert pieces.scheme in ('swift', 'swift+http', 'swift+https')
-+ self.scheme = pieces.scheme
-+ netloc = pieces.netloc
-+ path = pieces.path.lstrip('/')
-+ if netloc != '':
-+ # > Python 2.6.1
-+ if '@' in netloc:
-+ creds, netloc = netloc.split('@')
-+ else:
-+ creds = None
-+ else:
-+ # Python 2.6.1 compat
-+ # see lp659445 and Python issue7904
-+ if '@' in path:
-+ creds, path = path.split('@')
-+ else:
-+ creds = None
-+ netloc = path[0:path.find('/')].strip('/')
-+ path = path[path.find('/'):].strip('/')
-+ if creds:
-+ cred_parts = creds.split(':')
-+
-+ # User can be account:user, in which case cred_parts[0:2] will be
-+ # the account and user. Combine them into a single username of
-+ # account:user
-+ if len(cred_parts) == 1:
-+ reason = (_("Badly formed credentials '%(creds)s' in Swift "
-+ "URI") % locals())
-+ raise exception.BadStoreUri(uri, reason)
-+ elif len(cred_parts) == 3:
-+ user = ':'.join(cred_parts[0:2])
-+ else:
-+ user = cred_parts[0]
-+ key = cred_parts[-1]
-+ self.user = user
-+ self.key = key
-+ else:
-+ self.user = None
-+ path_parts = path.split('/')
-+ try:
-+ self.obj = path_parts.pop()
-+ self.container = path_parts.pop()
-+ if not netloc.startswith('http'):
-+ # push hostname back into the remaining to build full authurl
-+ path_parts.insert(0, netloc)
-+ self.authurl = '/'.join(path_parts)
-+ except IndexError:
-+ reason = _("Badly formed Swift URI")
-+ raise exception.BadStoreUri(uri, reason)
-+
-+ @property
-+ def swift_auth_url(self):
-+ """
-+ Creates a fully-qualified auth url that the Swift client library can
-+ use. The scheme for the auth_url is determined using the scheme
-+ included in the `location` field.
-+
-+ HTTPS is assumed, unless 'swift+http' is specified.
-+ """
-+ if self.scheme in ('swift+https', 'swift'):
-+ auth_scheme = 'https://'
-+ else:
-+ auth_scheme = 'http://'
-+
-+ full_url = ''.join([auth_scheme, self.authurl])
-+ return full_url
-+
-+
-+class Store(glance.store.base.Store):
-+ """An implementation of the swift backend adapter."""
-+
-+ EXAMPLE_URL = "swift://<USER>:<KEY>@<AUTH_ADDRESS>/<CONTAINER>/<FILE>"
-+
-+ CHUNKSIZE = 65536
-+
-+ opts = [
-+ cfg.BoolOpt('swift_enable_snet', default=False),
-+ cfg.StrOpt('swift_store_auth_address'),
-+ cfg.StrOpt('swift_store_user'),
-+ cfg.StrOpt('swift_store_key'),
-+ cfg.StrOpt('swift_store_container',
-+ default=DEFAULT_CONTAINER),
-+ cfg.IntOpt('swift_store_large_object_size',
-+ default=DEFAULT_LARGE_OBJECT_SIZE),
-+ cfg.IntOpt('swift_store_large_object_chunk_size',
-+ default=DEFAULT_LARGE_OBJECT_CHUNK_SIZE),
-+ cfg.BoolOpt('swift_store_create_container_on_put', default=False),
-+ ]
-+
-+ def configure(self):
-+ self.conf.register_opts(self.opts)
-+ self.snet = self.conf.swift_enable_snet
-+
-+ def configure_add(self):
-+ """
-+ Configure the Store to use the stored configuration options
-+ Any store that needs special configuration should implement
-+ this method. If the store was not able to successfully configure
-+ itself, it should raise `exception.BadStoreConfiguration`
-+ """
-+ self.auth_address = self._option_get('swift_store_auth_address')
-+ self.user = self._option_get('swift_store_user')
-+ self.key = self._option_get('swift_store_key')
-+ self.container = self.conf.swift_store_container
-+ try:
-+ # The config file has swift_store_large_object_*size in MB, but
-+ # internally we store it in bytes, since the image_size parameter
-+ # passed to add() is also in bytes.
-+ self.large_object_size = \
-+ self.conf.swift_store_large_object_size * ONE_MB
-+ self.large_object_chunk_size = \
-+ self.conf.swift_store_large_object_chunk_size * ONE_MB
-+ except cfg.ConfigFileValueError, e:
-+ reason = _("Error in configuration conf: %s") % e
-+ logger.error(reason)
-+ raise exception.BadStoreConfiguration(store_name="swift",
-+ reason=reason)
-+
-+ self.scheme = 'swift+https'
-+ if self.auth_address.startswith('http://'):
-+ self.scheme = 'swift+http'
-+ self.full_auth_address = self.auth_address
-+ elif self.auth_address.startswith('https://'):
-+ self.full_auth_address = self.auth_address
-+ else: # Defaults https
-+ self.full_auth_address = 'https://' + self.auth_address
-+
-+ def get(self, location):
-+ """
-+ Takes a `glance.store.location.Location` object that indicates
-+ where to find the image file, and returns a tuple of generator
-+ (for reading the image file) and image_size
-+
-+ :param location `glance.store.location.Location` object, supplied
-+ from glance.store.location.get_location_from_uri()
-+ :raises `glance.exception.NotFound` if image does not exist
-+ """
-+ loc = location.store_location
-+ swift_conn = self._make_swift_connection(
-+ auth_url=loc.swift_auth_url, user=loc.user, key=loc.key)
-+
-+ try:
-+ (resp_headers, resp_body) = swift_conn.get_object(
-+ container=loc.container, obj=loc.obj,
-+ resp_chunk_size=self.CHUNKSIZE)
-+ except swift_client.ClientException, e:
-+ if e.http_status == httplib.NOT_FOUND:
-+ uri = location.get_store_uri()
-+ raise exception.NotFound(_("Swift could not find image at "
-+ "uri %(uri)s") % locals())
-+ else:
-+ raise
-+
-+ class ResponseIndexable(glance.store.Indexable):
-+ def another(self):
-+ try:
-+ return self.wrapped.next()
-+ except StopIteration:
-+ return ''
-+
-+ length = resp_headers.get('content-length')
-+ return (ResponseIndexable(resp_body, length), length)
-+
-+ def get_size(self, location):
-+ """
-+ Takes a `glance.store.location.Location` object that indicates
-+ where to find the image file, and returns the image_size (or 0
-+ if unavailable)
-+
-+ :param location `glance.store.location.Location` object, supplied
-+ from glance.store.location.get_location_from_uri()
-+ """
-+ loc = location.store_location
-+ swift_conn = self._make_swift_connection(
-+ auth_url=loc.swift_auth_url, user=loc.user, key=loc.key)
-+
-+ try:
-+ resp_headers = swift_conn.head_object(container=loc.container,
-+ obj=loc.obj)
-+ return resp_headers.get('content-length', 0)
-+ except Exception:
-+ return 0
-+
-+ def _make_swift_connection(self, auth_url, user, key):
-+ """
-+ Creates a connection using the Swift client library.
-+ """
-+ snet = self.snet
-+ logger.debug(_("Creating Swift connection with "
-+ "(auth_address=%(auth_url)s, user=%(user)s, "
-+ "snet=%(snet)s)") % locals())
-+ return swift_client.Connection(
-+ authurl=auth_url, user=user, key=key, snet=snet)
-+
-+ def _option_get(self, param):
-+ result = getattr(self.conf, param)
-+ if not result:
-+ reason = (_("Could not find %(param)s in configuration "
-+ "options.") % locals())
-+ logger.error(reason)
-+ raise exception.BadStoreConfiguration(store_name="swift",
-+ reason=reason)
-+ return result
-+
-+ def add(self, image_id, image_file, image_size):
-+ """
-+ Stores an image file with supplied identifier to the backend
-+ storage system and returns an `glance.store.ImageAddResult` object
-+ containing information about the stored image.
-+
-+ :param image_id: The opaque image identifier
-+ :param image_file: The image data to write, as a file-like object
-+ :param image_size: The size of the image data to write, in bytes
-+
-+ :retval `glance.store.ImageAddResult` object
-+ :raises `glance.common.exception.Duplicate` if the image already
-+ existed
-+
-+ Swift writes the image data using the scheme:
-+ ``swift://<USER>:<KEY>@<AUTH_ADDRESS>/<CONTAINER>/<ID>`
-+ where:
-+ <USER> = ``swift_store_user``
-+ <KEY> = ``swift_store_key``
-+ <AUTH_ADDRESS> = ``swift_store_auth_address``
-+ <CONTAINER> = ``swift_store_container``
-+ <ID> = The id of the image being added
-+
-+ :note Swift auth URLs by default use HTTPS. To specify an HTTP
-+ auth URL, you can specify http://someurl.com for the
-+ swift_store_auth_address config option
-+
-+ :note Swift cannot natively/transparently handle objects >5GB
-+ in size. So, if the image is greater than 5GB, we write
-+ chunks of image data to Swift and then write an manifest
-+ to Swift that contains information about the chunks.
-+ This same chunking process is used by default for images
-+ of an unknown size, as pushing them directly to swift would
-+ fail if the image turns out to be greater than 5GB.
-+ """
-+ swift_conn = self._make_swift_connection(
-+ auth_url=self.full_auth_address, user=self.user, key=self.key)
-+
-+ create_container_if_missing(self.container, swift_conn, self.conf)
-+
-+ obj_name = str(image_id)
-+ location = StoreLocation({'scheme': self.scheme,
-+ 'container': self.container,
-+ 'obj': obj_name,
-+ 'authurl': self.auth_address,
-+ 'user': self.user,
-+ 'key': self.key})
-+
-+ logger.debug(_("Adding image object '%(obj_name)s' "
-+ "to Swift") % locals())
-+ try:
-+ if image_size > 0 and image_size < self.large_object_size:
-+ # Image size is known, and is less than large_object_size.
-+ # Send to Swift with regular PUT.
-+ obj_etag = swift_conn.put_object(self.container, obj_name,
-+ image_file,
-+ content_length=image_size)
-+ else:
-+ # Write the image into Swift in chunks.
-+ chunk_id = 1
-+ if image_size > 0:
-+ total_chunks = str(int(
-+ math.ceil(float(image_size) /
-+ float(self.large_object_chunk_size))))
-+ else:
-+ # image_size == 0 is when we don't know the size
-+ # of the image. This can occur with older clients
-+ # that don't inspect the payload size.
-+ logger.debug(_("Cannot determine image size. Adding as a "
-+ "segmented object to Swift."))
-+ total_chunks = '?'
-+
-+ checksum = hashlib.md5()
-+ combined_chunks_size = 0
-+ while True:
-+ chunk_size = self.large_object_chunk_size
-+ if image_size == 0:
-+ content_length = None
-+ else:
-+ left = image_size - combined_chunks_size
-+ if left == 0:
-+ break
-+ if chunk_size > left:
-+ chunk_size = left
-+ content_length = chunk_size
-+
-+ chunk_name = "%s-%05d" % (obj_name, chunk_id)
-+ reader = ChunkReader(image_file, checksum, chunk_size)
-+ chunk_etag = swift_conn.put_object(
-+ self.container, chunk_name, reader,
-+ content_length=content_length)
-+ bytes_read = reader.bytes_read
-+ logger.debug(_("Wrote chunk %(chunk_id)d/"
-+ "%(total_chunks)s of length %(bytes_read)d "
-+ "to Swift returning MD5 of content: "
-+ "%(chunk_etag)s")
-+ % locals())
-+
-+ if bytes_read == 0:
-+ # Delete the last chunk, because it's of zero size.
-+ # This will happen if image_size == 0.
-+ logger.debug(_("Deleting final zero-length chunk"))
-+ swift_conn.delete_object(self.container, chunk_name)
-+ break
-+
-+ chunk_id += 1
-+ combined_chunks_size += bytes_read
-+
-+ # In the case we have been given an unknown image size,
-+ # set the image_size to the total size of the combined chunks.
-+ if image_size == 0:
-+ image_size = combined_chunks_size
-+
-+ # Now we write the object manifest and return the
-+ # manifest's etag...
-+ manifest = "%s/%s" % (self.container, obj_name)
-+ headers = {'ETag': hashlib.md5("").hexdigest(),
-+ 'X-Object-Manifest': manifest}
-+
-+ # The ETag returned for the manifest is actually the
-+ # MD5 hash of the concatenated checksums of the strings
-+ # of each chunk...so we ignore this result in favour of
-+ # the MD5 of the entire image file contents, so that
-+ # users can verify the image file contents accordingly
-+ swift_conn.put_object(self.container, obj_name,
-+ None, headers=headers)
-+ obj_etag = checksum.hexdigest()
-+
-+ # NOTE: We return the user and key here! Have to because
-+ # location is used by the API server to return the actual
-+ # image data. We *really* should consider NOT returning
-+ # the location attribute from GET /images/<ID> and
-+ # GET /images/details
-+
-+ return (location.get_uri(), image_size, obj_etag)
-+ except swift_client.ClientException, e:
-+ if e.http_status == httplib.CONFLICT:
-+ raise exception.Duplicate(_("Swift already has an image at "
-+ "location %s") % location.get_uri())
-+ msg = (_("Failed to add object to Swift.\n"
-+ "Got error from Swift: %(e)s") % locals())
-+ logger.error(msg)
-+ raise glance.store.BackendException(msg)
-+
-+ def delete(self, location):
-+ """
-+ Takes a `glance.store.location.Location` object that indicates
-+ where to find the image file to delete
-+
-+ :location `glance.store.location.Location` object, supplied
-+ from glance.store.location.get_location_from_uri()
-+
-+ :raises NotFound if image does not exist
-+ """
-+ loc = location.store_location
-+ swift_conn = self._make_swift_connection(
-+ auth_url=loc.swift_auth_url, user=loc.user, key=loc.key)
-+
-+ try:
-+ # We request the manifest for the object. If one exists,
-+ # that means the object was uploaded in chunks/segments,
-+ # and we need to delete all the chunks as well as the
-+ # manifest.
-+ manifest = None
-+ try:
-+ headers = swift_conn.head_object(loc.container, loc.obj)
-+ manifest = headers.get('x-object-manifest')
-+ except swift_client.ClientException, e:
-+ if e.http_status != httplib.NOT_FOUND:
-+ raise
-+ if manifest:
-+ # Delete all the chunks before the object manifest itself
-+ obj_container, obj_prefix = manifest.split('/', 1)
-+ for segment in swift_conn.get_container(obj_container,
-+ prefix=obj_prefix)[1]:
-+ # TODO(jaypipes): This would be an easy area to parallelize
-+ # since we're simply sending off parallelizable requests
-+ # to Swift to delete stuff. It's not like we're going to
-+ # be hogging up network or file I/O here...
-+ swift_conn.delete_object(obj_container, segment['name'])
-+
-+ else:
-+ swift_conn.delete_object(loc.container, loc.obj)
-+
-+ except swift_client.ClientException, e:
-+ if e.http_status == httplib.NOT_FOUND:
-+ uri = location.get_store_uri()
-+ raise exception.NotFound(_("Swift could not find image at "
-+ "uri %(uri)s") % locals())
-+ else:
-+ raise
-+
-+
-+class ChunkReader(object):
-+ def __init__(self, fd, checksum, total):
-+ self.fd = fd
-+ self.checksum = checksum
-+ self.total = total
-+ self.bytes_read = 0
-+
-+ def read(self, i):
-+ left = self.total - self.bytes_read
-+ if i > left:
-+ i = left
-+ result = self.fd.read(i)
-+ self.bytes_read += len(result)
-+ self.checksum.update(result)
-+ return result
-+
-+
-+def create_container_if_missing(container, swift_conn, conf):
-+ """
-+ 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 conf: Option mapping
-+ """
-+ try:
-+ swift_conn.head_container(container)
-+ except swift_client.ClientException, e:
-+ if e.http_status == httplib.NOT_FOUND:
-+ if conf.swift_store_create_container_on_put:
-+ try:
-+ swift_conn.put_container(container)
-+ except swift_client.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)
-+ else:
-+ raise
-+
-+
-+glance.store.register_store(__name__, ['swift', 'swift+http', 'swift+https'])
-diff -urN glance-2012.1.orig/glance/store/swift.py.rej glance-2012.1/glance/store/swift.py.rej
---- glance-2012.1.orig/glance/store/swift.py.rej 1970-01-01 01:00:00.000000000 +0100
-+++ glance-2012.1/glance/store/swift.py.rej 2012-03-28 17:48:31.000000000 +0200
-@@ -0,0 +1,16 @@
-+***************
-+*** 192,197 ****
-+ cfg.StrOpt('swift_store_auth_address'),
-+ cfg.StrOpt('swift_store_user', secret=True),
-+ cfg.StrOpt('swift_store_key', secret=True),
-+ cfg.StrOpt('swift_store_container',
-+ default=DEFAULT_CONTAINER),
-+ cfg.IntOpt('swift_store_large_object_size',
-+--- 192,198 ----
-+ cfg.StrOpt('swift_store_auth_address'),
-+ cfg.StrOpt('swift_store_user', secret=True),
-+ cfg.StrOpt('swift_store_key', secret=True),
-++ cfg.StrOpt('swift_store_auth_version', default='2'),
-+ cfg.StrOpt('swift_store_container',
-+ default=DEFAULT_CONTAINER),
-+ cfg.IntOpt('swift_store_large_object_size',
-diff -urN glance-2012.1.orig/glance/tests/unit/test_swift_store.py glance-2012.1/glance/tests/unit/test_swift_store.py
---- glance-2012.1.orig/glance/tests/unit/test_swift_store.py 2012-03-21 10:51:12.000000000 +0100
-+++ glance-2012.1/glance/tests/unit/test_swift_store.py 2012-03-28 17:48:31.000000000 +0200
-@@ -52,7 +52,7 @@
- # We stub out as little as possible to ensure that the code paths
- # between glance.store.swift and swift.common.client are tested
- # thoroughly
--def stub_out_swift_common_client(stubs):
-+def stub_out_swift_common_client(stubs, conf):
-
- fixture_containers = ['glance']
- fixture_headers = {'glance/%s' % FAKE_UUID:
-@@ -158,9 +158,13 @@
- def fake_http_connection(*args, **kwargs):
- return None
-
-- def fake_get_auth(url, *args, **kwargs):
-+ def fake_get_auth(url, user, key, snet, auth_version, **kwargs):
- if 'http' in url and '://' not in url:
- raise ValueError('Invalid url %s' % url)
-+ # Check the auth version against the configured value
-+ if conf['swift_store_auth_version'] != auth_version:
-+ msg = 'AUTHENTICATION failed (version mismatch)'
-+ raise swift.common.client.ClientException(msg)
- return None, None
-
- stubs.Set(swift.common.client,
-@@ -181,17 +185,16 @@
- 'http_connection', fake_http_connection)
-
-
--class TestStore(unittest.TestCase):
-+class SwiftTests(object):
-
-- def setUp(self):
-- """Establish a clean test environment"""
-- self.stubs = stubout.StubOutForTesting()
-- stub_out_swift_common_client(self.stubs)
-- self.store = Store(test_utils.TestConfigOpts(SWIFT_CONF))
--
-- def tearDown(self):
-- """Clear the test environment"""
-- self.stubs.UnsetAll()
-+ def test_get_size(self):
-+ """
-+ Test that we can get the size of an object in the swift store
-+ """
-+ uri = "swift://user:key@auth_address/glance/%s" % FAKE_UUID
-+ loc = get_location_from_uri(uri)
-+ image_size = self.store.get_size(loc)
-+ self.assertEqual(image_size, 5120)
-
- def test_get(self):
- """Test a "normal" retrieval of an image in chunks"""
-@@ -298,15 +301,14 @@
- expected_swift_contents = "*" * expected_swift_size
- expected_checksum = \
- hashlib.md5(expected_swift_contents).hexdigest()
-- new_conf = SWIFT_CONF.copy()
-- new_conf['swift_store_auth_address'] = variation
-+ self.conf['swift_store_auth_address'] = variation
-
- image_swift = StringIO.StringIO(expected_swift_contents)
-
- global SWIFT_PUT_OBJECT_CALLS
- SWIFT_PUT_OBJECT_CALLS = 0
-
-- self.store = Store(test_utils.TestConfigOpts(new_conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
- location, size, checksum = self.store.add(image_id, image_swift,
- expected_swift_size)
-
-@@ -328,11 +330,10 @@
- Tests that adding an image with a non-existing container
- raises an appropriate exception
- """
-- conf = SWIFT_CONF.copy()
-- conf['swift_store_create_container_on_put'] = 'False'
-- conf['swift_store_container'] = 'noexist'
-+ self.conf['swift_store_create_container_on_put'] = 'False'
-+ self.conf['swift_store_container'] = 'noexist'
- image_swift = StringIO.StringIO("nevergonnamakeit")
-- self.store = Store(test_utils.TestConfigOpts(conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
-
- global SWIFT_PUT_OBJECT_CALLS
- SWIFT_PUT_OBJECT_CALLS = 0
-@@ -355,9 +356,8 @@
- Tests that adding an image with a non-existing container
- creates the container automatically if flag is set
- """
-- conf = SWIFT_CONF.copy()
-- conf['swift_store_create_container_on_put'] = 'True'
-- conf['swift_store_container'] = 'noexist'
-+ self.conf['swift_store_create_container_on_put'] = 'True'
-+ self.conf['swift_store_container'] = 'noexist'
- expected_swift_size = FIVE_KB
- expected_swift_contents = "*" * expected_swift_size
- expected_checksum = hashlib.md5(expected_swift_contents).hexdigest()
-@@ -369,7 +369,7 @@
- global SWIFT_PUT_OBJECT_CALLS
- SWIFT_PUT_OBJECT_CALLS = 0
-
-- self.store = Store(test_utils.TestConfigOpts(conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
- location, size, checksum = self.store.add(expected_image_id,
- image_swift,
- expected_swift_size)
-@@ -394,8 +394,7 @@
- and then verify that there have been a number of calls to
- put_object()...
- """
-- conf = SWIFT_CONF.copy()
-- conf['swift_store_container'] = 'glance'
-+ self.conf['swift_store_container'] = 'glance'
- expected_swift_size = FIVE_KB
- expected_swift_contents = "*" * expected_swift_size
- expected_checksum = hashlib.md5(expected_swift_contents).hexdigest()
-@@ -407,7 +406,7 @@
- global SWIFT_PUT_OBJECT_CALLS
- SWIFT_PUT_OBJECT_CALLS = 0
-
-- self.store = Store(test_utils.TestConfigOpts(conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
- orig_max_size = self.store.large_object_size
- orig_temp_size = self.store.large_object_chunk_size
- try:
-@@ -446,8 +445,7 @@
-
- Bug lp:891738
- """
-- conf = SWIFT_CONF.copy()
-- conf['swift_store_container'] = 'glance'
-+ self.conf['swift_store_container'] = 'glance'
-
- # Set up a 'large' image of 5KB
- expected_swift_size = FIVE_KB
-@@ -463,7 +461,7 @@
-
- # Temporarily set Swift MAX_SWIFT_OBJECT_SIZE to 1KB and add our image,
- # explicitly setting the image_length to 0
-- self.store = Store(test_utils.TestConfigOpts(conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
- orig_max_size = self.store.large_object_size
- orig_temp_size = self.store.large_object_chunk_size
- global MAX_SWIFT_OBJECT_SIZE
-@@ -507,11 +505,10 @@
- FAKE_UUID, image_swift, 0)
-
- def _option_required(self, key):
-- conf = SWIFT_CONF.copy()
-- del conf[key]
-+ del self.conf[key]
-
- try:
-- self.store = Store(test_utils.TestConfigOpts(conf))
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
- return self.store.add == self.store.add_disabled
- except:
- return False
-@@ -554,6 +551,32 @@
- self.assertRaises(exception.NotFound, self.store.delete, loc)
-
-
-+class TestStoreAuthV1(unittest.TestCase, SwiftTests):
-+
-+ def setUp(self):
-+ """Establish a clean test environment"""
-+ self.conf = SWIFT_CONF.copy()
-+ self.conf['swift_store_auth_version'] = '1'
-+ self.stubs = stubout.StubOutForTesting()
-+ stub_out_swift_common_client(self.stubs, self.conf)
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
-+
-+ def tearDown(self):
-+ """Clear the test environment"""
-+ self.stubs.UnsetAll()
-+
-+
-+class TestStoreAuthV2(TestStoreAuthV1):
-+
-+ def setUp(self):
-+ """Establish a clean test environment"""
-+ self.conf = SWIFT_CONF.copy()
-+ self.conf['swift_store_auth_version'] = '2'
-+ self.stubs = stubout.StubOutForTesting()
-+ stub_out_swift_common_client(self.stubs, self.conf)
-+ self.store = Store(test_utils.TestConfigOpts(self.conf))
-+
-+
- class TestChunkReader(unittest.TestCase):
-
- def test_read_all_data(self):