From 053cd092b1666455907427732f455bf28132a316 Mon Sep 17 00:00:00 2001 From: Chmouel Boudjnah Date: Mon, 12 Aug 2013 13:04:40 +0200 Subject: [PATCH] Allow multiple storage_domain in cname_lookup. Implements: blueprint multiple-domains-in-domain-remap Change-Id: Ia647f6777717e9ff4955ea66b29f072ac03d2785 --- etc/proxy-server.conf-sample | 3 ++ swift/common/middleware/cname_lookup.py | 21 ++++++--- .../common/middleware/test_cname_lookup.py | 44 +++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/etc/proxy-server.conf-sample b/etc/proxy-server.conf-sample index 0de120fd6e..d56888d856 100644 --- a/etc/proxy-server.conf-sample +++ b/etc/proxy-server.conf-sample @@ -390,7 +390,10 @@ use = egg:swift#cname_lookup # set log_headers = false # set log_address = /dev/log # +# Specify the storage_domain that match your cloud, multiple domains +# can be specified separated by a comma # storage_domain = example.com +# # lookup_depth = 1 # Note: Put staticweb just after your auth filter(s) in the pipeline diff --git a/swift/common/middleware/cname_lookup.py b/swift/common/middleware/cname_lookup.py index f79d0685c8..bd3697144b 100644 --- a/swift/common/middleware/cname_lookup.py +++ b/swift/common/middleware/cname_lookup.py @@ -41,7 +41,7 @@ else: # executed if the try block finishes with no errors MODULE_DEPENDENCY_MET = True from swift.common.swob import Request, HTTPBadRequest -from swift.common.utils import cache_from_env, get_logger +from swift.common.utils import cache_from_env, get_logger, list_from_csv def lookup_cname(domain): # pragma: no cover @@ -89,13 +89,22 @@ class CNAMELookupMiddleware(object): # reraise the exception if the dependency wasn't met raise ImportError('dnspython is required for this module') self.app = app - self.storage_domain = conf.get('storage_domain', 'example.com') - if self.storage_domain and self.storage_domain[0] != '.': - self.storage_domain = '.' + self.storage_domain + storage_domain = conf.get('storage_domain', 'example.com') + self.storage_domain = ['.' + s for s in + list_from_csv(storage_domain) + if not s.startswith('.')] + self.storage_domain += [s for s in list_from_csv(storage_domain) + if s.startswith('.')] self.lookup_depth = int(conf.get('lookup_depth', '1')) self.memcache = None self.logger = get_logger(conf, log_route='cname-lookup') + def _domain_endswith_in_storage_domain(self, a_domain): + for domain in self.storage_domain: + if a_domain.endswith(domain): + return True + return False + def __call__(self, env, start_response): if not self.storage_domain: return self.app(env, start_response) @@ -111,7 +120,7 @@ class CNAMELookupMiddleware(object): if is_ip(given_domain): return self.app(env, start_response) a_domain = given_domain - if not a_domain.endswith(self.storage_domain): + if not self._domain_endswith_in_storage_domain(a_domain): if self.memcache is None: self.memcache = cache_from_env(env) error = True @@ -131,7 +140,7 @@ class CNAMELookupMiddleware(object): error = True found_domain = None break - elif found_domain.endswith(self.storage_domain): + elif self._domain_endswith_in_storage_domain(found_domain): # Found it! self.logger.info( _('Mapped %(given_domain)s to %(found_domain)s') % diff --git a/test/unit/common/middleware/test_cname_lookup.py b/test/unit/common/middleware/test_cname_lookup.py index 2ffcfbf567..ba76c5546d 100644 --- a/test/unit/common/middleware/test_cname_lookup.py +++ b/test/unit/common/middleware/test_cname_lookup.py @@ -14,6 +14,7 @@ # limitations under the License. import unittest +import mock from nose import SkipTest try: @@ -193,3 +194,46 @@ class TestCNAMELookup(unittest.TestCase): resp = app(req.environ, start_response) self.assertEquals(resp, 'FAKE APP') + + def test_storage_domains_conf_format(self): + conf = {'storage_domain': 'foo.com'} + app = cname_lookup.filter_factory(conf)(FakeApp()) + self.assertEquals(app.storage_domain, ['.foo.com']) + + conf = {'storage_domain': 'foo.com, '} + app = cname_lookup.filter_factory(conf)(FakeApp()) + self.assertEquals(app.storage_domain, ['.foo.com']) + + conf = {'storage_domain': 'foo.com, bar.com'} + app = cname_lookup.filter_factory(conf)(FakeApp()) + self.assertEquals(app.storage_domain, ['.foo.com', '.bar.com']) + + conf = {'storage_domain': 'foo.com, .bar.com'} + app = cname_lookup.filter_factory(conf)(FakeApp()) + self.assertEquals(app.storage_domain, ['.foo.com', '.bar.com']) + + conf = {'storage_domain': '.foo.com, .bar.com'} + app = cname_lookup.filter_factory(conf)(FakeApp()) + self.assertEquals(app.storage_domain, ['.foo.com', '.bar.com']) + + def test_multiple_storage_domains(self): + conf = {'storage_domain': 'storage1.com, storage2.com', + 'lookup_depth': 2} + app = cname_lookup.CNAMELookupMiddleware(FakeApp(), conf) + + def do_test(lookup_back): + req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'}, + headers={'Host': 'c.a.example.com'}) + module = 'swift.common.middleware.cname_lookup.lookup_cname' + with mock.patch(module, lambda x: (0, lookup_back)): + return app(req.environ, start_response) + + resp = do_test('c.storage1.com') + self.assertEquals(resp, 'FAKE APP') + + resp = do_test('c.storage2.com') + self.assertEquals(resp, 'FAKE APP') + + bad_domain = ['CNAME lookup failed to resolve to a valid domain'] + resp = do_test('c.badtest.com') + self.assertEquals(resp, bad_domain)