diff --git a/etc/memcache.conf-sample b/etc/memcache.conf-sample new file mode 100644 index 0000000000..580d94aa98 --- /dev/null +++ b/etc/memcache.conf-sample @@ -0,0 +1,5 @@ +[memcache] +# You can use this single conf file instead of having memcache_servers set in +# several other conf files under [filter:cache] for example. You can specify +# multiple servers separated with commas, as in: 10.1.2.3:11211,10.1.2.4:11211 +# memcache_servers = 127.0.0.1:11211 diff --git a/etc/proxy-server.conf-sample b/etc/proxy-server.conf-sample index 1b21ff071f..9110df8e0e 100644 --- a/etc/proxy-server.conf-sample +++ b/etc/proxy-server.conf-sample @@ -104,8 +104,10 @@ use = egg:swift#memcache # set log_facility = LOG_LOCAL0 # set log_level = INFO # set log_headers = False -# Default for memcache_servers is below, but you can specify multiple servers -# with the format: 10.1.2.3:11211,10.1.2.4:11211 +# Default for memcache_servers is to try to read the property from +# memcache.conf (see memcache.conf-sample) or lacking that file, it will +# default to the value below. You can specify multiple servers separated with +# commas, as in: 10.1.2.3:11211,10.1.2.4:11211 # memcache_servers = 127.0.0.1:11211 [filter:ratelimit] diff --git a/swift/common/middleware/memcache.py b/swift/common/middleware/memcache.py index e2eca36d63..ba829d1e69 100644 --- a/swift/common/middleware/memcache.py +++ b/swift/common/middleware/memcache.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os +from ConfigParser import ConfigParser, NoSectionError, NoOptionError + from swift.common.memcached import MemcacheRing @@ -23,9 +26,21 @@ class MemcacheMiddleware(object): def __init__(self, app, conf): self.app = app - self.memcache = MemcacheRing([s.strip() for s in - conf.get('memcache_servers', '127.0.0.1:11211').split(',') - if s.strip()]) + self.memcache_servers = conf.get('memcache_servers') + if not self.memcache_servers: + path = os.path.join(conf.get('swift_dir', '/etc/swift'), + 'memcache.conf') + memcache_conf = ConfigParser() + if memcache_conf.read(path): + try: + self.memcache_servers = \ + memcache_conf.get('memcache', 'memcache_servers') + except (NoSectionError, NoOptionError): + pass + if not self.memcache_servers: + self.memcache_servers = '127.0.0.1:11211' + self.memcache = MemcacheRing( + [s.strip() for s in self.memcache_servers.split(',') if s.strip()]) def __call__(self, env, start_response): env['swift.cache'] = self.memcache diff --git a/test/unit/common/middleware/test_memcache.py b/test/unit/common/middleware/test_memcache.py index baf50c6f30..4610a779bf 100644 --- a/test/unit/common/middleware/test_memcache.py +++ b/test/unit/common/middleware/test_memcache.py @@ -14,6 +14,7 @@ # limitations under the License. import unittest +from ConfigParser import NoSectionError, NoOptionError from webob import Request @@ -24,6 +25,34 @@ class FakeApp(object): def __call__(self, env, start_response): return env + +class ExcConfigParser(object): + + def read(self, path): + raise Exception('read called with %r' % path) + + +class EmptyConfigParser(object): + + def read(self, path): + return False + + +class SetConfigParser(object): + + def read(self, path): + return True + + def get(self, section, option): + if section == 'memcache': + if option == 'memcache_servers': + return '1.2.3.4:5' + else: + raise NoOptionError(option) + else: + raise NoSectionError(option) + + def start_response(*args): pass @@ -38,5 +67,60 @@ class TestCacheMiddleware(unittest.TestCase): self.assertTrue('swift.cache' in resp) self.assertTrue(isinstance(resp['swift.cache'], MemcacheRing)) + def test_conf_default_read(self): + orig_parser = memcache.ConfigParser + memcache.ConfigParser = ExcConfigParser + exc = None + try: + app = memcache.MemcacheMiddleware(FakeApp(), {}) + except Exception, err: + exc = err + finally: + memcache.ConfigParser = orig_parser + self.assertEquals(str(exc), + "read called with '/etc/swift/memcache.conf'") + + def test_conf_set_no_read(self): + orig_parser = memcache.ConfigParser + memcache.ConfigParser = ExcConfigParser + exc = None + try: + app = memcache.MemcacheMiddleware( + FakeApp(), {'memcache_servers': '1.2.3.4:5'}) + except Exception, err: + exc = err + finally: + memcache.ConfigParser = orig_parser + self.assertEquals(exc, None) + + def test_conf_default(self): + orig_parser = memcache.ConfigParser + memcache.ConfigParser = EmptyConfigParser + try: + app = memcache.MemcacheMiddleware(FakeApp(), {}) + finally: + memcache.ConfigParser = orig_parser + self.assertEquals(app.memcache_servers, '127.0.0.1:11211') + + def test_conf_from_extra_conf(self): + orig_parser = memcache.ConfigParser + memcache.ConfigParser = SetConfigParser + try: + app = memcache.MemcacheMiddleware(FakeApp(), {}) + finally: + memcache.ConfigParser = orig_parser + self.assertEquals(app.memcache_servers, '1.2.3.4:5') + + def test_conf_from_inline_conf(self): + orig_parser = memcache.ConfigParser + memcache.ConfigParser = SetConfigParser + try: + app = memcache.MemcacheMiddleware( + FakeApp(), {'memcache_servers': '6.7.8.9:10'}) + finally: + memcache.ConfigParser = orig_parser + self.assertEquals(app.memcache_servers, '6.7.8.9:10') + + if __name__ == '__main__': unittest.main()