Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (13.2 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 6dd70a5c Christos Stavrakakis
                                ItemNotFound, ServiceUnavailable, Unauthorized,
59 7fede91e Christos Stavrakakis
                                BadMediaType)
60 6ef51e9f Giorgos Verigakis
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
61 7fede91e Christos Stavrakakis
                               Network, BackendNetwork, NetworkInterface,
62 af6a3bc5 Christos Stavrakakis
                               BridgePoolTable, MacPrefixPoolTable)
63 adc46059 Christos Stavrakakis
from synnefo.db.pools import EmptyPool
64 6dd70a5c Christos Stavrakakis
65 4b3b8688 Giorgos Verigakis
from synnefo.lib.astakos import get_user
66 3a9b3cde Giorgos Verigakis
from synnefo.plankton.backend import ImageBackend
67 b14725eb Christos Stavrakakis
from synnefo.settings import MAX_CIDR_BLOCK
68 9e98ba3c Giorgos Verigakis
69 9e98ba3c Giorgos Verigakis
70 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
71 9e98ba3c Giorgos Verigakis
72 7e2f9d4b Giorgos Verigakis
73 d8e50a39 Giorgos Verigakis
class UTC(tzinfo):
74 d8e50a39 Giorgos Verigakis
    def utcoffset(self, dt):
75 d8e50a39 Giorgos Verigakis
        return timedelta(0)
76 aa197ee4 Vangelis Koukis
77 d8e50a39 Giorgos Verigakis
    def tzname(self, dt):
78 d8e50a39 Giorgos Verigakis
        return 'UTC'
79 aa197ee4 Vangelis Koukis
80 d8e50a39 Giorgos Verigakis
    def dst(self, dt):
81 d8e50a39 Giorgos Verigakis
        return timedelta(0)
82 7e2f9d4b Giorgos Verigakis
83 7e2f9d4b Giorgos Verigakis
84 d8e50a39 Giorgos Verigakis
def isoformat(d):
85 529178b1 Giorgos Verigakis
    """Return an ISO8601 date string that includes a timezone."""
86 aa197ee4 Vangelis Koukis
87 d8e50a39 Giorgos Verigakis
    return d.replace(tzinfo=UTC()).isoformat()
88 d8e50a39 Giorgos Verigakis
89 a08e4270 Vangelis Koukis
90 d8e50a39 Giorgos Verigakis
def isoparse(s):
91 d8e50a39 Giorgos Verigakis
    """Parse an ISO8601 date string into a datetime object."""
92 aa197ee4 Vangelis Koukis
93 d8e50a39 Giorgos Verigakis
    if not s:
94 d8e50a39 Giorgos Verigakis
        return None
95 aa197ee4 Vangelis Koukis
96 d8e50a39 Giorgos Verigakis
    try:
97 d8e50a39 Giorgos Verigakis
        since = dateutil.parser.parse(s)
98 e87d30f3 Giorgos Verigakis
        utc_since = since.astimezone(UTC()).replace(tzinfo=None)
99 d8e50a39 Giorgos Verigakis
    except ValueError:
100 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid changes-since parameter.')
101 aa197ee4 Vangelis Koukis
102 e87d30f3 Giorgos Verigakis
    now = datetime.datetime.now()
103 e87d30f3 Giorgos Verigakis
    if utc_since > now:
104 d8e50a39 Giorgos Verigakis
        raise BadRequest('changes-since value set in the future.')
105 aa197ee4 Vangelis Koukis
106 e87d30f3 Giorgos Verigakis
    if now - utc_since > timedelta(seconds=settings.POLL_LIMIT):
107 d8e50a39 Giorgos Verigakis
        raise BadRequest('Too old changes-since value.')
108 aa197ee4 Vangelis Koukis
109 0140e54b Vangelis Koukis
    return utc_since
110 aa197ee4 Vangelis Koukis
111 dca2a31f Giorgos Verigakis
112 dca2a31f Giorgos Verigakis
def random_password():
113 dca2a31f Giorgos Verigakis
    """Generates a random password
114 ce55f211 Kostas Papadimitriou

115 62eac5a6 Giorgos Verigakis
    We generate a windows compliant password: it must contain at least
116 dca2a31f Giorgos Verigakis
    one charachter from each of the groups: upper case, lower case, digits.
117 dca2a31f Giorgos Verigakis
    """
118 ce55f211 Kostas Papadimitriou
119 dca2a31f Giorgos Verigakis
    pool = lowercase + uppercase + digits
120 dca2a31f Giorgos Verigakis
    lowerset = set(lowercase)
121 dca2a31f Giorgos Verigakis
    upperset = set(uppercase)
122 dca2a31f Giorgos Verigakis
    digitset = set(digits)
123 dca2a31f Giorgos Verigakis
    length = 10
124 ce55f211 Kostas Papadimitriou
125 62eac5a6 Giorgos Verigakis
    password = ''.join(choice(pool) for i in range(length - 2))
126 ce55f211 Kostas Papadimitriou
127 62eac5a6 Giorgos Verigakis
    # Make sure the password is compliant
128 62eac5a6 Giorgos Verigakis
    chars = set(password)
129 62eac5a6 Giorgos Verigakis
    if not chars & lowerset:
130 62eac5a6 Giorgos Verigakis
        password += choice(lowercase)
131 62eac5a6 Giorgos Verigakis
    if not chars & upperset:
132 62eac5a6 Giorgos Verigakis
        password += choice(uppercase)
133 62eac5a6 Giorgos Verigakis
    if not chars & digitset:
134 62eac5a6 Giorgos Verigakis
        password += choice(digits)
135 ce55f211 Kostas Papadimitriou
136 62eac5a6 Giorgos Verigakis
    # Pad if necessary to reach required length
137 62eac5a6 Giorgos Verigakis
    password += ''.join(choice(pool) for i in range(length - len(password)))
138 ce55f211 Kostas Papadimitriou
139 dca2a31f Giorgos Verigakis
    return password
140 dca2a31f Giorgos Verigakis
141 d8e50a39 Giorgos Verigakis
142 c738c935 Giorgos Verigakis
def zeropad(s):
143 c738c935 Giorgos Verigakis
    """Add zeros at the end of a string in order to make its length
144 c738c935 Giorgos Verigakis
       a multiple of 16."""
145 d1387ed7 Christodoulos Psaltis
146 c738c935 Giorgos Verigakis
    npad = 16 - len(s) % 16
147 c738c935 Giorgos Verigakis
    return s + '\x00' * npad
148 c738c935 Giorgos Verigakis
149 a08e4270 Vangelis Koukis
150 c738c935 Giorgos Verigakis
def encrypt(plaintext):
151 c738c935 Giorgos Verigakis
    # Make sure key is 32 bytes long
152 c738c935 Giorgos Verigakis
    key = sha256(settings.SECRET_KEY).digest()
153 d1387ed7 Christodoulos Psaltis
154 c738c935 Giorgos Verigakis
    aes = AES.new(key)
155 c738c935 Giorgos Verigakis
    enc = aes.encrypt(zeropad(plaintext))
156 c738c935 Giorgos Verigakis
    return b64encode(enc)
157 c738c935 Giorgos Verigakis
158 7e2f9d4b Giorgos Verigakis
159 6ef51e9f Giorgos Verigakis
def get_vm(server_id, user_id):
160 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachine instance or raise ItemNotFound."""
161 aa197ee4 Vangelis Koukis
162 d8e50a39 Giorgos Verigakis
    try:
163 d8e50a39 Giorgos Verigakis
        server_id = int(server_id)
164 6ef51e9f Giorgos Verigakis
        return VirtualMachine.objects.get(id=server_id, userid=user_id)
165 d8e50a39 Giorgos Verigakis
    except ValueError:
166 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid server ID.')
167 d8e50a39 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
168 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Server not found.')
169 d8e50a39 Giorgos Verigakis
170 a08e4270 Vangelis Koukis
171 40777cc8 Giorgos Verigakis
def get_vm_meta(vm, key):
172 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachineMetadata instance or raise ItemNotFound."""
173 aa197ee4 Vangelis Koukis
174 d8e50a39 Giorgos Verigakis
    try:
175 40777cc8 Giorgos Verigakis
        return VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
176 d8e50a39 Giorgos Verigakis
    except VirtualMachineMetadata.DoesNotExist:
177 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Metadata key not found.')
178 d8e50a39 Giorgos Verigakis
179 a08e4270 Vangelis Koukis
180 6ef51e9f Giorgos Verigakis
def get_image(image_id, user_id):
181 d8e50a39 Giorgos Verigakis
    """Return an Image instance or raise ItemNotFound."""
182 aa197ee4 Vangelis Koukis
183 6ef51e9f Giorgos Verigakis
    backend = ImageBackend(user_id)
184 d8e50a39 Giorgos Verigakis
    try:
185 6ef51e9f Giorgos Verigakis
        image = backend.get_image(image_id)
186 3a9b3cde Giorgos Verigakis
        if not image:
187 3a9b3cde Giorgos Verigakis
            raise ItemNotFound('Image not found.')
188 3a9b3cde Giorgos Verigakis
        return image
189 3a9b3cde Giorgos Verigakis
    finally:
190 3a9b3cde Giorgos Verigakis
        backend.close()
191 3a9b3cde Giorgos Verigakis
192 a08e4270 Vangelis Koukis
193 529178b1 Giorgos Verigakis
def get_flavor(flavor_id):
194 529178b1 Giorgos Verigakis
    """Return a Flavor instance or raise ItemNotFound."""
195 aa197ee4 Vangelis Koukis
196 529178b1 Giorgos Verigakis
    try:
197 529178b1 Giorgos Verigakis
        flavor_id = int(flavor_id)
198 529178b1 Giorgos Verigakis
        return Flavor.objects.get(id=flavor_id)
199 6ef51e9f Giorgos Verigakis
    except (ValueError, Flavor.DoesNotExist):
200 529178b1 Giorgos Verigakis
        raise ItemNotFound('Flavor not found.')
201 d8e50a39 Giorgos Verigakis
202 a08e4270 Vangelis Koukis
203 d2e73c0c Christos Stavrakakis
def get_network(network_id, user_id, for_update=False):
204 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
205 aa197ee4 Vangelis Koukis
206 e2ee7808 Giorgos Verigakis
    try:
207 7fede91e Christos Stavrakakis
        network_id = int(network_id)
208 d2e73c0c Christos Stavrakakis
        if for_update:
209 d2e73c0c Christos Stavrakakis
            return Network.objects.select_for_update().get(id=network_id, userid=user_id)
210 d2e73c0c Christos Stavrakakis
        else:
211 d2e73c0c Christos Stavrakakis
            return Network.objects.get(id=network_id, userid=user_id)
212 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
213 e2ee7808 Giorgos Verigakis
        raise ItemNotFound('Network not found.')
214 e2ee7808 Giorgos Verigakis
215 a08e4270 Vangelis Koukis
216 b14725eb Christos Stavrakakis
def validate_network_size(cidr_block):
217 b14725eb Christos Stavrakakis
    """Return True if network size is allowed."""
218 b14725eb Christos Stavrakakis
    return cidr_block <= 29 and cidr_block > MAX_CIDR_BLOCK
219 b14725eb Christos Stavrakakis
220 b14725eb Christos Stavrakakis
221 adc46059 Christos Stavrakakis
def allocate_public_address(backend):
222 adc46059 Christos Stavrakakis
    """Allocate a public IP for a vm."""
223 adc46059 Christos Stavrakakis
    for network in backend_public_networks(backend):
224 adc46059 Christos Stavrakakis
        try:
225 adc46059 Christos Stavrakakis
            address = get_network_free_address(network)
226 adc46059 Christos Stavrakakis
            return (network, address)
227 adc46059 Christos Stavrakakis
        except EmptyPool:
228 adc46059 Christos Stavrakakis
            pass
229 adc46059 Christos Stavrakakis
    return (None, None)
230 adc46059 Christos Stavrakakis
231 adc46059 Christos Stavrakakis
232 7fede91e Christos Stavrakakis
def backend_public_networks(backend):
233 7fede91e Christos Stavrakakis
    """Return available public networks of the backend.
234 7fede91e Christos Stavrakakis

235 7fede91e Christos Stavrakakis
    Iterator for non-deleted public networks that are available
236 7fede91e Christos Stavrakakis
    to the specified backend.
237 7fede91e Christos Stavrakakis

238 7fede91e Christos Stavrakakis
    """
239 7fede91e Christos Stavrakakis
    for network in Network.objects.filter(public=True, deleted=False):
240 7fede91e Christos Stavrakakis
        if BackendNetwork.objects.filter(network=network,
241 7fede91e Christos Stavrakakis
                                         backend=backend).exists():
242 7fede91e Christos Stavrakakis
            yield network
243 7fede91e Christos Stavrakakis
244 7fede91e Christos Stavrakakis
245 7fede91e Christos Stavrakakis
def get_network_free_address(network):
246 7fede91e Christos Stavrakakis
    """Reserve an IP address from the IP Pool of the network.
247 7fede91e Christos Stavrakakis

248 fdc94944 Christos Stavrakakis
    Raises EmptyPool
249 7fede91e Christos Stavrakakis

250 7fede91e Christos Stavrakakis
    """
251 7fede91e Christos Stavrakakis
252 fdc94944 Christos Stavrakakis
    pool = network.get_pool()
253 fdc94944 Christos Stavrakakis
    address = pool.get()
254 7fede91e Christos Stavrakakis
    pool.save()
255 7fede91e Christos Stavrakakis
    return address
256 7fede91e Christos Stavrakakis
257 7fede91e Christos Stavrakakis
258 d44c236b Giorgos Verigakis
def get_nic(machine, network):
259 d44c236b Giorgos Verigakis
    try:
260 d44c236b Giorgos Verigakis
        return NetworkInterface.objects.get(machine=machine, network=network)
261 d44c236b Giorgos Verigakis
    except NetworkInterface.DoesNotExist:
262 d44c236b Giorgos Verigakis
        raise ItemNotFound('Server not connected to this network.')
263 d44c236b Giorgos Verigakis
264 7fede91e Christos Stavrakakis
265 08b079e2 Stavros Sachtouris
def get_nic_from_index(vm, nic_index):
266 08b079e2 Stavros Sachtouris
    """Returns the nic_index-th nic of a vm
267 08b079e2 Stavros Sachtouris
       Error Response Codes: itemNotFound (404), badMediaType (415)
268 08b079e2 Stavros Sachtouris
    """
269 08b079e2 Stavros Sachtouris
    matching_nics = vm.nics.filter(index=nic_index)
270 08b079e2 Stavros Sachtouris
    matching_nics_len = len(matching_nics)
271 08b079e2 Stavros Sachtouris
    if matching_nics_len < 1:
272 08b079e2 Stavros Sachtouris
        raise  ItemNotFound('NIC not found on VM')
273 08b079e2 Stavros Sachtouris
    elif matching_nics_len > 1:
274 08b079e2 Stavros Sachtouris
        raise BadMediaType('NIC index conflict on VM')
275 08b079e2 Stavros Sachtouris
    nic = matching_nics[0]
276 08b079e2 Stavros Sachtouris
    return nic
277 e2ee7808 Giorgos Verigakis
278 7fede91e Christos Stavrakakis
279 7e2f9d4b Giorgos Verigakis
def get_request_dict(request):
280 d8e50a39 Giorgos Verigakis
    """Returns data sent by the client as a python dict."""
281 aa197ee4 Vangelis Koukis
282 7e2f9d4b Giorgos Verigakis
    data = request.raw_post_data
283 7e45ddef Dimitris Moraitis
    if request.META.get('CONTENT_TYPE').startswith('application/json'):
284 7e2f9d4b Giorgos Verigakis
        try:
285 7e2f9d4b Giorgos Verigakis
            return json.loads(data)
286 7e2f9d4b Giorgos Verigakis
        except ValueError:
287 d8e50a39 Giorgos Verigakis
            raise BadRequest('Invalid JSON data.')
288 d8e50a39 Giorgos Verigakis
    else:
289 d8e50a39 Giorgos Verigakis
        raise BadRequest('Unsupported Content-Type.')
290 7e2f9d4b Giorgos Verigakis
291 a08e4270 Vangelis Koukis
292 8b01f7f3 Giorgos Verigakis
def update_response_headers(request, response):
293 8b01f7f3 Giorgos Verigakis
    if request.serialization == 'xml':
294 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/xml'
295 8b01f7f3 Giorgos Verigakis
    elif request.serialization == 'atom':
296 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/atom+xml'
297 8b01f7f3 Giorgos Verigakis
    else:
298 8b01f7f3 Giorgos Verigakis
        response['Content-Type'] = 'application/json'
299 aa197ee4 Vangelis Koukis
300 4cf8adf8 Vangelis Koukis
    if settings.TEST:
301 cdb65551 Giorgos Verigakis
        response['Date'] = format_date_time(time())
302 ce55f211 Kostas Papadimitriou
303 b75555e5 Giorgos Verigakis
    add_never_cache_headers(response)
304 b75555e5 Giorgos Verigakis
305 8b01f7f3 Giorgos Verigakis
306 432fc8c3 Giorgos Verigakis
def render_metadata(request, metadata, use_values=False, status=200):
307 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
308 432fc8c3 Giorgos Verigakis
        data = render_to_string('metadata.xml', {'metadata': metadata})
309 432fc8c3 Giorgos Verigakis
    else:
310 b36f78fa Giorgos Verigakis
        if use_values:
311 b36f78fa Giorgos Verigakis
            d = {'metadata': {'values': metadata}}
312 b36f78fa Giorgos Verigakis
        else:
313 b36f78fa Giorgos Verigakis
            d = {'metadata': metadata}
314 432fc8c3 Giorgos Verigakis
        data = json.dumps(d)
315 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
316 432fc8c3 Giorgos Verigakis
317 a08e4270 Vangelis Koukis
318 432fc8c3 Giorgos Verigakis
def render_meta(request, meta, status=200):
319 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
320 6ef51e9f Giorgos Verigakis
        data = render_to_string('meta.xml', dict(key=key, val=val))
321 432fc8c3 Giorgos Verigakis
    else:
322 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(meta=meta))
323 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
324 432fc8c3 Giorgos Verigakis
325 a08e4270 Vangelis Koukis
326 c36934a7 Giorgos Verigakis
def render_fault(request, fault):
327 4cf8adf8 Vangelis Koukis
    if settings.DEBUG or settings.TEST:
328 7e2f9d4b Giorgos Verigakis
        fault.details = format_exc(fault)
329 aa197ee4 Vangelis Koukis
330 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
331 d8e50a39 Giorgos Verigakis
        data = render_to_string('fault.xml', {'fault': fault})
332 7e2f9d4b Giorgos Verigakis
    else:
333 b36f78fa Giorgos Verigakis
        d = {fault.name: {
334 b36f78fa Giorgos Verigakis
                'code': fault.code,
335 b36f78fa Giorgos Verigakis
                'message': fault.message,
336 b36f78fa Giorgos Verigakis
                'details': fault.details}}
337 7e2f9d4b Giorgos Verigakis
        data = json.dumps(d)
338 aa197ee4 Vangelis Koukis
339 f0656db1 Giorgos Verigakis
    resp = HttpResponse(data, status=fault.code)
340 8b01f7f3 Giorgos Verigakis
    update_response_headers(request, resp)
341 f0656db1 Giorgos Verigakis
    return resp
342 d8e50a39 Giorgos Verigakis
343 432fc8c3 Giorgos Verigakis
344 d8e50a39 Giorgos Verigakis
def request_serialization(request, atom_allowed=False):
345 d8e50a39 Giorgos Verigakis
    """Return the serialization format requested.
346 aa197ee4 Vangelis Koukis

347 529178b1 Giorgos Verigakis
    Valid formats are 'json', 'xml' and 'atom' if `atom_allowed` is True.
348 d8e50a39 Giorgos Verigakis
    """
349 aa197ee4 Vangelis Koukis
350 d8e50a39 Giorgos Verigakis
    path = request.path
351 aa197ee4 Vangelis Koukis
352 d8e50a39 Giorgos Verigakis
    if path.endswith('.json'):
353 d8e50a39 Giorgos Verigakis
        return 'json'
354 d8e50a39 Giorgos Verigakis
    elif path.endswith('.xml'):
355 d8e50a39 Giorgos Verigakis
        return 'xml'
356 d8e50a39 Giorgos Verigakis
    elif atom_allowed and path.endswith('.atom'):
357 d8e50a39 Giorgos Verigakis
        return 'atom'
358 aa197ee4 Vangelis Koukis
359 d8e50a39 Giorgos Verigakis
    for item in request.META.get('HTTP_ACCEPT', '').split(','):
360 d8e50a39 Giorgos Verigakis
        accept, sep, rest = item.strip().partition(';')
361 d8e50a39 Giorgos Verigakis
        if accept == 'application/json':
362 d8e50a39 Giorgos Verigakis
            return 'json'
363 d8e50a39 Giorgos Verigakis
        elif accept == 'application/xml':
364 d8e50a39 Giorgos Verigakis
            return 'xml'
365 d8e50a39 Giorgos Verigakis
        elif atom_allowed and accept == 'application/atom+xml':
366 d8e50a39 Giorgos Verigakis
            return 'atom'
367 aa197ee4 Vangelis Koukis
368 d8e50a39 Giorgos Verigakis
    return 'json'
369 7e2f9d4b Giorgos Verigakis
370 a08e4270 Vangelis Koukis
371 d8e50a39 Giorgos Verigakis
def api_method(http_method=None, atom_allowed=False):
372 d8e50a39 Giorgos Verigakis
    """Decorator function for views that implement an API method."""
373 aa197ee4 Vangelis Koukis
374 c36934a7 Giorgos Verigakis
    def decorator(func):
375 c36934a7 Giorgos Verigakis
        @wraps(func)
376 c36934a7 Giorgos Verigakis
        def wrapper(request, *args, **kwargs):
377 c36934a7 Giorgos Verigakis
            try:
378 6ef51e9f Giorgos Verigakis
                request.serialization = request_serialization(request,
379 6ef51e9f Giorgos Verigakis
                                                              atom_allowed)
380 4b3b8688 Giorgos Verigakis
                get_user(request, settings.ASTAKOS_URL)
381 4b3b8688 Giorgos Verigakis
                if not request.user_uniq:
382 40777cc8 Giorgos Verigakis
                    raise Unauthorized('No user found.')
383 d8e50a39 Giorgos Verigakis
                if http_method and request.method != http_method:
384 d8e50a39 Giorgos Verigakis
                    raise BadRequest('Method not allowed.')
385 7fede91e Christos Stavrakakis
386 c36934a7 Giorgos Verigakis
                resp = func(request, *args, **kwargs)
387 8b01f7f3 Giorgos Verigakis
                update_response_headers(request, resp)
388 c36934a7 Giorgos Verigakis
                return resp
389 5231a38a Giorgos Verigakis
            except VirtualMachine.DeletedError:
390 5231a38a Giorgos Verigakis
                fault = BadRequest('Server has been deleted.')
391 5231a38a Giorgos Verigakis
                return render_fault(request, fault)
392 5231a38a Giorgos Verigakis
            except VirtualMachine.BuildingError:
393 5231a38a Giorgos Verigakis
                fault = BuildInProgress('Server is being built.')
394 5231a38a Giorgos Verigakis
                return render_fault(request, fault)
395 c36934a7 Giorgos Verigakis
            except Fault, fault:
396 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
397 7fede91e Christos Stavrakakis
            except BaseException:
398 9e98ba3c Giorgos Verigakis
                log.exception('Unexpected error')
399 529178b1 Giorgos Verigakis
                fault = ServiceUnavailable('Unexpected error.')
400 c36934a7 Giorgos Verigakis
                return render_fault(request, fault)
401 c36934a7 Giorgos Verigakis
        return wrapper
402 c36934a7 Giorgos Verigakis
    return decorator
403 08b079e2 Stavros Sachtouris
404 3165f027 Christos Stavrakakis
405 08b079e2 Stavros Sachtouris
def construct_nic_id(nic):
406 08b079e2 Stavros Sachtouris
    return "-".join(["nic", unicode(nic.machine.id), unicode(nic.index)])
407 6dd70a5c Christos Stavrakakis
408 6dd70a5c Christos Stavrakakis
409 af6a3bc5 Christos Stavrakakis
def net_resources(net_type):
410 af6a3bc5 Christos Stavrakakis
    mac_prefix = settings.MAC_POOL_BASE
411 af6a3bc5 Christos Stavrakakis
    if net_type == 'PRIVATE_MAC_FILTERED':
412 3165f027 Christos Stavrakakis
        link = settings.PRIVATE_MAC_FILTERED_BRIDGE
413 af6a3bc5 Christos Stavrakakis
        mac_pool = MacPrefixPoolTable.get_pool()
414 af6a3bc5 Christos Stavrakakis
        mac_prefix = mac_pool.get()
415 af6a3bc5 Christos Stavrakakis
        mac_pool.save()
416 af6a3bc5 Christos Stavrakakis
    elif net_type == 'PRIVATE_PHYSICAL_VLAN':
417 03992c72 Christos Stavrakakis
        pool = BridgePoolTable.get_pool()
418 03992c72 Christos Stavrakakis
        link = pool.get()
419 03992c72 Christos Stavrakakis
        pool.save()
420 af6a3bc5 Christos Stavrakakis
    elif net_type == 'CUSTOM_ROUTED':
421 3165f027 Christos Stavrakakis
        link = settings.CUSTOM_ROUTED_ROUTING_TABLE
422 af6a3bc5 Christos Stavrakakis
    elif net_type == 'CUSTOM_BRIDGED':
423 3165f027 Christos Stavrakakis
        link = settings.CUSTOM_BRIDGED_BRIDGE
424 af6a3bc5 Christos Stavrakakis
    elif net_type == 'PUBLIC_ROUTED':
425 3165f027 Christos Stavrakakis
        link = settings.PUBLIC_ROUTED_ROUTING_TABLE
426 3165f027 Christos Stavrakakis
    else:
427 af6a3bc5 Christos Stavrakakis
        raise BadRequest('Unknown network type')
428 6dd70a5c Christos Stavrakakis
429 af6a3bc5 Christos Stavrakakis
    return link, mac_prefix