Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / util.py @ 0ed12c27

History | View | Annotate | Download (10.6 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 d1387ed7 Christodoulos Psaltis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 d1387ed7 Christodoulos Psaltis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 d1387ed7 Christodoulos Psaltis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 d1387ed7 Christodoulos Psaltis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 d1387ed7 Christodoulos Psaltis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 7e2f9d4b Giorgos Verigakis
34 c738c935 Giorgos Verigakis
import datetime
35 c738c935 Giorgos Verigakis
36 c738c935 Giorgos Verigakis
from base64 import b64encode
37 d8e50a39 Giorgos Verigakis
from datetime import timedelta, tzinfo
38 d8e50a39 Giorgos Verigakis
from functools import wraps
39 c738c935 Giorgos Verigakis
from hashlib import sha256
40 2035039b Giorgos Verigakis
from logging import getLogger
41 d8e50a39 Giorgos Verigakis
from random import choice
42 dca2a31f Giorgos Verigakis
from string import digits, lowercase, uppercase
43 8b01f7f3 Giorgos Verigakis
from time import time
44 d8e50a39 Giorgos Verigakis
from traceback import format_exc
45 8b01f7f3 Giorgos Verigakis
from wsgiref.handlers import format_date_time
46 7e2f9d4b Giorgos Verigakis
47 2035039b Giorgos Verigakis
import dateutil.parser
48 2035039b Giorgos Verigakis
49 c738c935 Giorgos Verigakis
from Crypto.Cipher import AES
50 529178b1 Giorgos Verigakis
51 d8e50a39 Giorgos Verigakis
from django.conf import settings
52 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
53 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
54 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
55 b75555e5 Giorgos Verigakis
from django.utils.cache import add_never_cache_headers
56 7e2f9d4b Giorgos Verigakis
57 b36f78fa Giorgos Verigakis
from synnefo.api.faults import (Fault, BadRequest, BuildInProgress,
58 b36f78fa Giorgos Verigakis
                                ItemNotFound, ServiceUnavailable, Unauthorized)
59 6ef51e9f Giorgos Verigakis
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
60 6ef51e9f Giorgos Verigakis
                               Network, NetworkInterface)
61 4b3b8688 Giorgos Verigakis
from synnefo.lib.astakos import get_user
62 3a9b3cde Giorgos Verigakis
from synnefo.plankton.backend import ImageBackend
63 9e98ba3c Giorgos Verigakis
64 9e98ba3c Giorgos Verigakis
65 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
66 9e98ba3c Giorgos Verigakis
67 7e2f9d4b Giorgos Verigakis
68 d8e50a39 Giorgos Verigakis
class UTC(tzinfo):
69 d8e50a39 Giorgos Verigakis
    def utcoffset(self, dt):
70 d8e50a39 Giorgos Verigakis
        return timedelta(0)
71 aa197ee4 Vangelis Koukis
72 d8e50a39 Giorgos Verigakis
    def tzname(self, dt):
73 d8e50a39 Giorgos Verigakis
        return 'UTC'
74 aa197ee4 Vangelis Koukis
75 d8e50a39 Giorgos Verigakis
    def dst(self, dt):
76 d8e50a39 Giorgos Verigakis
        return timedelta(0)
77 7e2f9d4b Giorgos Verigakis
78 7e2f9d4b Giorgos Verigakis
79 d8e50a39 Giorgos Verigakis
def isoformat(d):
80 529178b1 Giorgos Verigakis
    """Return an ISO8601 date string that includes a timezone."""
81 aa197ee4 Vangelis Koukis
82 d8e50a39 Giorgos Verigakis
    return d.replace(tzinfo=UTC()).isoformat()
83 d8e50a39 Giorgos Verigakis
84 a08e4270 Vangelis Koukis
85 d8e50a39 Giorgos Verigakis
def isoparse(s):
86 d8e50a39 Giorgos Verigakis
    """Parse an ISO8601 date string into a datetime object."""
87 aa197ee4 Vangelis Koukis
88 d8e50a39 Giorgos Verigakis
    if not s:
89 d8e50a39 Giorgos Verigakis
        return None
90 aa197ee4 Vangelis Koukis
91 d8e50a39 Giorgos Verigakis
    try:
92 d8e50a39 Giorgos Verigakis
        since = dateutil.parser.parse(s)
93 e87d30f3 Giorgos Verigakis
        utc_since = since.astimezone(UTC()).replace(tzinfo=None)
94 d8e50a39 Giorgos Verigakis
    except ValueError:
95 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid changes-since parameter.')
96 aa197ee4 Vangelis Koukis
97 e87d30f3 Giorgos Verigakis
    now = datetime.datetime.now()
98 e87d30f3 Giorgos Verigakis
    if utc_since > now:
99 d8e50a39 Giorgos Verigakis
        raise BadRequest('changes-since value set in the future.')
100 aa197ee4 Vangelis Koukis
101 e87d30f3 Giorgos Verigakis
    if now - utc_since > timedelta(seconds=settings.POLL_LIMIT):
102 d8e50a39 Giorgos Verigakis
        raise BadRequest('Too old changes-since value.')
103 aa197ee4 Vangelis Koukis
104 0140e54b Vangelis Koukis
    return utc_since
105 aa197ee4 Vangelis Koukis
106 dca2a31f Giorgos Verigakis
107 dca2a31f Giorgos Verigakis
def random_password():
108 dca2a31f Giorgos Verigakis
    """Generates a random password
109 dca2a31f Giorgos Verigakis
    
110 62eac5a6 Giorgos Verigakis
    We generate a windows compliant password: it must contain at least
111 dca2a31f Giorgos Verigakis
    one charachter from each of the groups: upper case, lower case, digits.
112 dca2a31f Giorgos Verigakis
    """
113 dca2a31f Giorgos Verigakis
    
114 dca2a31f Giorgos Verigakis
    pool = lowercase + uppercase + digits
115 dca2a31f Giorgos Verigakis
    lowerset = set(lowercase)
116 dca2a31f Giorgos Verigakis
    upperset = set(uppercase)
117 dca2a31f Giorgos Verigakis
    digitset = set(digits)
118 dca2a31f Giorgos Verigakis
    length = 10
119 dca2a31f Giorgos Verigakis
    
120 62eac5a6 Giorgos Verigakis
    password = ''.join(choice(pool) for i in range(length - 2))
121 62eac5a6 Giorgos Verigakis
    
122 62eac5a6 Giorgos Verigakis
    # Make sure the password is compliant
123 62eac5a6 Giorgos Verigakis
    chars = set(password)
124 62eac5a6 Giorgos Verigakis
    if not chars & lowerset:
125 62eac5a6 Giorgos Verigakis
        password += choice(lowercase)
126 62eac5a6 Giorgos Verigakis
    if not chars & upperset:
127 62eac5a6 Giorgos Verigakis
        password += choice(uppercase)
128 62eac5a6 Giorgos Verigakis
    if not chars & digitset:
129 62eac5a6 Giorgos Verigakis
        password += choice(digits)
130 62eac5a6 Giorgos Verigakis
    
131 62eac5a6 Giorgos Verigakis
    # Pad if necessary to reach required length
132 62eac5a6 Giorgos Verigakis
    password += ''.join(choice(pool) for i in range(length - len(password)))
133 dca2a31f Giorgos Verigakis
    
134 dca2a31f Giorgos Verigakis
    return password
135 dca2a31f Giorgos Verigakis
136 d8e50a39 Giorgos Verigakis
137 c738c935 Giorgos Verigakis
def zeropad(s):
138 c738c935 Giorgos Verigakis
    """Add zeros at the end of a string in order to make its length
139 c738c935 Giorgos Verigakis
       a multiple of 16."""
140 d1387ed7 Christodoulos Psaltis
141 c738c935 Giorgos Verigakis
    npad = 16 - len(s) % 16
142 c738c935 Giorgos Verigakis
    return s + '\x00' * npad
143 c738c935 Giorgos Verigakis
144 a08e4270 Vangelis Koukis
145 c738c935 Giorgos Verigakis
def encrypt(plaintext):
146 c738c935 Giorgos Verigakis
    # Make sure key is 32 bytes long
147 c738c935 Giorgos Verigakis
    key = sha256(settings.SECRET_KEY).digest()
148 d1387ed7 Christodoulos Psaltis
149 c738c935 Giorgos Verigakis
    aes = AES.new(key)
150 c738c935 Giorgos Verigakis
    enc = aes.encrypt(zeropad(plaintext))
151 c738c935 Giorgos Verigakis
    return b64encode(enc)
152 c738c935 Giorgos Verigakis
153 7e2f9d4b Giorgos Verigakis
154 6ef51e9f Giorgos Verigakis
def get_vm(server_id, user_id):
155 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachine instance or raise ItemNotFound."""
156 aa197ee4 Vangelis Koukis
157 d8e50a39 Giorgos Verigakis
    try:
158 d8e50a39 Giorgos Verigakis
        server_id = int(server_id)
159 6ef51e9f Giorgos Verigakis
        return VirtualMachine.objects.get(id=server_id, userid=user_id)
160 d8e50a39 Giorgos Verigakis
    except ValueError:
161 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid server ID.')
162 d8e50a39 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
163 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Server not found.')
164 d8e50a39 Giorgos Verigakis
165 a08e4270 Vangelis Koukis
166 40777cc8 Giorgos Verigakis
def get_vm_meta(vm, key):
167 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachineMetadata instance or raise ItemNotFound."""
168 aa197ee4 Vangelis Koukis
169 d8e50a39 Giorgos Verigakis
    try:
170 40777cc8 Giorgos Verigakis
        return VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
171 d8e50a39 Giorgos Verigakis
    except VirtualMachineMetadata.DoesNotExist:
172 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Metadata key not found.')
173 d8e50a39 Giorgos Verigakis
174 a08e4270 Vangelis Koukis
175 6ef51e9f Giorgos Verigakis
def get_image(image_id, user_id):
176 d8e50a39 Giorgos Verigakis
    """Return an Image instance or raise ItemNotFound."""
177 aa197ee4 Vangelis Koukis
178 6ef51e9f Giorgos Verigakis
    backend = ImageBackend(user_id)
179 d8e50a39 Giorgos Verigakis
    try:
180 6ef51e9f Giorgos Verigakis
        image = backend.get_image(image_id)
181 3a9b3cde Giorgos Verigakis
        if not image:
182 3a9b3cde Giorgos Verigakis
            raise ItemNotFound('Image not found.')
183 3a9b3cde Giorgos Verigakis
        return image
184 3a9b3cde Giorgos Verigakis
    finally:
185 3a9b3cde Giorgos Verigakis
        backend.close()
186 3a9b3cde Giorgos Verigakis
187 a08e4270 Vangelis Koukis
188 529178b1 Giorgos Verigakis
def get_flavor(flavor_id):
189 529178b1 Giorgos Verigakis
    """Return a Flavor instance or raise ItemNotFound."""
190 aa197ee4 Vangelis Koukis
191 529178b1 Giorgos Verigakis
    try:
192 529178b1 Giorgos Verigakis
        flavor_id = int(flavor_id)
193 529178b1 Giorgos Verigakis
        return Flavor.objects.get(id=flavor_id)
194 6ef51e9f Giorgos Verigakis
    except (ValueError, Flavor.DoesNotExist):
195 529178b1 Giorgos Verigakis
        raise ItemNotFound('Flavor not found.')
196 d8e50a39 Giorgos Verigakis
197 a08e4270 Vangelis Koukis
198 6ef51e9f Giorgos Verigakis
def get_network(network_id, user_id):
199 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
200 aa197ee4 Vangelis Koukis
201 e2ee7808 Giorgos Verigakis
    try:
202 d44c236b Giorgos Verigakis
        if network_id == 'public':
203 207b70d5 Giorgos Verigakis
            return Network.objects.get(public=True)
204 207b70d5 Giorgos Verigakis
        else:
205 207b70d5 Giorgos Verigakis
            network_id = int(network_id)
206 6ef51e9f Giorgos Verigakis
            return Network.objects.get(id=network_id, userid=user_id)
207 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
208 e2ee7808 Giorgos Verigakis
        raise ItemNotFound('Network not found.')
209 e2ee7808 Giorgos Verigakis
210 a08e4270 Vangelis Koukis
211 d44c236b Giorgos Verigakis
def get_nic(machine, network):
212 d44c236b Giorgos Verigakis
    try:
213 d44c236b Giorgos Verigakis
        return NetworkInterface.objects.get(machine=machine, network=network)
214 d44c236b Giorgos Verigakis
    except NetworkInterface.DoesNotExist:
215 d44c236b Giorgos Verigakis
        raise ItemNotFound('Server not connected to this network.')
216 d44c236b Giorgos Verigakis
217 e2ee7808 Giorgos Verigakis
218 7e2f9d4b Giorgos Verigakis
def get_request_dict(request):
219 d8e50a39 Giorgos Verigakis
    """Returns data sent by the client as a python dict."""
220 aa197ee4 Vangelis Koukis
221 7e2f9d4b Giorgos Verigakis
    data = request.raw_post_data
222 7e45ddef Dimitris Moraitis
    if request.META.get('CONTENT_TYPE').startswith('application/json'):
223 7e2f9d4b Giorgos Verigakis
        try:
224 7e2f9d4b Giorgos Verigakis
            return json.loads(data)
225 7e2f9d4b Giorgos Verigakis
        except ValueError:
226 d8e50a39 Giorgos Verigakis
            raise BadRequest('Invalid JSON data.')
227 d8e50a39 Giorgos Verigakis
    else:
228 d8e50a39 Giorgos Verigakis
        raise BadRequest('Unsupported Content-Type.')
229 7e2f9d4b Giorgos Verigakis
230 a08e4270 Vangelis Koukis
231 8b01f7f3 Giorgos Verigakis
def update_response_headers(request, response):
232 8b01f7f3 Giorgos Verigakis
    if request.serialization == 'xml':
233 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/xml'
234 8b01f7f3 Giorgos Verigakis
    elif request.serialization == 'atom':
235 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/atom+xml'
236 8b01f7f3 Giorgos Verigakis
    else:
237 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/json'
238 aa197ee4 Vangelis Koukis
239 4cf8adf8 Vangelis Koukis
    if settings.TEST:
240 cdb65551 Giorgos Verigakis
        response['Date'] = format_date_time(time())
241 b75555e5 Giorgos Verigakis
    
242 b75555e5 Giorgos Verigakis
    add_never_cache_headers(response)
243 b75555e5 Giorgos Verigakis
244 8b01f7f3 Giorgos Verigakis
245 432fc8c3 Giorgos Verigakis
def render_metadata(request, metadata, use_values=False, status=200):
246 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
247 432fc8c3 Giorgos Verigakis
        data = render_to_string('metadata.xml', {'metadata': metadata})
248 432fc8c3 Giorgos Verigakis
    else:
249 b36f78fa Giorgos Verigakis
        if use_values:
250 b36f78fa Giorgos Verigakis
            d = {'metadata': {'values': metadata}}
251 b36f78fa Giorgos Verigakis
        else:
252 b36f78fa Giorgos Verigakis
            d = {'metadata': metadata}
253 432fc8c3 Giorgos Verigakis
        data = json.dumps(d)
254 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
255 432fc8c3 Giorgos Verigakis
256 a08e4270 Vangelis Koukis
257 432fc8c3 Giorgos Verigakis
def render_meta(request, meta, status=200):
258 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
259 6ef51e9f Giorgos Verigakis
        data = render_to_string('meta.xml', dict(key=key, val=val))
260 432fc8c3 Giorgos Verigakis
    else:
261 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(meta=meta))
262 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
263 432fc8c3 Giorgos Verigakis
264 a08e4270 Vangelis Koukis
265 c36934a7 Giorgos Verigakis
def render_fault(request, fault):
266 4cf8adf8 Vangelis Koukis
    if settings.DEBUG or settings.TEST:
267 7e2f9d4b Giorgos Verigakis
        fault.details = format_exc(fault)
268 aa197ee4 Vangelis Koukis
269 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
270 d8e50a39 Giorgos Verigakis
        data = render_to_string('fault.xml', {'fault': fault})
271 7e2f9d4b Giorgos Verigakis
    else:
272 b36f78fa Giorgos Verigakis
        d = {fault.name: {
273 b36f78fa Giorgos Verigakis
                'code': fault.code,
274 b36f78fa Giorgos Verigakis
                'message': fault.message,
275 b36f78fa Giorgos Verigakis
                'details': fault.details}}
276 7e2f9d4b Giorgos Verigakis
        data = json.dumps(d)
277 aa197ee4 Vangelis Koukis
278 f0656db1 Giorgos Verigakis
    resp = HttpResponse(data, status=fault.code)
279 8b01f7f3 Giorgos Verigakis
    update_response_headers(request, resp)
280 f0656db1 Giorgos Verigakis
    return resp
281 d8e50a39 Giorgos Verigakis
282 432fc8c3 Giorgos Verigakis
283 d8e50a39 Giorgos Verigakis
def request_serialization(request, atom_allowed=False):
284 d8e50a39 Giorgos Verigakis
    """Return the serialization format requested.
285 aa197ee4 Vangelis Koukis

286 529178b1 Giorgos Verigakis
    Valid formats are 'json', 'xml' and 'atom' if `atom_allowed` is True.
287 d8e50a39 Giorgos Verigakis
    """
288 aa197ee4 Vangelis Koukis
289 d8e50a39 Giorgos Verigakis
    path = request.path
290 aa197ee4 Vangelis Koukis
291 d8e50a39 Giorgos Verigakis
    if path.endswith('.json'):
292 d8e50a39 Giorgos Verigakis
        return 'json'
293 d8e50a39 Giorgos Verigakis
    elif path.endswith('.xml'):
294 d8e50a39 Giorgos Verigakis
        return 'xml'
295 d8e50a39 Giorgos Verigakis
    elif atom_allowed and path.endswith('.atom'):
296 d8e50a39 Giorgos Verigakis
        return 'atom'
297 aa197ee4 Vangelis Koukis
298 d8e50a39 Giorgos Verigakis
    for item in request.META.get('HTTP_ACCEPT', '').split(','):
299 d8e50a39 Giorgos Verigakis
        accept, sep, rest = item.strip().partition(';')
300 d8e50a39 Giorgos Verigakis
        if accept == 'application/json':
301 d8e50a39 Giorgos Verigakis
            return 'json'
302 d8e50a39 Giorgos Verigakis
        elif accept == 'application/xml':
303 d8e50a39 Giorgos Verigakis
            return 'xml'
304 d8e50a39 Giorgos Verigakis
        elif atom_allowed and accept == 'application/atom+xml':
305 d8e50a39 Giorgos Verigakis
            return 'atom'
306 aa197ee4 Vangelis Koukis
307 d8e50a39 Giorgos Verigakis
    return 'json'
308 7e2f9d4b Giorgos Verigakis
309 a08e4270 Vangelis Koukis
310 d8e50a39 Giorgos Verigakis
def api_method(http_method=None, atom_allowed=False):
311 d8e50a39 Giorgos Verigakis
    """Decorator function for views that implement an API method."""
312 aa197ee4 Vangelis Koukis
313 c36934a7 Giorgos Verigakis
    def decorator(func):
314 c36934a7 Giorgos Verigakis
        @wraps(func)
315 c36934a7 Giorgos Verigakis
        def wrapper(request, *args, **kwargs):
316 c36934a7 Giorgos Verigakis
            try:
317 6ef51e9f Giorgos Verigakis
                request.serialization = request_serialization(request,
318 6ef51e9f Giorgos Verigakis
                                                              atom_allowed)
319 4b3b8688 Giorgos Verigakis
                get_user(request, settings.ASTAKOS_URL)
320 4b3b8688 Giorgos Verigakis
                if not request.user_uniq:
321 40777cc8 Giorgos Verigakis
                    raise Unauthorized('No user found.')
322 d8e50a39 Giorgos Verigakis
                if http_method and request.method != http_method:
323 d8e50a39 Giorgos Verigakis
                    raise BadRequest('Method not allowed.')
324 aa197ee4 Vangelis Koukis
325 c36934a7 Giorgos Verigakis
                resp = func(request, *args, **kwargs)
326 8b01f7f3 Giorgos Verigakis
                update_response_headers(request, resp)
327 c36934a7 Giorgos Verigakis
                return resp
328 5231a38a Giorgos Verigakis
            except VirtualMachine.DeletedError:
329 5231a38a Giorgos Verigakis
                fault = BadRequest('Server has been deleted.')
330 5231a38a Giorgos Verigakis
                return render_fault(request, fault)
331 5231a38a Giorgos Verigakis
            except VirtualMachine.BuildingError:
332 5231a38a Giorgos Verigakis
                fault = BuildInProgress('Server is being built.')
333 5231a38a Giorgos Verigakis
                return render_fault(request, fault)
334 c36934a7 Giorgos Verigakis
            except Fault, fault:
335 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
336 a62a4d20 Giorgos Verigakis
            except BaseException, e:
337 9e98ba3c Giorgos Verigakis
                log.exception('Unexpected error')
338 529178b1 Giorgos Verigakis
                fault = ServiceUnavailable('Unexpected error.')
339 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
340 c36934a7 Giorgos Verigakis
        return wrapper
341 c36934a7 Giorgos Verigakis
    return decorator