proxy: added account DELETE method; added option to control whether account PUTs and DELETEs are even callable
This commit is contained in:
commit
295cbdc7a9
@ -462,6 +462,8 @@ error_suppression_interval 60 Time in seconds that must
|
||||
no longer error limited
|
||||
error_suppression_limit 10 Error count to consider a
|
||||
node error limited
|
||||
allow_account_management false Whether account PUTs and DELETEs
|
||||
are even callable
|
||||
============================ =============== =============================
|
||||
|
||||
[auth]
|
||||
|
@ -241,6 +241,7 @@ Sample configuration files are provided with all defaults in line-by-line commen
|
||||
|
||||
[app:proxy-server]
|
||||
use = egg:swift#proxy
|
||||
allow_account_management = true
|
||||
|
||||
[filter:auth]
|
||||
use = egg:swift#auth
|
||||
|
@ -124,6 +124,7 @@ Configure the Proxy node
|
||||
|
||||
[app:proxy-server]
|
||||
use = egg:swift#proxy
|
||||
allow_account_management = true
|
||||
|
||||
[filter:auth]
|
||||
use = egg:swift#auth
|
||||
|
@ -29,6 +29,9 @@ use = egg:swift#proxy
|
||||
# error_suppression_interval = 60
|
||||
# How many errors can accumulate before a node is temporarily ignored.
|
||||
# error_suppression_limit = 10
|
||||
# If set to 'true' any authorized user may create and delete accounts; if
|
||||
# 'false' no one, even authorized, can.
|
||||
# allow_account_management = false
|
||||
|
||||
[filter:auth]
|
||||
use = egg:swift#auth
|
||||
|
@ -1139,6 +1139,8 @@ class AccountController(Controller):
|
||||
@public
|
||||
def PUT(self, req):
|
||||
"""HTTP PUT request handler."""
|
||||
if not self.app.allow_account_management:
|
||||
return HTTPMethodNotAllowed(request=req)
|
||||
error_response = check_metadata(req, 'account')
|
||||
if error_response:
|
||||
return error_response
|
||||
@ -1238,6 +1240,51 @@ class AccountController(Controller):
|
||||
return self.best_response(req, statuses, reasons, bodies,
|
||||
'Account POST')
|
||||
|
||||
@public
|
||||
def DELETE(self, req):
|
||||
"""HTTP DELETE request handler."""
|
||||
if not self.app.allow_account_management:
|
||||
return HTTPMethodNotAllowed(request=req)
|
||||
account_partition, accounts = \
|
||||
self.app.account_ring.get_nodes(self.account_name)
|
||||
headers = {'X-Timestamp': normalize_timestamp(time.time()),
|
||||
'X-CF-Trans-Id': self.trans_id}
|
||||
statuses = []
|
||||
reasons = []
|
||||
bodies = []
|
||||
for node in self.iter_nodes(account_partition, accounts,
|
||||
self.app.account_ring):
|
||||
if self.error_limited(node):
|
||||
continue
|
||||
try:
|
||||
with ConnectionTimeout(self.app.conn_timeout):
|
||||
conn = http_connect(node['ip'], node['port'],
|
||||
node['device'], account_partition, 'DELETE',
|
||||
req.path_info, headers)
|
||||
with Timeout(self.app.node_timeout):
|
||||
source = conn.getresponse()
|
||||
body = source.read()
|
||||
if 200 <= source.status < 300 \
|
||||
or 400 <= source.status < 500:
|
||||
statuses.append(source.status)
|
||||
reasons.append(source.reason)
|
||||
bodies.append(body)
|
||||
elif source.status == 507:
|
||||
self.error_limit(node)
|
||||
except:
|
||||
self.exception_occurred(node, 'Account',
|
||||
'Trying to DELETE %s' % req.path)
|
||||
if len(statuses) >= len(accounts):
|
||||
break
|
||||
while len(statuses) < len(accounts):
|
||||
statuses.append(503)
|
||||
reasons.append('')
|
||||
bodies.append('')
|
||||
if self.app.memcache:
|
||||
self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
|
||||
return self.best_response(req, statuses, reasons, bodies,
|
||||
'Account DELETE')
|
||||
|
||||
|
||||
class BaseApplication(object):
|
||||
"""Base WSGI application for the proxy server"""
|
||||
@ -1265,6 +1312,8 @@ class BaseApplication(object):
|
||||
int(conf.get('recheck_container_existence', 60))
|
||||
self.recheck_account_existence = \
|
||||
int(conf.get('recheck_account_existence', 60))
|
||||
self.allow_account_management = \
|
||||
conf.get('allow_account_management', 'false').lower() == 'true'
|
||||
self.resellers_conf = ConfigParser()
|
||||
self.resellers_conf.read(os.path.join(swift_dir, 'resellers.conf'))
|
||||
self.object_ring = object_ring or \
|
||||
|
@ -2601,6 +2601,8 @@ class TestAccountController(unittest.TestCase):
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(expected)], expected)
|
||||
test_status_map((201, 201, 201), 405)
|
||||
self.app.allow_account_management = True
|
||||
test_status_map((201, 201, 201), 201)
|
||||
test_status_map((201, 201, 500), 201)
|
||||
test_status_map((201, 500, 500), 503)
|
||||
@ -2608,6 +2610,7 @@ class TestAccountController(unittest.TestCase):
|
||||
|
||||
def test_PUT_max_account_name_length(self):
|
||||
with save_globals():
|
||||
self.app.allow_account_management = True
|
||||
controller = proxy_server.AccountController(self.app, '1' * 256)
|
||||
self.assert_status_map(controller.PUT, (201, 201, 201), 201)
|
||||
controller = proxy_server.AccountController(self.app, '2' * 257)
|
||||
@ -2615,6 +2618,7 @@ class TestAccountController(unittest.TestCase):
|
||||
|
||||
def test_PUT_connect_exceptions(self):
|
||||
with save_globals():
|
||||
self.app.allow_account_management = True
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
self.assert_status_map(controller.PUT, (201, 201, -1), 201)
|
||||
self.assert_status_map(controller.PUT, (201, -1, -1), 503)
|
||||
@ -2643,6 +2647,7 @@ class TestAccountController(unittest.TestCase):
|
||||
test_errors.append('%s: %s not in %s' %
|
||||
(test_header, test_value, headers))
|
||||
with save_globals():
|
||||
self.app.allow_account_management = True
|
||||
controller = \
|
||||
proxy_server.AccountController(self.app, 'a')
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201,
|
||||
@ -2661,6 +2666,7 @@ class TestAccountController(unittest.TestCase):
|
||||
|
||||
def bad_metadata_helper(self, method):
|
||||
with save_globals():
|
||||
self.app.allow_account_management = True
|
||||
controller = proxy_server.AccountController(self.app, 'a')
|
||||
proxy_server.http_connect = fake_http_connect(200, 201, 201, 201)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method})
|
||||
@ -2743,6 +2749,27 @@ class TestAccountController(unittest.TestCase):
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
def test_DELETE(self):
|
||||
with save_globals():
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
|
||||
def test_status_map(statuses, expected, **kwargs):
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(*statuses, **kwargs)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a', {'REQUEST_METHOD': 'DELETE'})
|
||||
req.content_length = 0
|
||||
self.app.update_request(req)
|
||||
res = controller.DELETE(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(expected)], expected)
|
||||
test_status_map((201, 201, 201), 405)
|
||||
self.app.allow_account_management = True
|
||||
test_status_map((201, 201, 201), 201)
|
||||
test_status_map((201, 201, 500), 201)
|
||||
test_status_map((201, 500, 500), 503)
|
||||
test_status_map((204, 500, 404), 503)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user