From e677abf4ff9d2ea3bdc92e58ec81a4784df3b29e Mon Sep 17 00:00:00 2001 From: Eoghan Glynn Date: Wed, 21 Mar 2012 11:54:21 +0000 Subject: [PATCH] Specify location when creating s3 bucket. Fixes bug 961050 Avoids bucket creation failure when a region-specific S3 endpoint (e.g. s3-eu-west-1.amazonaws.com) and also bucket create-on-demand are configured. Change-Id: Ieba9c535ccb961a1f81bd2632b5ac49c23ac7901 --- glance/store/s3.py | 19 ++++++++++++++- glance/tests/unit/test_s3_store.py | 37 +++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/glance/store/s3.py b/glance/store/s3.py index 8d975df310..025906f000 100644 --- a/glance/store/s3.py +++ b/glance/store/s3.py @@ -442,6 +442,22 @@ def get_bucket(conn, bucket_id): return bucket +def get_s3_location(s3_host): + from boto.s3.connection import Location + locations = { + 's3.amazonaws.com': Location.DEFAULT, + 's3-eu-west-1.amazonaws.com': Location.EU, + 's3-us-west-1.amazonaws.com': Location.USWest, + 's3-ap-southeast-1.amazonaws.com': Location.APSoutheast, + 's3-ap-northeast-1.amazonaws.com': Location.APNortheast, + } + # strip off scheme and port if present + key = re.sub('^(https?://)?(?P[^:]+)(:[0-9]+)?$', + '\g', + s3_host) + return locations.get(key, Location.DEFAULT) + + def create_bucket_if_missing(bucket, s3_conn, conf): """ Creates a missing bucket in S3 if the @@ -457,8 +473,9 @@ def create_bucket_if_missing(bucket, s3_conn, conf): except S3ResponseError, e: if e.status == httplib.NOT_FOUND: if conf.s3_store_create_bucket_on_put: + location = get_s3_location(conf.s3_store_host) try: - s3_conn.create_bucket(bucket) + s3_conn.create_bucket(bucket, location=location) except S3ResponseError, e: msg = ("Failed to add bucket to S3.\n" "Got error from S3: %(e)s" % locals()) diff --git a/glance/tests/unit/test_s3_store.py b/glance/tests/unit/test_s3_store.py index b7da8af915..9adb3afba3 100644 --- a/glance/tests/unit/test_s3_store.py +++ b/glance/tests/unit/test_s3_store.py @@ -31,7 +31,7 @@ from glance.common import utils from glance.store import BackendException, UnsupportedBackend from glance.store.location import get_location_from_uri -from glance.store.s3 import Store +from glance.store.s3 import Store, get_s3_location from glance.tests import utils as test_utils @@ -335,3 +335,38 @@ def test_delete_non_existing(self): uri = "s3://user:key@auth_address/glance/noexist" loc = get_location_from_uri(uri) self.assertRaises(exception.NotFound, self.store.delete, loc) + + def _do_test_get_s3_location(self, host, loc): + self.assertEquals(get_s3_location(host), loc) + self.assertEquals(get_s3_location(host + ':80'), loc) + self.assertEquals(get_s3_location('http://' + host), loc) + self.assertEquals(get_s3_location('http://' + host + ':80'), loc) + self.assertEquals(get_s3_location('https://' + host), loc) + self.assertEquals(get_s3_location('https://' + host + ':80'), loc) + + def test_get_s3_good_location(self): + """ + Test that the s3 location can be derived from the host + """ + good_locations = [ + ('s3.amazonaws.com', ''), + ('s3-eu-west-1.amazonaws.com', 'EU'), + ('s3-us-west-1.amazonaws.com', 'us-west-1'), + ('s3-ap-southeast-1.amazonaws.com', 'ap-southeast-1'), + ('s3-ap-northeast-1.amazonaws.com', 'ap-northeast-1'), + ] + for (url, expected) in good_locations: + self._do_test_get_s3_location(url, expected) + + def test_get_s3_bad_location(self): + """ + Test that the s3 location cannot be derived from an unexpected host + """ + bad_locations = [ + ('', ''), + ('s3.amazon.co.uk', ''), + ('s3-govcloud.amazonaws.com', ''), + ('cloudfiles.rackspace.com', ''), + ] + for (url, expected) in bad_locations: + self._do_test_get_s3_location(url, expected)