Revision c36934a7
b/api/errors.py | ||
---|---|---|
22 | 22 |
class ItemNotFound(Fault): |
23 | 23 |
code = 404 |
24 | 24 |
|
25 |
class ServiceUnavailable(Fault): |
|
26 |
code = 503 |
b/api/flavors.py | ||
---|---|---|
1 |
# |
|
2 |
# Copyright (c) 2010 Greek Research and Technology Network |
|
3 |
# |
|
4 |
|
|
5 |
from synnefo.api.util import * |
|
6 |
from synnefo.db.models import Flavor |
|
7 |
|
|
8 |
from django.conf.urls.defaults import * |
|
9 |
from django.http import HttpResponse |
|
10 |
from django.template.loader import render_to_string |
|
11 |
|
|
12 |
|
|
13 |
urlpatterns = patterns('synnefo.api.flavors', |
|
14 |
(r'^(?:/|.json|.xml)?$', 'list_flavors'), |
|
15 |
(r'^/detail(?:.json|.xml)?$', 'list_flavors', {'detail': True}), |
|
16 |
(r'^/(\d+)(?:.json|.xml)?$', 'get_flavor_details'), |
|
17 |
) |
|
18 |
|
|
19 |
|
|
20 |
def flavor_to_dict(flavor, detail=True): |
|
21 |
d = {'id': flavor.id, 'name': flavor.name} |
|
22 |
if detail: |
|
23 |
d['ram'] = flavor.ram |
|
24 |
d['disk'] = flavor.disk |
|
25 |
return d |
|
26 |
|
|
27 |
|
|
28 |
@api_method('GET') |
|
29 |
def list_flavors(request, detail=False): |
|
30 |
# Normal Response Codes: 200, 203 |
|
31 |
# Error Response Codes: computeFault (400, 500), |
|
32 |
# serviceUnavailable (503), |
|
33 |
# unauthorized (401), |
|
34 |
# badRequest (400), |
|
35 |
# overLimit (413) |
|
36 |
|
|
37 |
all_flavors = Flavor.objects.all() |
|
38 |
flavors = [flavor_to_dict(flavor, detail) for flavor in all_flavors] |
|
39 |
|
|
40 |
if request.type == 'xml': |
|
41 |
mimetype = 'application/xml' |
|
42 |
data = render_to_string('list_flavors.xml', {'flavors': flavors, 'detail': detail}) |
|
43 |
else: |
|
44 |
mimetype = 'application/json' |
|
45 |
data = json.dumps({'flavors': {'values': flavors}}) |
|
46 |
|
|
47 |
return HttpResponse(data, mimetype=mimetype, status=200) |
|
48 |
|
|
49 |
@api_method('GET') |
|
50 |
def get_flavor_details(request, flavor_id): |
|
51 |
# Normal Response Codes: 200, 203 |
|
52 |
# Error Response Codes: computeFault (400, 500), |
|
53 |
# serviceUnavailable (503), |
|
54 |
# unauthorized (401), |
|
55 |
# badRequest (400), |
|
56 |
# itemNotFound (404), |
|
57 |
# overLimit (413) |
|
58 |
|
|
59 |
try: |
|
60 |
falvor_id = int(flavor_id) |
|
61 |
flavor = flavor_to_dict(Flavor.objects.get(id=flavor_id)) |
|
62 |
except Flavor.DoesNotExist: |
|
63 |
raise ItemNotFound |
|
64 |
|
|
65 |
if request.type == 'xml': |
|
66 |
data = render_to_string('flavor.xml', {'flavor': flavor}) |
|
67 |
else: |
|
68 |
data = json.dumps({'flavor': flavor}) |
|
69 |
|
|
70 |
return HttpResponse(data, status=200) |
b/api/images.py | ||
---|---|---|
1 |
# |
|
2 |
# Copyright (c) 2010 Greek Research and Technology Network |
|
3 |
# |
|
4 |
|
|
5 |
from synnefo.api.util import * |
|
6 |
from synnefo.db.models import Image |
|
7 |
|
|
8 |
from django.conf.urls.defaults import * |
|
9 |
from django.http import HttpResponse |
|
10 |
from django.template.loader import render_to_string |
|
11 |
|
|
12 |
|
|
13 |
urlpatterns = patterns('synnefo.api.images', |
|
14 |
(r'^(?:/|.json|.xml)?$', 'demux'), |
|
15 |
(r'^/detail(?:.json|.xml)?$', 'list_images', {'detail': True}), |
|
16 |
(r'^/(\d+)(?:.json|.xml)?$', 'image_demux'), |
|
17 |
) |
|
18 |
|
|
19 |
def demux(request): |
|
20 |
if request.method == 'GET': |
|
21 |
return list_images(request) |
|
22 |
elif request.method == 'POST': |
|
23 |
return create_image(request) |
|
24 |
else: |
|
25 |
fault = BadRequest() |
|
26 |
return render_fault(request, fault) |
|
27 |
|
|
28 |
def image_demux(request, image_id): |
|
29 |
if request.method == 'GET': |
|
30 |
return get_image_details(request, image_id) |
|
31 |
elif request.method == 'DELETE': |
|
32 |
return delete_image(request, image_id) |
|
33 |
else: |
|
34 |
fault = BadRequest() |
|
35 |
return render_fault(request, fault) |
|
36 |
|
|
37 |
|
|
38 |
def image_to_dict(image, detail=True): |
|
39 |
d = {'id': image.id, 'name': image.name} |
|
40 |
if detail: |
|
41 |
d['updated'] = image.updated.isoformat() |
|
42 |
d['created'] = image.created.isoformat() |
|
43 |
d['status'] = image.state |
|
44 |
d['progress'] = 100 if image.state == 'ACTIVE' else 0 |
|
45 |
d['description'] = image.description |
|
46 |
if image.sourcevm: |
|
47 |
d['serverRef'] = image.sourcevm.id |
|
48 |
return d |
|
49 |
|
|
50 |
|
|
51 |
@api_method('GET') |
|
52 |
def list_images(request, detail=False): |
|
53 |
# Normal Response Codes: 200, 203 |
|
54 |
# Error Response Codes: computeFault (400, 500), |
|
55 |
# serviceUnavailable (503), |
|
56 |
# unauthorized (401), |
|
57 |
# badRequest (400), |
|
58 |
# overLimit (413) |
|
59 |
|
|
60 |
all_images = Image.objects.all() |
|
61 |
images = [image_to_dict(image, detail) for image in all_images] |
|
62 |
|
|
63 |
if request.type == 'xml': |
|
64 |
mimetype = 'application/xml' |
|
65 |
data = render_to_string('list_images.xml', {'images': images, 'detail': detail}) |
|
66 |
else: |
|
67 |
mimetype = 'application/json' |
|
68 |
data = json.dumps({'images': {'values': images}}) |
|
69 |
|
|
70 |
return HttpResponse(data, mimetype=mimetype, status=200) |
|
71 |
|
|
72 |
@api_method('POST') |
|
73 |
def create_image(request): |
|
74 |
# Normal Response Code: 202 |
|
75 |
# Error Response Codes: computeFault (400, 500), |
|
76 |
# serviceUnavailable (503), |
|
77 |
# unauthorized (401), |
|
78 |
# badMediaType(415), |
|
79 |
# itemNotFound (404), |
|
80 |
# badRequest (400), |
|
81 |
# serverCapacityUnavailable (503), |
|
82 |
# buildInProgress (409), |
|
83 |
# resizeNotAllowed (403), |
|
84 |
# backupOrResizeInProgress (409), |
|
85 |
# overLimit (413) |
|
86 |
|
|
87 |
req = get_request_dict(request) |
|
88 |
owner = get_user() |
|
89 |
|
|
90 |
try: |
|
91 |
d = req['image'] |
|
92 |
server_id = int(d['serverRef']) |
|
93 |
vm = VirtualMachine.objects.get(id=server_id) |
|
94 |
image = Image.objects.create(name=d['name'], size=0, owner=owner, sourcevm=vm) |
|
95 |
image.save() |
|
96 |
except KeyError: |
|
97 |
raise BadRequest |
|
98 |
except ValueError: |
|
99 |
raise BadRequest |
|
100 |
except VirtualMachine.DoesNotExist: |
|
101 |
raise ItemNotFound |
|
102 |
|
|
103 |
imagedict = image_to_dict(image) |
|
104 |
if request.type == 'xml': |
|
105 |
data = render_to_string('image.xml', {'image': imagedict}) |
|
106 |
else: |
|
107 |
data = json.dumps({'image': imagedict}) |
|
108 |
|
|
109 |
return HttpResponse(data, status=202) |
|
110 |
|
|
111 |
@api_method('GET') |
|
112 |
def get_image_details(request, image_id): |
|
113 |
# Normal Response Codes: 200, 203 |
|
114 |
# Error Response Codes: computeFault (400, 500), |
|
115 |
# serviceUnavailable (503), |
|
116 |
# unauthorized (401), |
|
117 |
# badRequest (400), |
|
118 |
# itemNotFound (404), |
|
119 |
# overLimit (413) |
|
120 |
|
|
121 |
try: |
|
122 |
image_id = int(image_id) |
|
123 |
imagedict = image_to_dict(Image.objects.get(id=image_id)) |
|
124 |
except Image.DoesNotExist: |
|
125 |
raise ItemNotFound |
|
126 |
|
|
127 |
if request.type == 'xml': |
|
128 |
data = render_to_string('image.xml', {'image': imagedict}) |
|
129 |
else: |
|
130 |
data = json.dumps({'image': imagedict}) |
|
131 |
|
|
132 |
return HttpResponse(data, status=200) |
|
133 |
|
|
134 |
@api_method('DELETE') |
|
135 |
def delete_image(request, image_id): |
|
136 |
# Normal Response Code: 204 |
|
137 |
# Error Response Codes: computeFault (400, 500), |
|
138 |
# serviceUnavailable (503), |
|
139 |
# unauthorized (401), |
|
140 |
# itemNotFound (404), |
|
141 |
# overLimit (413) |
|
142 |
|
|
143 |
try: |
|
144 |
image_id = int(image_id) |
|
145 |
image = Image.objects.get(id=image_id) |
|
146 |
except Image.DoesNotExist: |
|
147 |
raise ItemNotFound |
|
148 |
|
|
149 |
if image.owner != get_user(): |
|
150 |
raise Unauthorized() |
|
151 |
image.delete() |
|
152 |
return HttpResponse(status=204) |
b/api/servers.py | ||
---|---|---|
32 | 32 |
elif request.method == 'POST': |
33 | 33 |
return create_server(request) |
34 | 34 |
else: |
35 |
return HttpResponse(status=404) |
|
35 |
fault = BadRequest() |
|
36 |
return render_fault(request, fault) |
|
36 | 37 |
|
37 | 38 |
def server_demux(request, server_id): |
38 | 39 |
if request.method == 'GET': |
... | ... | |
42 | 43 |
elif request.method == 'DELETE': |
43 | 44 |
return delete_server(request, server_id) |
44 | 45 |
else: |
45 |
return HttpResponse(status=404) |
|
46 |
fault = BadRequest() |
|
47 |
return render_fault(request, fault) |
|
46 | 48 |
|
47 |
def server_dict(vm, detail=False): |
|
48 |
d = dict(id=vm.id, name=vm.name) |
|
49 |
|
|
50 |
def server_to_dict(server, detail=False): |
|
51 |
d = dict(id=server.id, name=server.name) |
|
49 | 52 |
if detail: |
50 |
d['status'] = vm.rsapi_state
|
|
51 |
d['progress'] = 100 if vm.rsapi_state == 'ACTIVE' else 0
|
|
52 |
d['hostId'] = vm.hostid
|
|
53 |
d['updated'] = vm.updated.isoformat()
|
|
54 |
d['created'] = vm.created.isoformat()
|
|
55 |
d['flavorId'] = vm.flavor.id # XXX Should use flavorRef instead?
|
|
56 |
d['imageId'] = vm.sourceimage.id # XXX Should use imageRef instead?
|
|
57 |
d['description'] = vm.description # XXX Not in OpenStack docs
|
|
53 |
d['status'] = server.rsapi_state
|
|
54 |
d['progress'] = 100 if server.rsapi_state == 'ACTIVE' else 0
|
|
55 |
d['hostId'] = server.hostid
|
|
56 |
d['updated'] = server.updated.isoformat()
|
|
57 |
d['created'] = server.created.isoformat()
|
|
58 |
d['flavorId'] = server.flavor.id # XXX Should use flavorRef instead?
|
|
59 |
d['imageId'] = server.sourceimage.id # XXX Should use imageRef instead?
|
|
60 |
d['description'] = server.description # XXX Not in OpenStack docs
|
|
58 | 61 |
|
59 |
vm_meta = vm.virtualmachinemetadata_set.all()
|
|
60 |
metadata = dict((meta.meta_key, meta.meta_value) for meta in vm_meta)
|
|
62 |
server_meta = server.virtualmachinemetadata_set.all()
|
|
63 |
metadata = dict((meta.meta_key, meta.meta_value) for meta in server_meta)
|
|
61 | 64 |
if metadata: |
62 | 65 |
d['metadata'] = dict(values=metadata) |
63 | 66 |
|
64 |
public_addrs = [dict(version=4, addr=vm.ipfour), dict(version=6, addr=vm.ipsix)]
|
|
67 |
public_addrs = [dict(version=4, addr=server.ipfour), dict(version=6, addr=server.ipsix)]
|
|
65 | 68 |
d['addresses'] = {'values': []} |
66 | 69 |
d['addresses']['values'].append({'id': 'public', 'values': public_addrs}) |
67 | 70 |
return d |
68 | 71 |
|
69 |
def render_server(server, request, status=200):
|
|
72 |
def render_server(request, serverdict, status=200):
|
|
70 | 73 |
if request.type == 'xml': |
71 |
mimetype = 'application/xml' |
|
72 |
data = render_to_string('server.xml', dict(server=server, is_root=True)) |
|
74 |
data = render_to_string('server.xml', dict(server=serverdict, is_root=True)) |
|
73 | 75 |
else: |
74 |
mimetype = 'application/json' |
|
75 |
data = json.dumps({'server': server}) |
|
76 |
return HttpResponse(data, mimetype=mimetype, status=status) |
|
76 |
data = json.dumps({'server': serverdict}) |
|
77 |
return HttpResponse(data, status=status) |
|
77 | 78 |
|
78 | 79 |
|
79 |
@api_method |
|
80 |
@api_method('GET')
|
|
80 | 81 |
def list_servers(request, detail=False): |
81 | 82 |
# Normal Response Codes: 200, 203 |
82 | 83 |
# Error Response Codes: computeFault (400, 500), |
... | ... | |
84 | 85 |
# unauthorized (401), |
85 | 86 |
# badRequest (400), |
86 | 87 |
# overLimit (413) |
88 |
|
|
87 | 89 |
owner = get_user() |
88 |
vms = VirtualMachine.objects.filter(owner=owner, deleted=False) |
|
89 |
servers = [server_dict(vm, detail) for vm in vms] |
|
90 |
user_servers = VirtualMachine.objects.filter(owner=owner, deleted=False) |
|
91 |
servers = [server_to_dict(server, detail) for server in user_servers] |
|
92 |
|
|
90 | 93 |
if request.type == 'xml': |
91 |
mimetype = 'application/xml' |
|
92 | 94 |
data = render_to_string('list_servers.xml', dict(servers=servers, detail=detail)) |
93 | 95 |
else: |
94 |
mimetype = 'application/json'
|
|
95 |
data = json.dumps({'servers': servers}) |
|
96 |
return HttpResponse(data, mimetype=mimetype, status=200)
|
|
96 |
data = json.dumps({'servers': {'values': servers}})
|
|
97 |
|
|
98 |
return HttpResponse(data, status=200) |
|
97 | 99 |
|
98 |
@api_method |
|
100 |
@api_method('POST')
|
|
99 | 101 |
def create_server(request): |
100 | 102 |
# Normal Response Code: 202 |
101 | 103 |
# Error Response Codes: computeFault (400, 500), |
... | ... | |
121 | 123 |
except Flavor.DoesNotExist: |
122 | 124 |
raise ItemNotFound |
123 | 125 |
|
124 |
vm = VirtualMachine.objects.create(
|
|
126 |
server = VirtualMachine.objects.create(
|
|
125 | 127 |
name=name, |
126 | 128 |
owner=get_user(), |
127 | 129 |
sourceimage=sourceimage, |
... | ... | |
133 | 135 |
name = 'test-server' |
134 | 136 |
dry_run = True |
135 | 137 |
else: |
136 |
name = vm.backend_id
|
|
138 |
name = server.backend_id
|
|
137 | 139 |
dry_run = False |
138 | 140 |
|
139 | 141 |
jobId = rapi.CreateInstance( |
... | ... | |
149 | 151 |
dry_run=dry_run, |
150 | 152 |
beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram)) |
151 | 153 |
|
152 |
vm.save()
|
|
154 |
server.save()
|
|
153 | 155 |
|
154 | 156 |
log.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk)) |
155 | 157 |
|
156 |
server = server_dict(vm, detail=True)
|
|
157 |
server['status'] = 'BUILD' |
|
158 |
server['adminPass'] = random_password() |
|
159 |
return render_server(server, request, status=202)
|
|
158 |
serverdict = server_to_dict(server, detail=True)
|
|
159 |
serverdict['status'] = 'BUILD'
|
|
160 |
serverdict['adminPass'] = random_password()
|
|
161 |
return render_server(request, serverdict, status=202)
|
|
160 | 162 |
|
161 |
@api_method |
|
163 |
@api_method('GET')
|
|
162 | 164 |
def get_server_details(request, server_id): |
165 |
# Normal Response Codes: 200, 203 |
|
166 |
# Error Response Codes: computeFault (400, 500), |
|
167 |
# serviceUnavailable (503), |
|
168 |
# unauthorized (401), |
|
169 |
# badRequest (400), |
|
170 |
# itemNotFound (404), |
|
171 |
# overLimit (413) |
|
172 |
|
|
163 | 173 |
try: |
164 |
vm = VirtualMachine.objects.get(id=int(server_id)) |
|
174 |
server_id = int(server_id) |
|
175 |
server = VirtualMachine.objects.get(id=server_id) |
|
165 | 176 |
except VirtualMachine.DoesNotExist: |
166 |
raise NotFound |
|
177 |
raise ItemNotFound
|
|
167 | 178 |
|
168 |
server = server_dict(vm, detail=True)
|
|
169 |
return render_server(server, request)
|
|
179 |
serverdict = server_to_dict(server, detail=True)
|
|
180 |
return render_server(request, serverdict)
|
|
170 | 181 |
|
171 |
@api_method |
|
172 |
def update_server_name(request, server_id): |
|
182 |
@api_method('PUT') |
|
183 |
def update_server_name(request, server_id): |
|
184 |
# Normal Response Code: 204 |
|
185 |
# Error Response Codes: computeFault (400, 500), |
|
186 |
# serviceUnavailable (503), |
|
187 |
# unauthorized (401), |
|
188 |
# badRequest (400), |
|
189 |
# badMediaType(415), |
|
190 |
# itemNotFound (404), |
|
191 |
# buildInProgress (409), |
|
192 |
# overLimit (413) |
|
193 |
|
|
173 | 194 |
req = get_request_dict(request) |
174 | 195 |
|
175 | 196 |
try: |
176 | 197 |
name = req['server']['name'] |
177 |
vm = VirtualMachine.objects.get(id=int(server_id)) |
|
198 |
server_id = int(server_id) |
|
199 |
server = VirtualMachine.objects.get(id=server_id) |
|
178 | 200 |
except KeyError: |
179 | 201 |
raise BadRequest |
180 | 202 |
except VirtualMachine.DoesNotExist: |
181 |
raise NotFound |
|
203 |
raise ItemNotFound
|
|
182 | 204 |
|
183 |
vm.name = name
|
|
184 |
vm.save()
|
|
205 |
server.name = name
|
|
206 |
server.save()
|
|
185 | 207 |
|
186 | 208 |
return HttpResponse(status=204) |
187 | 209 |
|
188 |
@api_method |
|
210 |
@api_method('DELETE')
|
|
189 | 211 |
def delete_server(request, server_id): |
212 |
# Normal Response Codes: 204 |
|
213 |
# Error Response Codes: computeFault (400, 500), |
|
214 |
# serviceUnavailable (503), |
|
215 |
# unauthorized (401), |
|
216 |
# itemNotFound (404), |
|
217 |
# unauthorized (401), |
|
218 |
# buildInProgress (409), |
|
219 |
# overLimit (413) |
|
220 |
|
|
190 | 221 |
try: |
191 |
vm = VirtualMachine.objects.get(id=int(server_id)) |
|
222 |
server_id = int(server_id) |
|
223 |
server = VirtualMachine.objects.get(id=server_id) |
|
192 | 224 |
except VirtualMachine.DoesNotExist: |
193 |
raise NotFound |
|
225 |
raise ItemNotFound
|
|
194 | 226 |
|
195 |
vm.start_action('DESTROY') |
|
196 |
rapi.DeleteInstance(vm.backend_id) |
|
197 |
vm.state = 'DESTROYED' |
|
198 |
vm.save() |
|
227 |
server.start_action('DESTROY') |
|
228 |
rapi.DeleteInstance(server.backend_id) |
|
199 | 229 |
return HttpResponse(status=204) |
b/api/templates/flavor.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<flavor xmlns="http://docs.openstack.org/compute/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" id="{{ flavor.id }}" name="{{ flavor.name }}" ram="{{ flavor.ram }}" disk="{{ flavor.disk }}"> |
|
3 |
</flavor> |
b/api/templates/image.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<image xmlns="http://docs.openstack.org/compute/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" id="{{ image.id }}" name="{{ image.name }}" serverRef="{{ image.serverRef }}" updated="{{ image.updated }}" created="{{ image.created }}" status="{{ image.status }}" progress="{{ image.progress }}"> </image> |
b/api/templates/list_flavors.xml | ||
---|---|---|
1 |
{% spaceless %} |
|
2 |
<?xml version="1.0" encoding="UTF-8"?> |
|
3 |
<flavors xmlns="http://docs.openstack.org/compute/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom"> |
|
4 |
{% for flavor in flavors %} |
|
5 |
<flavor id="{{ flavor.id}}" name="{{ flavor.name }}"{% if detail %} ram="{{ flavor.ram }}" disk="{{ flavor.disk }}"{% endif %}> |
|
6 |
</flavor> |
|
7 |
{% endfor %} |
|
8 |
</flavors> |
|
9 |
{% endspaceless %} |
b/api/templates/list_images.xml | ||
---|---|---|
1 |
{% spaceless %} |
|
2 |
<?xml version="1.0" encoding="UTF-8"?> |
|
3 |
<images xmlns="http://docs.openstack.org/compute/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom"> |
|
4 |
{% for image in images %} |
|
5 |
<image id="{{ image.id }}" name="{{ image.name }}"{% if detail %} updated="{{ image.updated }}" created="{{ image.created }}" status="{{ image.status }}"{% endif %}> |
|
6 |
</image> |
|
7 |
{% endfor %} |
|
8 |
</images> |
|
9 |
{% endspaceless %} |
b/api/urls.py | ||
---|---|---|
104 | 104 |
# The OpenStack Compute API v1.1 (REDUX) |
105 | 105 |
v11redux_patterns = patterns('', |
106 | 106 |
(r'^servers', include('synnefo.api.servers')), |
107 |
(r'^flavors', include('synnefo.api.flavors')), |
|
108 |
(r'^images', include('synnefo.api.images')), |
|
107 | 109 |
(r'^.+', notFound), # catch-all |
108 | 110 |
) |
109 | 111 |
|
b/api/util.py | ||
---|---|---|
27 | 27 |
return name if sep else e.tag |
28 | 28 |
|
29 | 29 |
def xml_to_dict(s): |
30 |
# XXX Quick and dirty |
|
30 | 31 |
def _xml_to_dict(e): |
31 | 32 |
root = {} |
32 | 33 |
d = root[tag_name(e)] = dict(e.items()) |
... | ... | |
60 | 61 |
return ''.join(choice(pool) for i in range(length)) |
61 | 62 |
|
62 | 63 |
|
63 |
def render_fault(fault, request):
|
|
64 |
def render_fault(request, fault):
|
|
64 | 65 |
if settings.DEBUG or request.META.get('SERVER_NAME', None) == 'testserver': |
65 | 66 |
fault.details = format_exc(fault) |
66 | 67 |
if request.type == 'xml': |
... | ... | |
72 | 73 |
data = json.dumps(d) |
73 | 74 |
return HttpResponse(data, mimetype=mimetype, status=fault.code) |
74 | 75 |
|
75 |
def api_method(func): |
|
76 |
@wraps(func) |
|
77 |
def wrapper(request, *args, **kwargs): |
|
78 |
try: |
|
79 |
if request.path.endswith('.json'): |
|
80 |
type = 'json' |
|
81 |
elif request.path.endswith('.xml'): |
|
82 |
type = 'xml' |
|
83 |
elif request.META.get('HTTP_ACCEPT', None) == 'application/xml': |
|
84 |
type = 'xml' |
|
85 |
else: |
|
86 |
type = 'json' |
|
87 |
request.type = type |
|
88 |
return func(request, *args, **kwargs) |
|
89 |
except Fault, fault: |
|
90 |
return render_fault(fault, request) |
|
91 |
except Exception, e: |
|
92 |
log.exception('Unexpected error: %s' % e) |
|
93 |
return HttpResponse(status=500) |
|
94 |
return wrapper |
|
76 |
def api_method(http_method): |
|
77 |
def decorator(func): |
|
78 |
@wraps(func) |
|
79 |
def wrapper(request, *args, **kwargs): |
|
80 |
try: |
|
81 |
if request.path.endswith('.json'): |
|
82 |
type = 'json' |
|
83 |
elif request.path.endswith('.xml'): |
|
84 |
type = 'xml' |
|
85 |
elif request.META.get('HTTP_ACCEPT', None) == 'application/xml': |
|
86 |
type = 'xml' |
|
87 |
else: |
|
88 |
type = 'json' |
|
89 |
request.type = type |
|
90 |
|
|
91 |
if request.method != http_method: |
|
92 |
raise BadRequest() |
|
93 |
|
|
94 |
resp = func(request, *args, **kwargs) |
|
95 |
resp['Content-Type'] = 'application/xml' if type == 'xml' else 'application/json' |
|
96 |
return resp |
|
97 |
except Fault, fault: |
|
98 |
return render_fault(request, fault) |
|
99 |
except Exception, e: |
|
100 |
log.exception('Unexpected error: %s' % e) |
|
101 |
fault = ServiceUnavailable() |
|
102 |
return render_fault(request, fault) |
|
103 |
return wrapper |
|
104 |
return decorator |
Also available in: Unified diff