Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / util.py @ 2035039b

History | View | Annotate | Download (10.5 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 3a9b3cde Giorgos Verigakis
from synnefo.plankton.backend import ImageBackend
62 9e98ba3c Giorgos Verigakis
63 9e98ba3c Giorgos Verigakis
64 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
65 9e98ba3c Giorgos Verigakis
66 7e2f9d4b Giorgos Verigakis
67 d8e50a39 Giorgos Verigakis
class UTC(tzinfo):
68 d8e50a39 Giorgos Verigakis
    def utcoffset(self, dt):
69 d8e50a39 Giorgos Verigakis
        return timedelta(0)
70 aa197ee4 Vangelis Koukis
71 d8e50a39 Giorgos Verigakis
    def tzname(self, dt):
72 d8e50a39 Giorgos Verigakis
        return 'UTC'
73 aa197ee4 Vangelis Koukis
74 d8e50a39 Giorgos Verigakis
    def dst(self, dt):
75 d8e50a39 Giorgos Verigakis
        return timedelta(0)
76 7e2f9d4b Giorgos Verigakis
77 7e2f9d4b Giorgos Verigakis
78 d8e50a39 Giorgos Verigakis
def isoformat(d):
79 529178b1 Giorgos Verigakis
    """Return an ISO8601 date string that includes a timezone."""
80 aa197ee4 Vangelis Koukis
81 d8e50a39 Giorgos Verigakis
    return d.replace(tzinfo=UTC()).isoformat()
82 d8e50a39 Giorgos Verigakis
83 a08e4270 Vangelis Koukis
84 d8e50a39 Giorgos Verigakis
def isoparse(s):
85 d8e50a39 Giorgos Verigakis
    """Parse an ISO8601 date string into a datetime object."""
86 aa197ee4 Vangelis Koukis
87 d8e50a39 Giorgos Verigakis
    if not s:
88 d8e50a39 Giorgos Verigakis
        return None
89 aa197ee4 Vangelis Koukis
90 d8e50a39 Giorgos Verigakis
    try:
91 d8e50a39 Giorgos Verigakis
        since = dateutil.parser.parse(s)
92 e87d30f3 Giorgos Verigakis
        utc_since = since.astimezone(UTC()).replace(tzinfo=None)
93 d8e50a39 Giorgos Verigakis
    except ValueError:
94 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid changes-since parameter.')
95 aa197ee4 Vangelis Koukis
96 e87d30f3 Giorgos Verigakis
    now = datetime.datetime.now()
97 e87d30f3 Giorgos Verigakis
    if utc_since > now:
98 d8e50a39 Giorgos Verigakis
        raise BadRequest('changes-since value set in the future.')
99 aa197ee4 Vangelis Koukis
100 e87d30f3 Giorgos Verigakis
    if now - utc_since > timedelta(seconds=settings.POLL_LIMIT):
101 d8e50a39 Giorgos Verigakis
        raise BadRequest('Too old changes-since value.')
102 aa197ee4 Vangelis Koukis
103 0140e54b Vangelis Koukis
    return utc_since
104 aa197ee4 Vangelis Koukis
105 dca2a31f Giorgos Verigakis
106 dca2a31f Giorgos Verigakis
def random_password():
107 dca2a31f Giorgos Verigakis
    """Generates a random password
108 dca2a31f Giorgos Verigakis
    
109 62eac5a6 Giorgos Verigakis
    We generate a windows compliant password: it must contain at least
110 dca2a31f Giorgos Verigakis
    one charachter from each of the groups: upper case, lower case, digits.
111 dca2a31f Giorgos Verigakis
    """
112 dca2a31f Giorgos Verigakis
    
113 dca2a31f Giorgos Verigakis
    pool = lowercase + uppercase + digits
114 dca2a31f Giorgos Verigakis
    lowerset = set(lowercase)
115 dca2a31f Giorgos Verigakis
    upperset = set(uppercase)
116 dca2a31f Giorgos Verigakis
    digitset = set(digits)
117 dca2a31f Giorgos Verigakis
    length = 10
118 dca2a31f Giorgos Verigakis
    
119 62eac5a6 Giorgos Verigakis
    password = ''.join(choice(pool) for i in range(length - 2))
120 62eac5a6 Giorgos Verigakis
    
121 62eac5a6 Giorgos Verigakis
    # Make sure the password is compliant
122 62eac5a6 Giorgos Verigakis
    chars = set(password)
123 62eac5a6 Giorgos Verigakis
    if not chars & lowerset:
124 62eac5a6 Giorgos Verigakis
        password += choice(lowercase)
125 62eac5a6 Giorgos Verigakis
    if not chars & upperset:
126 62eac5a6 Giorgos Verigakis
        password += choice(uppercase)
127 62eac5a6 Giorgos Verigakis
    if not chars & digitset:
128 62eac5a6 Giorgos Verigakis
        password += choice(digits)
129 62eac5a6 Giorgos Verigakis
    
130 62eac5a6 Giorgos Verigakis
    # Pad if necessary to reach required length
131 62eac5a6 Giorgos Verigakis
    password += ''.join(choice(pool) for i in range(length - len(password)))
132 dca2a31f Giorgos Verigakis
    
133 dca2a31f Giorgos Verigakis
    return password
134 dca2a31f Giorgos Verigakis
135 d8e50a39 Giorgos Verigakis
136 c738c935 Giorgos Verigakis
def zeropad(s):
137 c738c935 Giorgos Verigakis
    """Add zeros at the end of a string in order to make its length
138 c738c935 Giorgos Verigakis
       a multiple of 16."""
139 d1387ed7 Christodoulos Psaltis
140 c738c935 Giorgos Verigakis
    npad = 16 - len(s) % 16
141 c738c935 Giorgos Verigakis
    return s + '\x00' * npad
142 c738c935 Giorgos Verigakis
143 a08e4270 Vangelis Koukis
144 c738c935 Giorgos Verigakis
def encrypt(plaintext):
145 c738c935 Giorgos Verigakis
    # Make sure key is 32 bytes long
146 c738c935 Giorgos Verigakis
    key = sha256(settings.SECRET_KEY).digest()
147 d1387ed7 Christodoulos Psaltis
148 c738c935 Giorgos Verigakis
    aes = AES.new(key)
149 c738c935 Giorgos Verigakis
    enc = aes.encrypt(zeropad(plaintext))
150 c738c935 Giorgos Verigakis
    return b64encode(enc)
151 c738c935 Giorgos Verigakis
152 7e2f9d4b Giorgos Verigakis
153 6ef51e9f Giorgos Verigakis
def get_vm(server_id, user_id):
154 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachine instance or raise ItemNotFound."""
155 aa197ee4 Vangelis Koukis
156 d8e50a39 Giorgos Verigakis
    try:
157 d8e50a39 Giorgos Verigakis
        server_id = int(server_id)
158 6ef51e9f Giorgos Verigakis
        return VirtualMachine.objects.get(id=server_id, userid=user_id)
159 d8e50a39 Giorgos Verigakis
    except ValueError:
160 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid server ID.')
161 d8e50a39 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
162 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Server not found.')
163 d8e50a39 Giorgos Verigakis
164 a08e4270 Vangelis Koukis
165 40777cc8 Giorgos Verigakis
def get_vm_meta(vm, key):
166 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachineMetadata instance or raise ItemNotFound."""
167 aa197ee4 Vangelis Koukis
168 d8e50a39 Giorgos Verigakis
    try:
169 40777cc8 Giorgos Verigakis
        return VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
170 d8e50a39 Giorgos Verigakis
    except VirtualMachineMetadata.DoesNotExist:
171 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Metadata key not found.')
172 d8e50a39 Giorgos Verigakis
173 a08e4270 Vangelis Koukis
174 6ef51e9f Giorgos Verigakis
def get_image(image_id, user_id):
175 d8e50a39 Giorgos Verigakis
    """Return an Image instance or raise ItemNotFound."""
176 aa197ee4 Vangelis Koukis
177 6ef51e9f Giorgos Verigakis
    backend = ImageBackend(user_id)
178 d8e50a39 Giorgos Verigakis
    try:
179 6ef51e9f Giorgos Verigakis
        image = backend.get_image(image_id)
180 3a9b3cde Giorgos Verigakis
        if not image:
181 3a9b3cde Giorgos Verigakis
            raise ItemNotFound('Image not found.')
182 3a9b3cde Giorgos Verigakis
        return image
183 3a9b3cde Giorgos Verigakis
    finally:
184 3a9b3cde Giorgos Verigakis
        backend.close()
185 3a9b3cde Giorgos Verigakis
186 a08e4270 Vangelis Koukis
187 529178b1 Giorgos Verigakis
def get_flavor(flavor_id):
188 529178b1 Giorgos Verigakis
    """Return a Flavor instance or raise ItemNotFound."""
189 aa197ee4 Vangelis Koukis
190 529178b1 Giorgos Verigakis
    try:
191 529178b1 Giorgos Verigakis
        flavor_id = int(flavor_id)
192 529178b1 Giorgos Verigakis
        return Flavor.objects.get(id=flavor_id)
193 6ef51e9f Giorgos Verigakis
    except (ValueError, Flavor.DoesNotExist):
194 529178b1 Giorgos Verigakis
        raise ItemNotFound('Flavor not found.')
195 d8e50a39 Giorgos Verigakis
196 a08e4270 Vangelis Koukis
197 6ef51e9f Giorgos Verigakis
def get_network(network_id, user_id):
198 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
199 aa197ee4 Vangelis Koukis
200 e2ee7808 Giorgos Verigakis
    try:
201 d44c236b Giorgos Verigakis
        if network_id == 'public':
202 207b70d5 Giorgos Verigakis
            return Network.objects.get(public=True)
203 207b70d5 Giorgos Verigakis
        else:
204 207b70d5 Giorgos Verigakis
            network_id = int(network_id)
205 6ef51e9f Giorgos Verigakis
            return Network.objects.get(id=network_id, userid=user_id)
206 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
207 e2ee7808 Giorgos Verigakis
        raise ItemNotFound('Network not found.')
208 e2ee7808 Giorgos Verigakis
209 a08e4270 Vangelis Koukis
210 d44c236b Giorgos Verigakis
def get_nic(machine, network):
211 d44c236b Giorgos Verigakis
    try:
212 d44c236b Giorgos Verigakis
        return NetworkInterface.objects.get(machine=machine, network=network)
213 d44c236b Giorgos Verigakis
    except NetworkInterface.DoesNotExist:
214 d44c236b Giorgos Verigakis
        raise ItemNotFound('Server not connected to this network.')
215 d44c236b Giorgos Verigakis
216 e2ee7808 Giorgos Verigakis
217 7e2f9d4b Giorgos Verigakis
def get_request_dict(request):
218 d8e50a39 Giorgos Verigakis
    """Returns data sent by the client as a python dict."""
219 aa197ee4 Vangelis Koukis
220 7e2f9d4b Giorgos Verigakis
    data = request.raw_post_data
221 7e45ddef Dimitris Moraitis
    if request.META.get('CONTENT_TYPE').startswith('application/json'):
222 7e2f9d4b Giorgos Verigakis
        try:
223 7e2f9d4b Giorgos Verigakis
            return json.loads(data)
224 7e2f9d4b Giorgos Verigakis
        except ValueError:
225 d8e50a39 Giorgos Verigakis
            raise BadRequest('Invalid JSON data.')
226 d8e50a39 Giorgos Verigakis
    else:
227 d8e50a39 Giorgos Verigakis
        raise BadRequest('Unsupported Content-Type.')
228 7e2f9d4b Giorgos Verigakis
229 a08e4270 Vangelis Koukis
230 8b01f7f3 Giorgos Verigakis
def update_response_headers(request, response):
231 8b01f7f3 Giorgos Verigakis
    if request.serialization == 'xml':
232 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/xml'
233 8b01f7f3 Giorgos Verigakis
    elif request.serialization == 'atom':
234 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/atom+xml'
235 8b01f7f3 Giorgos Verigakis
    else:
236 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/json'
237 aa197ee4 Vangelis Koukis
238 4cf8adf8 Vangelis Koukis
    if settings.TEST:
239 cdb65551 Giorgos Verigakis
        response['Date'] = format_date_time(time())
240 b75555e5 Giorgos Verigakis
    
241 b75555e5 Giorgos Verigakis
    add_never_cache_headers(response)
242 b75555e5 Giorgos Verigakis
243 8b01f7f3 Giorgos Verigakis
244 432fc8c3 Giorgos Verigakis
def render_metadata(request, metadata, use_values=False, status=200):
245 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
246 432fc8c3 Giorgos Verigakis
        data = render_to_string('metadata.xml', {'metadata': metadata})
247 432fc8c3 Giorgos Verigakis
    else:
248 b36f78fa Giorgos Verigakis
        if use_values:
249 b36f78fa Giorgos Verigakis
            d = {'metadata': {'values': metadata}}
250 b36f78fa Giorgos Verigakis
        else:
251 b36f78fa Giorgos Verigakis
            d = {'metadata': metadata}
252 432fc8c3 Giorgos Verigakis
        data = json.dumps(d)
253 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
254 432fc8c3 Giorgos Verigakis
255 a08e4270 Vangelis Koukis
256 432fc8c3 Giorgos Verigakis
def render_meta(request, meta, status=200):
257 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
258 6ef51e9f Giorgos Verigakis
        data = render_to_string('meta.xml', dict(key=key, val=val))
259 432fc8c3 Giorgos Verigakis
    else:
260 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(meta=meta))
261 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
262 432fc8c3 Giorgos Verigakis
263 a08e4270 Vangelis Koukis
264 c36934a7 Giorgos Verigakis
def render_fault(request, fault):
265 4cf8adf8 Vangelis Koukis
    if settings.DEBUG or settings.TEST:
266 7e2f9d4b Giorgos Verigakis
        fault.details = format_exc(fault)
267 aa197ee4 Vangelis Koukis
268 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
269 d8e50a39 Giorgos Verigakis
        data = render_to_string('fault.xml', {'fault': fault})
270 7e2f9d4b Giorgos Verigakis
    else:
271 b36f78fa Giorgos Verigakis
        d = {fault.name: {
272 b36f78fa Giorgos Verigakis
                'code': fault.code,
273 b36f78fa Giorgos Verigakis
                'message': fault.message,
274 b36f78fa Giorgos Verigakis
                'details': fault.details}}
275 7e2f9d4b Giorgos Verigakis
        data = json.dumps(d)
276 aa197ee4 Vangelis Koukis
277 f0656db1 Giorgos Verigakis
    resp = HttpResponse(data, status=fault.code)
278 8b01f7f3 Giorgos Verigakis
    update_response_headers(request, resp)
279 f0656db1 Giorgos Verigakis
    return resp
280 d8e50a39 Giorgos Verigakis
281 432fc8c3 Giorgos Verigakis
282 d8e50a39 Giorgos Verigakis
def request_serialization(request, atom_allowed=False):
283 d8e50a39 Giorgos Verigakis
    """Return the serialization format requested.
284 aa197ee4 Vangelis Koukis

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