Statistics
| Branch: | Tag: | Revision:

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

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

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

248 7fede91e Christos Stavrakakis
    Iterator for non-deleted public networks that are available
249 7fede91e Christos Stavrakakis
    to the specified backend.
250 7fede91e Christos Stavrakakis

251 7fede91e Christos Stavrakakis
    """
252 7fede91e Christos Stavrakakis
    for network in Network.objects.filter(public=True, deleted=False):
253 7fede91e Christos Stavrakakis
        if BackendNetwork.objects.filter(network=network,
254 7fede91e Christos Stavrakakis
                                         backend=backend).exists():
255 7fede91e Christos Stavrakakis
            yield network
256 7fede91e Christos Stavrakakis
257 7fede91e Christos Stavrakakis
258 7fede91e Christos Stavrakakis
def get_network_free_address(network):
259 7fede91e Christos Stavrakakis
    """Reserve an IP address from the IP Pool of the network.
260 7fede91e Christos Stavrakakis

261 fdc94944 Christos Stavrakakis
    Raises EmptyPool
262 7fede91e Christos Stavrakakis

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

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