summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortermie <github@anarkystic.com>2011-03-24 16:37:35 -0700
committertermie <github@anarkystic.com>2011-03-24 16:37:35 -0700
commitd7835f81c46d880d5ba8e67cdcdc9d0bc977f86e (patch)
tree78a292baeb302da9afd11ef57b29578702422ab1
parent47592e504cca5c4b36868412720ca1ff443de4d8 (diff)
downloadnova-d7835f81c46d880d5ba8e67cdcdc9d0bc977f86e.tar.gz
nova-d7835f81c46d880d5ba8e67cdcdc9d0bc977f86e.tar.xz
nova-d7835f81c46d880d5ba8e67cdcdc9d0bc977f86e.zip
port s3server to eventlet/wsgi
-rwxr-xr-xbin/nova-objectstore15
-rw-r--r--nova/objectstore/s3server.py105
2 files changed, 81 insertions, 39 deletions
diff --git a/bin/nova-objectstore b/bin/nova-objectstore
index 94ef2a8d5..6ef841b85 100755
--- a/bin/nova-objectstore
+++ b/bin/nova-objectstore
@@ -36,9 +36,10 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
gettext.install('nova', unicode=1)
from nova import flags
+from nova import log as logging
from nova import utils
-from nova import twistd
-from nova.objectstore import handler
+from nova import wsgi
+from nova.objectstore import s3server
FLAGS = flags.FLAGS
@@ -46,7 +47,9 @@ FLAGS = flags.FLAGS
if __name__ == '__main__':
utils.default_flagfile()
- twistd.serve(__file__)
-
-if __name__ == '__builtin__':
- application = handler.get_application() # pylint: disable=C0103
+ FLAGS(sys.argv)
+ logging.setup()
+ router = s3server.S3Application(FLAGS.buckets_path)
+ server = wsgi.Server()
+ server.start(router, FLAGS.s3_port, host=FLAGS.s3_host)
+ server.wait()
diff --git a/nova/objectstore/s3server.py b/nova/objectstore/s3server.py
index b739c6c3b..7a7317af2 100644
--- a/nova/objectstore/s3server.py
+++ b/nova/objectstore/s3server.py
@@ -1,5 +1,8 @@
-#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2010 OpenStack LLC.
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -38,56 +41,92 @@ import os
import os.path
import urllib
-from tornado import escape
-from tornado import httpserver
-from tornado import ioloop
-from tornado import web
+import routes
+import webob
-def start(port, root_directory="/tmp/s3", bucket_depth=0):
- """Starts the mock S3 server on the given port at the given path."""
- application = S3Application(root_directory, bucket_depth)
- http_server = httpserver.HTTPServer(application)
- http_server.listen(port)
- ioloop.IOLoop.instance().start()
+from nova import flags
+from nova import log as logging
+from nova import utils
+from nova import wsgi
-class S3Application(web.Application):
+FLAGS = flags.FLAGS
+flags.DEFINE_string('buckets_path', '$state_path/buckets',
+ 'path to s3 buckets')
+
+
+class S3Application(wsgi.Router):
"""Implementation of an S3-like storage server based on local files.
If bucket depth is given, we break files up into multiple directories
to prevent hitting file system limits for number of files in each
directories. 1 means one level of directories, 2 means 2, etc.
+
"""
- def __init__(self, root_directory, bucket_depth=0):
- web.Application.__init__(self, [
- (r"/", RootHandler),
- (r"/([^/]+)/(.+)", ObjectHandler),
- (r"/([^/]+)/", BucketHandler),
- ])
+
+ def __init__(self, root_directory, bucket_depth=0, mapper=None):
+ if mapper is None:
+ mapper = routes.Mapper()
+
+ mapper.connect('/', controller=RootHandler(self))
+ #controller=lambda *a, **kw: RootHandler(self)(*a, **kw))
+ mapper.connect('/{bucket_name}/{object_name}',
+ controller=lambda *a, **kw: ObjectHandler(self)(*a, **kw))
+ mapper.connect('/{bucket_name}/',
+ controller=lambda *a, **kw: BucketHandler(self)(*a, **kw))
self.directory = os.path.abspath(root_directory)
if not os.path.exists(self.directory):
os.makedirs(self.directory)
self.bucket_depth = bucket_depth
+ super(S3Application, self).__init__(mapper)
+
+
+class BaseRequestHandler(wsgi.Controller):
+ def __init__(self, application):
+ self.application = application
+
+ @webob.dec.wsgify
+ def __call__(self, request):
+ logging.debug('GOT HERE')
+ method = request.method.lower()
+ f = getattr(self, method, self.invalid)
+ self.request = request
+ self.response = webob.Response()
+ params = request.environ['wsgiorg.routing_args'][1]
+ del params['controller']
+ f(**params)
+ return self.response
+
+ def get_argument(self, arg, default):
+ return self.request.str_params.get(arg, default)
+
+ def set_header(self, header, value):
+ self.response.headers[header] = value
+
+ def set_status(self, status_code):
+ self.response.status = status_code
+ def finish(self, body=''):
+ self.response.body = utils.utf8(body)
-class BaseRequestHandler(web.RequestHandler):
- SUPPORTED_METHODS = ("PUT", "GET", "DELETE")
+ def invalid(self, request, **kwargs):
+ pass
def render_xml(self, value):
assert isinstance(value, dict) and len(value) == 1
self.set_header("Content-Type", "application/xml; charset=UTF-8")
name = value.keys()[0]
parts = []
- parts.append('<' + escape.utf8(name) +
+ parts.append('<' + utils.utf8(name) +
' xmlns="http://doc.s3.amazonaws.com/2006-03-01">')
self._render_parts(value.values()[0], parts)
- parts.append('</' + escape.utf8(name) + '>')
+ parts.append('</' + utils.utf8(name) + '>')
self.finish('<?xml version="1.0" encoding="UTF-8"?>\n' +
''.join(parts))
def _render_parts(self, value, parts=[]):
if isinstance(value, basestring):
- parts.append(escape.xhtml_escape(value))
+ parts.append(utils.xhtml_escape(value))
elif isinstance(value, int) or isinstance(value, long):
parts.append(str(value))
elif isinstance(value, datetime.datetime):
@@ -97,9 +136,9 @@ class BaseRequestHandler(web.RequestHandler):
if not isinstance(subvalue, list):
subvalue = [subvalue]
for subsubvalue in subvalue:
- parts.append('<' + escape.utf8(name) + '>')
+ parts.append('<' + utils.utf8(name) + '>')
self._render_parts(subsubvalue, parts)
- parts.append('</' + escape.utf8(name) + '>')
+ parts.append('</' + utils.utf8(name) + '>')
else:
raise Exception("Unknown S3 value type %r", value)
@@ -142,7 +181,7 @@ class BucketHandler(BaseRequestHandler):
terse = int(self.get_argument("terse", 0))
if not path.startswith(self.application.directory) or \
not os.path.isdir(path):
- raise web.HTTPError(404)
+ raise webob.exc.HTTPError(404)
object_names = []
for root, dirs, files in os.walk(path):
for file_name in files:
@@ -192,7 +231,7 @@ class BucketHandler(BaseRequestHandler):
self.application.directory, bucket_name))
if not path.startswith(self.application.directory) or \
os.path.exists(path):
- raise web.HTTPError(403)
+ raise webob.exc.HTTPError(403)
os.makedirs(path)
self.finish()
@@ -201,9 +240,9 @@ class BucketHandler(BaseRequestHandler):
self.application.directory, bucket_name))
if not path.startswith(self.application.directory) or \
not os.path.isdir(path):
- raise web.HTTPError(404)
+ raise webob.exc.HTTPError(404)
if len(os.listdir(path)) > 0:
- raise web.HTTPError(403)
+ raise webob.exc.HTTPError(403)
os.rmdir(path)
self.set_status(204)
self.finish()
@@ -215,7 +254,7 @@ class ObjectHandler(BaseRequestHandler):
path = self._object_path(bucket, object_name)
if not path.startswith(self.application.directory) or \
not os.path.isfile(path):
- raise web.HTTPError(404)
+ raise webob.exc.HTTPError(404)
info = os.stat(path)
self.set_header("Content-Type", "application/unknown")
self.set_header("Last-Modified", datetime.datetime.utcfromtimestamp(
@@ -232,10 +271,10 @@ class ObjectHandler(BaseRequestHandler):
self.application.directory, bucket))
if not bucket_dir.startswith(self.application.directory) or \
not os.path.isdir(bucket_dir):
- raise web.HTTPError(404)
+ raise webob.exc.HTTPError(404)
path = self._object_path(bucket, object_name)
if not path.startswith(bucket_dir) or os.path.isdir(path):
- raise web.HTTPError(403)
+ raise webob.exc.HTTPError(403)
directory = os.path.dirname(path)
if not os.path.exists(directory):
os.makedirs(directory)
@@ -249,7 +288,7 @@ class ObjectHandler(BaseRequestHandler):
path = self._object_path(bucket, object_name)
if not path.startswith(self.application.directory) or \
not os.path.isfile(path):
- raise web.HTTPError(404)
+ raise webob.exc.HTTPError(404)
os.unlink(path)
self.set_status(204)
self.finish()