1
# Copyright (c) 2010-2012 OpenStack, LLC.
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
17
# You'll see swift_conn passed around a few places in this file. This is the
18
# source httplib connection of whatever it is attached to.
19
# It is used when early termination of reading from the connection should
20
# happen, such as when a range request is satisfied but there's still more the
21
# source connection would like to send. To prevent having to read all the data
22
# that could be left, the source connection can be .close() and then reads
23
# commence to empty out any buffers.
24
# These shenanigans are to ensure all related objects can be garbage
25
# collected. We've seen objects hang around forever otherwise.
28
from urllib import unquote
29
from random import shuffle
31
from webob.exc import HTTPBadRequest, HTTPMethodNotAllowed
32
from webob import Request
34
from swift.common.utils import normalize_timestamp, public
35
from swift.common.constraints import check_metadata, MAX_ACCOUNT_NAME_LENGTH
36
from swift.common.http import is_success, HTTP_NOT_FOUND
37
from swift.proxy.controllers.base import Controller
40
class AccountController(Controller):
41
"""WSGI controller for account requests"""
42
server_type = 'Account'
44
def __init__(self, app, account_name, **kwargs):
45
Controller.__init__(self, app)
46
self.account_name = unquote(account_name)
48
def GETorHEAD(self, req):
49
"""Handler for HTTP GET/HEAD requests."""
50
partition, nodes = self.app.account_ring.get_nodes(self.account_name)
52
resp = self.GETorHEAD_base(req, _('Account'), partition, nodes,
53
req.path_info.rstrip('/'), len(nodes))
54
if resp.status_int == HTTP_NOT_FOUND and self.app.account_autocreate:
55
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
56
resp = HTTPBadRequest(request=req)
57
resp.body = 'Account name length of %d longer than %d' % \
58
(len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
60
headers = {'X-Timestamp': normalize_timestamp(time.time()),
61
'X-Trans-Id': self.trans_id,
62
'Connection': 'close'}
63
resp = self.make_requests(
64
Request.blank('/v1/' + self.account_name),
65
self.app.account_ring, partition, 'PUT',
66
'/' + self.account_name, [headers] * len(nodes))
67
if not is_success(resp.status_int):
68
self.app.logger.warning('Could not autocreate account %r' %
71
resp = self.GETorHEAD_base(req, _('Account'), partition, nodes,
72
req.path_info.rstrip('/'), len(nodes))
77
"""HTTP PUT request handler."""
78
if not self.app.allow_account_management:
79
return HTTPMethodNotAllowed(request=req)
80
error_response = check_metadata(req, 'account')
83
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
84
resp = HTTPBadRequest(request=req)
85
resp.body = 'Account name length of %d longer than %d' % \
86
(len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
88
account_partition, accounts = \
89
self.app.account_ring.get_nodes(self.account_name)
90
headers = {'X-Timestamp': normalize_timestamp(time.time()),
91
'x-trans-id': self.trans_id,
92
'Connection': 'close'}
93
self.transfer_headers(req.headers, headers)
95
self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
96
resp = self.make_requests(req, self.app.account_ring,
97
account_partition, 'PUT', req.path_info, [headers] * len(accounts))
102
"""HTTP POST request handler."""
103
error_response = check_metadata(req, 'account')
105
return error_response
106
account_partition, accounts = \
107
self.app.account_ring.get_nodes(self.account_name)
108
headers = {'X-Timestamp': normalize_timestamp(time.time()),
109
'X-Trans-Id': self.trans_id,
110
'Connection': 'close'}
111
self.transfer_headers(req.headers, headers)
112
if self.app.memcache:
113
self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
114
resp = self.make_requests(req, self.app.account_ring,
115
account_partition, 'POST', req.path_info,
116
[headers] * len(accounts))
117
if resp.status_int == HTTP_NOT_FOUND and self.app.account_autocreate:
118
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
119
resp = HTTPBadRequest(request=req)
120
resp.body = 'Account name length of %d longer than %d' % \
121
(len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
123
resp = self.make_requests(
124
Request.blank('/v1/' + self.account_name),
125
self.app.account_ring, account_partition, 'PUT',
126
'/' + self.account_name, [headers] * len(accounts))
127
if not is_success(resp.status_int):
128
self.app.logger.warning('Could not autocreate account %r' %
134
def DELETE(self, req):
135
"""HTTP DELETE request handler."""
136
if not self.app.allow_account_management:
137
return HTTPMethodNotAllowed(request=req)
138
account_partition, accounts = \
139
self.app.account_ring.get_nodes(self.account_name)
140
headers = {'X-Timestamp': normalize_timestamp(time.time()),
141
'X-Trans-Id': self.trans_id,
142
'Connection': 'close'}
143
if self.app.memcache:
144
self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
145
resp = self.make_requests(req, self.app.account_ring,
146
account_partition, 'DELETE', req.path_info,
147
[headers] * len(accounts))