summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaypipes@gmail.com <>2010-08-10 14:20:15 -0400
committerjaypipes@gmail.com <>2010-08-10 14:20:15 -0400
commit1d414f6bddbae33bcbec799e29ab904d86811869 (patch)
treeb27f06c13282e25b55fa57cc77bcad19317ad616
parente1199140315e7cc85249820e92ab8b7998e50ae2 (diff)
pylint fixes for nova/objectstore/handler.py
-rw-r--r--nova/objectstore/handler.py133
1 files changed, 100 insertions, 33 deletions
diff --git a/nova/objectstore/handler.py b/nova/objectstore/handler.py
index f625a2aa1..cb38c89f2 100644
--- a/nova/objectstore/handler.py
+++ b/nova/objectstore/handler.py
@@ -19,6 +19,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+# Disabling pylint's R0201 (Method could be a function) because
+# the API of render_GET, render_PUT, etc is Twisted's, not ours.
+# pylint: disable-msg=R0201
+
"""
Implementation of an S3-like storage server based on local files.
@@ -61,6 +65,7 @@ from nova.objectstore import image
FLAGS = flags.FLAGS
def render_xml(request, value):
+ """Writes value as XML string to request"""
assert isinstance(value, dict) and len(value) == 1
request.setHeader("Content-Type", "application/xml; charset=UTF-8")
@@ -73,11 +78,13 @@ def render_xml(request, value):
request.finish()
def finish(request, content=None):
+ """Finalizer method for request"""
if content:
request.write(content)
request.finish()
def _render_parts(value, write_cb):
+ """Helper method to render different Python objects to XML"""
if isinstance(value, basestring):
write_cb(escape.xhtml_escape(value))
elif isinstance(value, int) or isinstance(value, long):
@@ -96,35 +103,47 @@ def _render_parts(value, write_cb):
raise Exception("Unknown S3 value type %r", value)
def get_argument(request, key, default_value):
+ """Returns the request's value at key, or default_value
+ if not found
+ """
if key in request.args:
return request.args[key][0]
return default_value
def get_context(request):
+ """Returns the supplied request's context object"""
try:
# Authorization Header format: 'AWS <access>:<secret>'
authorization_header = request.getHeader('Authorization')
if not authorization_header:
raise exception.NotAuthorized
- access, sep, secret = authorization_header.split(' ')[1].rpartition(':')
- (user, project) = manager.AuthManager().authenticate(access,
- secret,
- {},
- request.method,
- request.getRequestHostname(),
- request.uri,
- headers=request.getAllHeaders(),
- check_type='s3')
+ auth_header_value = authorization_header.split(' ')[1]
+ access, _ignored, secret = auth_header_value.rpartition(':')
+ am = manager.AuthManager()
+ (user, project) = am.authenticate(access,
+ secret,
+ {},
+ request.method,
+ request.getRequestHostname(),
+ request.uri,
+ headers=request.getAllHeaders(),
+ check_type='s3')
return api.APIRequestContext(None, user, project)
except exception.Error as ex:
- logging.debug("Authentication Failure: %s" % ex)
+ logging.debug("Authentication Failure: %s", ex)
raise exception.NotAuthorized
class ErrorHandlingResource(Resource):
- """Maps exceptions to 404 / 401 codes. Won't work for exceptions thrown after NOT_DONE_YET is returned."""
- # TODO(unassigned) (calling-all-twisted-experts): This needs to be plugged in to the right place in twisted...
- # This doesn't look like it's the right place (consider exceptions in getChild; or after NOT_DONE_YET is returned
+ """Maps exceptions to 404 / 401 codes. Won't work for
+ exceptions thrown after NOT_DONE_YET is returned.
+ """
+ # TODO(unassigned) (calling-all-twisted-experts): This needs to be
+ # plugged in to the right place in twisted...
+ # This doesn't look like it's the right place
+ # (consider exceptions in getChild; or after
+ # NOT_DONE_YET is returned
def render(self, request):
+ """Renders the response as XML"""
try:
return Resource.render(self, request)
except exception.NotFound:
@@ -136,7 +155,11 @@ class ErrorHandlingResource(Resource):
class S3(ErrorHandlingResource):
"""Implementation of an S3-like storage server based on local files."""
- def getChild(self, name, request):
+ def __init__(self):
+ ErrorHandlingResource.__init__(self)
+
+ def getChild(self, name, request): # pylint: disable-msg=C0103
+ """Returns either the image or bucket resource"""
request.context = get_context(request)
if name == '':
return self
@@ -146,8 +169,10 @@ class S3(ErrorHandlingResource):
return BucketResource(name)
def render_GET(self, request):
+ """Renders the GET request for a list of buckets as XML"""
logging.debug('List of buckets requested')
- buckets = [b for b in bucket.Bucket.all() if b.is_authorized(request.context)]
+ buckets = [b for b in bucket.Bucket.all() \
+ if b.is_authorized(request.context)]
render_xml(request, {"ListAllMyBucketsResult": {
"Buckets": {"Bucket": [b.metadata for b in buckets]},
@@ -155,22 +180,27 @@ class S3(ErrorHandlingResource):
return server.NOT_DONE_YET
class BucketResource(ErrorHandlingResource):
+ """A web resource containing an S3-like bucket"""
def __init__(self, name):
- Resource.__init__(self)
+ ErrorHandlingResource.__init__(self)
self.name = name
def getChild(self, name, request):
+ """Returns the bucket resource itself, or the object resource
+ the bucket contains if a name is supplied
+ """
if name == '':
return self
else:
return ObjectResource(bucket.Bucket(self.name), name)
def render_GET(self, request):
- logging.debug("List keys for bucket %s" % (self.name))
+ "Returns the keys for the bucket resource"""
+ logging.debug("List keys for bucket %s", self.name)
try:
bucket_object = bucket.Bucket(self.name)
- except exception.NotFound, e:
+ except exception.NotFound:
return error.NoResource(message="No such bucket").render(request)
if not bucket_object.is_authorized(request.context):
@@ -181,19 +211,26 @@ class BucketResource(ErrorHandlingResource):
max_keys = int(get_argument(request, "max-keys", 1000))
terse = int(get_argument(request, "terse", 0))
- results = bucket_object.list_keys(prefix=prefix, marker=marker, max_keys=max_keys, terse=terse)
+ results = bucket_object.list_keys(prefix=prefix,
+ marker=marker,
+ max_keys=max_keys,
+ terse=terse)
render_xml(request, {"ListBucketResult": results})
return server.NOT_DONE_YET
def render_PUT(self, request):
- logging.debug("Creating bucket %s" % (self.name))
- logging.debug("calling bucket.Bucket.create(%r, %r)" % (self.name, request.context))
+ "Creates the bucket resource"""
+ logging.debug("Creating bucket %s", self.name)
+ logging.debug("calling bucket.Bucket.create(%r, %r)",
+ self.name,
+ request.context)
bucket.Bucket.create(self.name, request.context)
request.finish()
return server.NOT_DONE_YET
def render_DELETE(self, request):
- logging.debug("Deleting bucket %s" % (self.name))
+ """Deletes the bucket resource"""
+ logging.debug("Deleting bucket %s", self.name)
bucket_object = bucket.Bucket(self.name)
if not bucket_object.is_authorized(request.context):
@@ -205,25 +242,37 @@ class BucketResource(ErrorHandlingResource):
class ObjectResource(ErrorHandlingResource):
- def __init__(self, bucket, name):
- Resource.__init__(self)
- self.bucket = bucket
+ """The resource returned from a bucket"""
+ def __init__(self, bucket_name, name):
+ ErrorHandlingResource.__init__(self)
+ self.bucket = bucket_name
self.name = name
def render_GET(self, request):
- logging.debug("Getting object: %s / %s" % (self.bucket.name, self.name))
+ """Returns the object
+
+ Raises NotAuthorized if user in request context is not
+ authorized to delete the object.
+ """
+ logging.debug("Getting object: %s / %s", self.bucket.name, self.name)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
obj = self.bucket[urllib.unquote(self.name)]
request.setHeader("Content-Type", "application/unknown")
- request.setHeader("Last-Modified", datetime.datetime.utcfromtimestamp(obj.mtime))
+ request.setHeader("Last-Modified",
+ datetime.datetime.utcfromtimestamp(obj.mtime))
request.setHeader("Etag", '"' + obj.md5 + '"')
return static.File(obj.path).render_GET(request)
def render_PUT(self, request):
- logging.debug("Putting object: %s / %s" % (self.bucket.name, self.name))
+ """Modifies/inserts the object and returns a result code
+
+ Raises NotAuthorized if user in request context is not
+ authorized to delete the object.
+ """
+ logging.debug("Putting object: %s / %s", self.bucket.name, self.name)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
@@ -236,7 +285,15 @@ class ObjectResource(ErrorHandlingResource):
return server.NOT_DONE_YET
def render_DELETE(self, request):
- logging.debug("Deleting object: %s / %s" % (self.bucket.name, self.name))
+ """Deletes the object and returns a result code
+
+ Raises NotAuthorized if user in request context is not
+ authorized to delete the object.
+ """
+
+ logging.debug("Deleting object: %s / %s",
+ self.bucket.name,
+ self.name)
if not self.bucket.is_authorized(request.context):
raise exception.NotAuthorized
@@ -246,17 +303,23 @@ class ObjectResource(ErrorHandlingResource):
return ''
class ImageResource(ErrorHandlingResource):
+ """A web resource representing a single image"""
isLeaf = True
def __init__(self, name):
- Resource.__init__(self)
+ ErrorHandlingResource.__init__(self)
self.img = image.Image(name)
def render_GET(self, request):
- return static.File(self.img.image_path, defaultType='application/octet-stream').render_GET(request)
+ """Returns the image file"""
+ return static.File(self.img.image_path,
+ defaultType='application/octet-stream'
+ ).render_GET(request)
class ImagesResource(Resource):
- def getChild(self, name, request):
+ """A web resource representing a list of images"""
+ def getChild(self, name, _request):
+ """Returns itself or an ImageResource if no name given"""
if name == '':
return self
else:
@@ -285,7 +348,6 @@ class ImagesResource(Resource):
raise exception.NotAuthorized
bucket_object = bucket.Bucket(image_location.split("/")[0])
- manifest = image_location[len(image_location.split('/')[0])+1:]
if not bucket_object.is_authorized(request.context):
raise exception.NotAuthorized
@@ -324,13 +386,18 @@ class ImagesResource(Resource):
return ''
def get_site():
+ """Support for WSGI-like interfaces"""
root = S3()
site = server.Site(root)
return site
def get_application():
+ """Support WSGI-like interfaces"""
factory = get_site()
application = service.Application("objectstore")
+ # Disabled because of lack of proper introspection in Twisted
+ # or possibly different versions of twisted?
+ # pylint: disable-msg=E1101
objectStoreService = internet.TCPServer(FLAGS.s3_port, factory)
objectStoreService.setServiceParent(application)
return application