Added doc strings and pointers to docs for swift3
This commit is contained in:
parent
d0651b914d
commit
e2c0a23839
@ -31,7 +31,7 @@ Installing dependencies and the core code
|
|||||||
#. `apt-get install curl gcc bzr memcached python-configobj
|
#. `apt-get install curl gcc bzr memcached python-configobj
|
||||||
python-coverage python-dev python-nose python-setuptools python-simplejson
|
python-coverage python-dev python-nose python-setuptools python-simplejson
|
||||||
python-xattr sqlite3 xfsprogs python-webob python-eventlet
|
python-xattr sqlite3 xfsprogs python-webob python-eventlet
|
||||||
python-greenlet python-pastedeploy`
|
python-greenlet python-pastedeploy python-netifaces`
|
||||||
#. Install anything else you want, like screen, ssh, vim, etc.
|
#. Install anything else you want, like screen, ssh, vim, etc.
|
||||||
#. Next, choose either :ref:`partition-section` or :ref:`loopback-section`.
|
#. Next, choose either :ref:`partition-section` or :ref:`loopback-section`.
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ And the following python libraries:
|
|||||||
* Xattr
|
* Xattr
|
||||||
* Nose
|
* Nose
|
||||||
* Sphinx
|
* Sphinx
|
||||||
|
* netifaces
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
Development
|
Development
|
||||||
@ -38,4 +39,4 @@ Production
|
|||||||
|
|
||||||
If you want to set up and configure Swift for a production cluster, the following doc should be useful:
|
If you want to set up and configure Swift for a production cluster, the following doc should be useful:
|
||||||
|
|
||||||
* :doc:`Multiple Server Swift Installation <howto_installmultinode>`
|
* :doc:`Multiple Server Swift Installation <howto_installmultinode>`
|
||||||
|
@ -122,3 +122,11 @@ Ratelimit
|
|||||||
.. automodule:: swift.common.middleware.ratelimit
|
.. automodule:: swift.common.middleware.ratelimit
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
Swift3
|
||||||
|
======
|
||||||
|
|
||||||
|
.. automodule:: swift.common.middleware.swift3
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
@ -32,25 +32,32 @@ MAX_BUCKET_LISTING = 1000
|
|||||||
|
|
||||||
|
|
||||||
def get_err_response(code):
|
def get_err_response(code):
|
||||||
error_table = {'AccessDenied':
|
"""
|
||||||
(403, 'Access denied'),
|
Given an HTTP response code, create a properly formatted xml error response
|
||||||
'BucketAlreadyExists':
|
|
||||||
(409, 'The requested bucket name is not available'),
|
:param code: error code
|
||||||
'BucketNotEmpty':
|
:returns: webob.response object
|
||||||
(409, 'The bucket you tried to delete is not empty'),
|
"""
|
||||||
'InvalidArgument':
|
error_table = {
|
||||||
(400, 'Invalid Argument'),
|
'AccessDenied':
|
||||||
'InvalidBucketName':
|
(403, 'Access denied'),
|
||||||
(400, 'The specified bucket is not valid'),
|
'BucketAlreadyExists':
|
||||||
'InvalidURI':
|
(409, 'The requested bucket name is not available'),
|
||||||
(400, 'Could not parse the specified URI'),
|
'BucketNotEmpty':
|
||||||
'NoSuchBucket':
|
(409, 'The bucket you tried to delete is not empty'),
|
||||||
(404, 'The specified bucket does not exist'),
|
'InvalidArgument':
|
||||||
'SignatureDoesNotMatch':
|
(400, 'Invalid Argument'),
|
||||||
(403, 'The calculated request signature does not match '\
|
'InvalidBucketName':
|
||||||
'your provided one'),
|
(400, 'The specified bucket is not valid'),
|
||||||
'NoSuchKey':
|
'InvalidURI':
|
||||||
(404, 'The resource you requested does not exist')}
|
(400, 'Could not parse the specified URI'),
|
||||||
|
'NoSuchBucket':
|
||||||
|
(404, 'The specified bucket does not exist'),
|
||||||
|
'SignatureDoesNotMatch':
|
||||||
|
(403, 'The calculated request signature does not match '\
|
||||||
|
'your provided one'),
|
||||||
|
'NoSuchKey':
|
||||||
|
(404, 'The resource you requested does not exist')}
|
||||||
|
|
||||||
resp = Response(content_type='text/xml')
|
resp = Response(content_type='text/xml')
|
||||||
resp.status = error_table[code][0]
|
resp.status = error_table[code][0]
|
||||||
@ -71,12 +78,18 @@ class Controller(object):
|
|||||||
|
|
||||||
|
|
||||||
class ServiceController(Controller):
|
class ServiceController(Controller):
|
||||||
|
"""
|
||||||
|
Handles account level requests.
|
||||||
|
"""
|
||||||
def __init__(self, env, app, account_name, token, **kwargs):
|
def __init__(self, env, app, account_name, token, **kwargs):
|
||||||
Controller.__init__(self, app)
|
Controller.__init__(self, app)
|
||||||
env['HTTP_X_AUTH_TOKEN'] = token
|
env['HTTP_X_AUTH_TOKEN'] = token
|
||||||
env['PATH_INFO'] = '/v1/%s' % account_name
|
env['PATH_INFO'] = '/v1/%s' % account_name
|
||||||
|
|
||||||
def GET(self, env, start_response):
|
def GET(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle GET Service request
|
||||||
|
"""
|
||||||
env['QUERY_STRING'] = 'format=json'
|
env['QUERY_STRING'] = 'format=json'
|
||||||
body_iter = self.app(env, self.do_start_response)
|
body_iter = self.app(env, self.do_start_response)
|
||||||
status = int(self.response_args[0].split()[0])
|
status = int(self.response_args[0].split()[0])
|
||||||
@ -105,6 +118,9 @@ class ServiceController(Controller):
|
|||||||
|
|
||||||
|
|
||||||
class BucketController(Controller):
|
class BucketController(Controller):
|
||||||
|
"""
|
||||||
|
Handles bucket request.
|
||||||
|
"""
|
||||||
def __init__(self, env, app, account_name, token, container_name,
|
def __init__(self, env, app, account_name, token, container_name,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
Controller.__init__(self, app)
|
Controller.__init__(self, app)
|
||||||
@ -113,6 +129,9 @@ class BucketController(Controller):
|
|||||||
env['PATH_INFO'] = '/v1/%s/%s' % (account_name, container_name)
|
env['PATH_INFO'] = '/v1/%s/%s' % (account_name, container_name)
|
||||||
|
|
||||||
def GET(self, env, start_response):
|
def GET(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle GET Bucket (List Objects) request
|
||||||
|
"""
|
||||||
if 'QUERY_STRING' in env:
|
if 'QUERY_STRING' in env:
|
||||||
args = dict(cgi.parse_qsl(env['QUERY_STRING']))
|
args = dict(cgi.parse_qsl(env['QUERY_STRING']))
|
||||||
else:
|
else:
|
||||||
@ -170,6 +189,9 @@ class BucketController(Controller):
|
|||||||
return Response(body=body, content_type='text/xml')
|
return Response(body=body, content_type='text/xml')
|
||||||
|
|
||||||
def PUT(self, env, start_response):
|
def PUT(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle PUT Bucket request
|
||||||
|
"""
|
||||||
body_iter = self.app(env, self.do_start_response)
|
body_iter = self.app(env, self.do_start_response)
|
||||||
status = int(self.response_args[0].split()[0])
|
status = int(self.response_args[0].split()[0])
|
||||||
headers = dict(self.response_args[1])
|
headers = dict(self.response_args[1])
|
||||||
@ -188,6 +210,9 @@ class BucketController(Controller):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
def DELETE(self, env, start_response):
|
def DELETE(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle DELETE Bucket request
|
||||||
|
"""
|
||||||
body_iter = self.app(env, self.do_start_response)
|
body_iter = self.app(env, self.do_start_response)
|
||||||
status = int(self.response_args[0].split()[0])
|
status = int(self.response_args[0].split()[0])
|
||||||
headers = dict(self.response_args[1])
|
headers = dict(self.response_args[1])
|
||||||
@ -208,6 +233,9 @@ class BucketController(Controller):
|
|||||||
|
|
||||||
|
|
||||||
class ObjectController(Controller):
|
class ObjectController(Controller):
|
||||||
|
"""
|
||||||
|
Handles requests on objects
|
||||||
|
"""
|
||||||
def __init__(self, env, app, account_name, token, container_name,
|
def __init__(self, env, app, account_name, token, container_name,
|
||||||
object_name, **kwargs):
|
object_name, **kwargs):
|
||||||
Controller.__init__(self, app)
|
Controller.__init__(self, app)
|
||||||
@ -239,12 +267,21 @@ class ObjectController(Controller):
|
|||||||
return get_err_response('InvalidURI')
|
return get_err_response('InvalidURI')
|
||||||
|
|
||||||
def HEAD(self, env, start_response):
|
def HEAD(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle HEAD Object request
|
||||||
|
"""
|
||||||
return self.GETorHEAD(env, start_response)
|
return self.GETorHEAD(env, start_response)
|
||||||
|
|
||||||
def GET(self, env, start_response):
|
def GET(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle GET Object request
|
||||||
|
"""
|
||||||
return self.GETorHEAD(env, start_response)
|
return self.GETorHEAD(env, start_response)
|
||||||
|
|
||||||
def PUT(self, env, start_response):
|
def PUT(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle PUT Object and PUT Object (Copy) request
|
||||||
|
"""
|
||||||
for key, value in env.items():
|
for key, value in env.items():
|
||||||
if key.startswith('HTTP_X_AMZ_META_'):
|
if key.startswith('HTTP_X_AMZ_META_'):
|
||||||
del env[key]
|
del env[key]
|
||||||
@ -269,6 +306,9 @@ class ObjectController(Controller):
|
|||||||
return Response(status=200, etag=headers['etag'])
|
return Response(status=200, etag=headers['etag'])
|
||||||
|
|
||||||
def DELETE(self, env, start_response):
|
def DELETE(self, env, start_response):
|
||||||
|
"""
|
||||||
|
Handle DELETE Object request
|
||||||
|
"""
|
||||||
body_iter = self.app(env, self.do_start_response)
|
body_iter = self.app(env, self.do_start_response)
|
||||||
status = int(self.response_args[0].split()[0])
|
status = int(self.response_args[0].split()[0])
|
||||||
headers = dict(self.response_args[1])
|
headers = dict(self.response_args[1])
|
||||||
@ -287,6 +327,42 @@ class ObjectController(Controller):
|
|||||||
|
|
||||||
|
|
||||||
class Swift3Middleware(object):
|
class Swift3Middleware(object):
|
||||||
|
"""
|
||||||
|
The swift3 middleware will emulate the S3 REST api on top of swift.
|
||||||
|
|
||||||
|
The following opperations are currently supported:
|
||||||
|
|
||||||
|
* GET Service
|
||||||
|
* DELETE Bucket
|
||||||
|
* GET Bucket (List Objects)
|
||||||
|
* PUT Bucket
|
||||||
|
* DELETE Object
|
||||||
|
* GET Object
|
||||||
|
* HEAD Object
|
||||||
|
* PUT Object
|
||||||
|
* PUT Object (Copy)
|
||||||
|
|
||||||
|
To add this middleware to your configuration, add the swift3 middleware
|
||||||
|
in front of the auth middleware, and before any other middleware that
|
||||||
|
look at swift requests (like rate limiting).
|
||||||
|
|
||||||
|
To set up your client, the access key will be the account string that
|
||||||
|
should look like AUTH_d305e9dbedbc47df8b25ab46f3152f81, and the
|
||||||
|
secret access key is the account password. The host should also point
|
||||||
|
to the swift storage hostname. It also will have to use the old style
|
||||||
|
calling format, and not the hostname based container format.
|
||||||
|
|
||||||
|
An example client using the python boto library might look like the
|
||||||
|
following for an SAIO setup::
|
||||||
|
|
||||||
|
connection = boto.s3.Connection(
|
||||||
|
aws_access_key_id='AUTH_d305e9dbedbc47df8b25ab46f3152f81',
|
||||||
|
aws_secret_access_key='testing',
|
||||||
|
port=8080,
|
||||||
|
host='127.0.0.1',
|
||||||
|
is_secure=False,
|
||||||
|
calling_format=boto.s3.connection.OrdinaryCallingFormat())
|
||||||
|
"""
|
||||||
def __init__(self, app, conf, *args, **kwargs):
|
def __init__(self, app, conf, *args, **kwargs):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
@ -352,6 +428,7 @@ class Swift3Middleware(object):
|
|||||||
|
|
||||||
|
|
||||||
def filter_factory(global_conf, **local_conf):
|
def filter_factory(global_conf, **local_conf):
|
||||||
|
"""Standard filter factory to use the middleware with paste.deploy"""
|
||||||
conf = global_conf.copy()
|
conf = global_conf.copy()
|
||||||
conf.update(local_conf)
|
conf.update(local_conf)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user