Object delete and metadata handling API.
[pithos] / api / functions.py
1 #\r
2 # Copyright (c) 2011 Greek Research and Technology Network\r
3 #\r
4 \r
5 from django.http import HttpResponse\r
6 from django.template.loader import render_to_string\r
7 from django.utils import simplejson as json\r
8 \r
9 from pithos.api.faults import Fault, BadRequest, Unauthorized\r
10 from pithos.api.util import api_method\r
11 \r
12 from pithos.backends.dummy_debug import *\r
13 \r
14 import logging\r
15 \r
16 logging.basicConfig(level=logging.DEBUG)\r
17 \r
18 @api_method('GET')\r
19 def authenticate(request):\r
20     # Normal Response Codes: 204\r
21     # Error Response Codes: serviceUnavailable (503),\r
22     #                       unauthorized (401),\r
23     #                       badRequest (400)\r
24     \r
25     x_auth_user = request.META.get('HTTP_X_AUTH_USER')\r
26     x_auth_key = request.META.get('HTTP_X_AUTH_KEY')\r
27     \r
28     if not x_auth_user or not x_auth_key:\r
29         raise BadRequest('Missing auth user or key.')\r
30     \r
31     response = HttpResponse(status = 204)\r
32     response['X-Auth-Token'] = 'eaaafd18-0fed-4b3a-81b4-663c99ec1cbb'\r
33     # TODO: Do we support redirections?\r
34     #response['X-Storage-Url'] = 'https://storage.grnet.gr/pithos/v1.0/<some reference>'\r
35     return response\r
36 \r
37 def account_demux(request, v_account):\r
38     if request.method == 'HEAD':\r
39         return account_meta(request, v_account)\r
40     elif request.method == 'GET':\r
41         return container_list(request, v_account)\r
42     else:\r
43         return method_not_allowed(request)\r
44 \r
45 def container_demux(request, v_account, v_container):\r
46     if request.method == 'HEAD':\r
47         return container_meta(request, v_account, v_container)\r
48     elif request.method == 'GET':\r
49         return object_list(request, v_account, v_container)\r
50     elif request.method == 'PUT':\r
51         return container_create(request, v_account, v_container)\r
52     elif request.method == 'DELETE':\r
53         return container_delete(request, v_account, v_container)\r
54     else:\r
55         return method_not_allowed(request)\r
56 \r
57 def object_demux(request, v_account, v_container, v_object):\r
58     if request.method == 'HEAD':\r
59         return object_meta(request, v_account, v_container, v_object)\r
60     elif request.method == 'GET':\r
61         return object_read(request, v_account, v_container, v_object)\r
62     elif request.method == 'PUT':\r
63         return object_write(request, v_account, v_container, v_object)\r
64     elif request.method == 'POST':\r
65         return object_update(request, v_account, v_container, v_object)\r
66     elif request.method == 'DELETE':\r
67         return object_delete(request, v_account, v_container, v_object)\r
68     else:\r
69         return method_not_allowed(request)\r
70 \r
71 @api_method('HEAD')\r
72 def account_meta(request, v_account):\r
73     # Normal Response Codes: 204\r
74     # Error Response Codes: serviceUnavailable (503),\r
75     #                       itemNotFound (404),\r
76     #                       unauthorized (401),\r
77     #                       badRequest (400)\r
78     \r
79     container_count, bytes_count = get_account_meta(request.user)\r
80     \r
81     response = HttpResponse(status = 204)\r
82     response['X-Account-Container-Count'] = container_count\r
83     response['X-Account-Total-Bytes-Used'] = bytes_count\r
84     return response\r
85 \r
86 @api_method('GET', format_allowed = True)\r
87 def container_list(request, v_account):\r
88     # Normal Response Codes: 200, 204\r
89     # Error Response Codes: serviceUnavailable (503),\r
90     #                       unauthorized (401),\r
91     #                       badRequest (400)\r
92     \r
93     marker = request.GET.get('marker')\r
94     limit = request.GET.get('limit')\r
95     if limit:\r
96         try:\r
97             limit = int(limit)\r
98         except ValueError:\r
99             limit = None\r
100     \r
101     containers = list_containers(request.user, marker, limit)\r
102     if len(containers) == 0:\r
103         return HttpResponse(status = 204)\r
104     \r
105     if request.serialization == 'xml':\r
106         data = render_to_string('containers.xml', {'account': request.user, 'containers': containers})\r
107     elif request.serialization  == 'json':\r
108         data = json.dumps(containers)\r
109     else:\r
110         data = '\n'.join(x['name'] for x in containers)\r
111     \r
112     return HttpResponse(data, status = 200)\r
113 \r
114 @api_method('HEAD')\r
115 def container_meta(request, v_account, v_container):\r
116     # Normal Response Codes: 204\r
117     # Error Response Codes: serviceUnavailable (503),\r
118     #                       itemNotFound (404),\r
119     #                       unauthorized (401),\r
120     #                       badRequest (400)\r
121     \r
122     object_count, bytes_count = get_container_meta(request.user, v_container)\r
123     \r
124     response = HttpResponse(status = 204)\r
125     response['X-Container-Object-Count'] = object_count\r
126     response['X-Container-Bytes-Used'] = bytes_count\r
127     return response\r
128 \r
129 @api_method('PUT')\r
130 def container_create(request, v_account, v_container):\r
131     # Normal Response Codes: 201, 202\r
132     # Error Response Codes: serviceUnavailable (503),\r
133     #                       itemNotFound (404),\r
134     #                       unauthorized (401),\r
135     #                       badRequest (400)\r
136 \r
137     if create_container(request.user, v_container):\r
138         return HttpResponse(status = 201)\r
139     else:\r
140         return HttpResponse(status = 202)\r
141 \r
142 @api_method('DELETE')\r
143 def container_delete(request, v_account, v_container):\r
144     # Normal Response Codes: 204\r
145     # Error Response Codes: serviceUnavailable (503),\r
146     #                       itemNotFound (404),\r
147     #                       unauthorized (401),\r
148     #                       badRequest (400)\r
149     \r
150     object_count, bytes_count = get_container_meta(request.user, v_container)\r
151     if object_count > 0:\r
152         return HttpResponse(status = 409)\r
153     \r
154     delete_container(request.user, v_container)\r
155     return HttpResponse(status = 204)\r
156 \r
157 @api_method('GET', format_allowed = True)\r
158 def object_list(request, v_account, v_container):\r
159     # Normal Response Codes: 200, 204\r
160     # Error Response Codes: serviceUnavailable (503),\r
161     #                       itemNotFound (404),\r
162     #                       unauthorized (401),\r
163     #                       badRequest (400)\r
164     \r
165     path = request.GET.get('path')\r
166     prefix = request.GET.get('prefix')\r
167     delimiter = request.GET.get('delimiter')\r
168     logging.debug("path: %s", path)\r
169     \r
170     # Path overrides prefix and delimiter.\r
171     if path:\r
172         prefix = path\r
173         delimiter = '/'\r
174     # Naming policy.\r
175     if prefix and delimiter:\r
176         prefix = prefix + delimiter\r
177     \r
178     marker = request.GET.get('marker')\r
179     limit = request.GET.get('limit')\r
180     if limit:\r
181         try:\r
182             limit = int(limit)\r
183         except ValueError:\r
184             limit = None\r
185     \r
186     objects = list_objects(request.user, v_container, prefix, delimiter, marker, limit)\r
187     if len(objects) == 0:\r
188         return HttpResponse(status = 204)\r
189     \r
190     if request.serialization == 'xml':\r
191         data = render_to_string('objects.xml', {'container': v_container, 'objects': objects})\r
192     elif request.serialization  == 'json':\r
193         data = json.dumps(objects)\r
194     else:\r
195         data = '\n'.join(x['name'] for x in objects)\r
196     \r
197     return HttpResponse(data, status = 200)\r
198 \r
199 @api_method('HEAD')\r
200 def object_meta(request, v_account, v_container, v_object):\r
201     # Normal Response Codes: 204\r
202     # Error Response Codes: serviceUnavailable (503),\r
203     #                       itemNotFound (404),\r
204     #                       unauthorized (401),\r
205     #                       badRequest (400)\r
206 \r
207     info = get_object_meta(request.user, v_container, v_object)\r
208     \r
209     response = HttpResponse(status = 204)\r
210     response['ETag'] = info['hash']\r
211     response['Content-Length'] = info['bytes']\r
212     response['Content-Type'] = info['content_type']\r
213     # TODO: Format time.\r
214     response['Last-Modified'] = info['last_modified']\r
215     for k, v in info['meta'].iteritems():\r
216         response['X-Object-Meta-%s' % k.capitalize()] = v\r
217     \r
218     return response\r
219 \r
220 @api_method('GET')\r
221 def object_read(request, v_account, v_container, v_object):\r
222     return HttpResponse("object_read: %s %s %s" % (v_account, v_container, v_object))\r
223 \r
224 @api_method('PUT')\r
225 def object_write(request, v_account, v_container, v_object):\r
226     return HttpResponse("object_write: %s %s %s" % (v_account, v_container, v_object))\r
227 \r
228 @api_method('POST')\r
229 def object_update(request, v_account, v_container, v_object):\r
230     # Normal Response Codes: 202\r
231     # Error Response Codes: serviceUnavailable (503),\r
232     #                       itemNotFound (404),\r
233     #                       unauthorized (401),\r
234     #                       badRequest (400)\r
235     \r
236     prefix = 'X-Object-Meta-'\r
237     meta = dict([(k[len(prefix):].lower(), v) for k, v in request.POST.iteritems() if k.startswith(prefix)])\r
238     \r
239     update_object_meta(request.user, v_container, v_object, meta)\r
240     return HttpResponse(status = 202)\r
241 \r
242 @api_method('DELETE')\r
243 def object_delete(request, v_account, v_container, v_object):\r
244     # Normal Response Codes: 204\r
245     # Error Response Codes: serviceUnavailable (503),\r
246     #                       itemNotFound (404),\r
247     #                       unauthorized (401),\r
248     #                       badRequest (400)\r
249     \r
250     delete_object(request.user, v_container, v_object)\r
251     return HttpResponse(status = 204)\r
252 \r
253 @api_method()\r
254 def method_not_allowed(request):\r
255     raise BadRequest('Method not allowed.')\r