Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (14.8 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 9ae613af Christos Stavrakakis
import ipaddr
36 c738c935 Giorgos Verigakis
37 dca7553e Christos Stavrakakis
from base64 import b64encode, b64decode
38 d8e50a39 Giorgos Verigakis
from datetime import timedelta, tzinfo
39 d8e50a39 Giorgos Verigakis
from functools import wraps
40 c738c935 Giorgos Verigakis
from hashlib import sha256
41 2035039b Giorgos Verigakis
from logging import getLogger
42 d8e50a39 Giorgos Verigakis
from random import choice
43 dca2a31f Giorgos Verigakis
from string import digits, lowercase, uppercase
44 8b01f7f3 Giorgos Verigakis
from time import time
45 d8e50a39 Giorgos Verigakis
from traceback import format_exc
46 8b01f7f3 Giorgos Verigakis
from wsgiref.handlers import format_date_time
47 7e2f9d4b Giorgos Verigakis
48 2035039b Giorgos Verigakis
import dateutil.parser
49 2035039b Giorgos Verigakis
50 c738c935 Giorgos Verigakis
from Crypto.Cipher import AES
51 529178b1 Giorgos Verigakis
52 d8e50a39 Giorgos Verigakis
from django.conf import settings
53 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
54 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
55 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
56 b75555e5 Giorgos Verigakis
from django.utils.cache import add_never_cache_headers
57 d3406fbc Christos Stavrakakis
from django.db.models import Q
58 7e2f9d4b Giorgos Verigakis
59 bd40abfa Christos Stavrakakis
from snf_django.lib.api import faults
60 6ef51e9f Giorgos Verigakis
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
61 7fede91e Christos Stavrakakis
                               Network, BackendNetwork, NetworkInterface,
62 85919a0f Christos Stavrakakis
                               BridgePoolTable, MacPrefixPoolTable, Backend)
63 adc46059 Christos Stavrakakis
from synnefo.db.pools import EmptyPool
64 6dd70a5c Christos Stavrakakis
65 04a1b675 Christos Stavrakakis
from snf_django.lib.astakos import get_user
66 b3fd98ae Christos Stavrakakis
from synnefo.plankton.utils import image_backend
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 dca2a31f Giorgos Verigakis
def random_password():
74 dca2a31f Giorgos Verigakis
    """Generates a random password
75 ce55f211 Kostas Papadimitriou

76 62eac5a6 Giorgos Verigakis
    We generate a windows compliant password: it must contain at least
77 dca2a31f Giorgos Verigakis
    one charachter from each of the groups: upper case, lower case, digits.
78 dca2a31f Giorgos Verigakis
    """
79 ce55f211 Kostas Papadimitriou
80 dca2a31f Giorgos Verigakis
    pool = lowercase + uppercase + digits
81 dca2a31f Giorgos Verigakis
    lowerset = set(lowercase)
82 dca2a31f Giorgos Verigakis
    upperset = set(uppercase)
83 dca2a31f Giorgos Verigakis
    digitset = set(digits)
84 dca2a31f Giorgos Verigakis
    length = 10
85 ce55f211 Kostas Papadimitriou
86 62eac5a6 Giorgos Verigakis
    password = ''.join(choice(pool) for i in range(length - 2))
87 ce55f211 Kostas Papadimitriou
88 62eac5a6 Giorgos Verigakis
    # Make sure the password is compliant
89 62eac5a6 Giorgos Verigakis
    chars = set(password)
90 62eac5a6 Giorgos Verigakis
    if not chars & lowerset:
91 62eac5a6 Giorgos Verigakis
        password += choice(lowercase)
92 62eac5a6 Giorgos Verigakis
    if not chars & upperset:
93 62eac5a6 Giorgos Verigakis
        password += choice(uppercase)
94 62eac5a6 Giorgos Verigakis
    if not chars & digitset:
95 62eac5a6 Giorgos Verigakis
        password += choice(digits)
96 ce55f211 Kostas Papadimitriou
97 62eac5a6 Giorgos Verigakis
    # Pad if necessary to reach required length
98 62eac5a6 Giorgos Verigakis
    password += ''.join(choice(pool) for i in range(length - len(password)))
99 ce55f211 Kostas Papadimitriou
100 dca2a31f Giorgos Verigakis
    return password
101 dca2a31f Giorgos Verigakis
102 d8e50a39 Giorgos Verigakis
103 c738c935 Giorgos Verigakis
def zeropad(s):
104 c738c935 Giorgos Verigakis
    """Add zeros at the end of a string in order to make its length
105 c738c935 Giorgos Verigakis
       a multiple of 16."""
106 d1387ed7 Christodoulos Psaltis
107 c738c935 Giorgos Verigakis
    npad = 16 - len(s) % 16
108 c738c935 Giorgos Verigakis
    return s + '\x00' * npad
109 c738c935 Giorgos Verigakis
110 a08e4270 Vangelis Koukis
111 c738c935 Giorgos Verigakis
def encrypt(plaintext):
112 c738c935 Giorgos Verigakis
    # Make sure key is 32 bytes long
113 c738c935 Giorgos Verigakis
    key = sha256(settings.SECRET_KEY).digest()
114 d1387ed7 Christodoulos Psaltis
115 c738c935 Giorgos Verigakis
    aes = AES.new(key)
116 c738c935 Giorgos Verigakis
    enc = aes.encrypt(zeropad(plaintext))
117 c738c935 Giorgos Verigakis
    return b64encode(enc)
118 c738c935 Giorgos Verigakis
119 7e2f9d4b Giorgos Verigakis
120 7f2dbcad Christos Stavrakakis
def get_vm(server_id, user_id, for_update=False, non_deleted=False,
121 7f2dbcad Christos Stavrakakis
           non_suspended=False):
122 e221ade2 Christos Stavrakakis
    """Find a VirtualMachine instance based on ID and owner."""
123 aa197ee4 Vangelis Koukis
124 d8e50a39 Giorgos Verigakis
    try:
125 d8e50a39 Giorgos Verigakis
        server_id = int(server_id)
126 7f2dbcad Christos Stavrakakis
        servers = VirtualMachine.objects
127 7f2dbcad Christos Stavrakakis
        if for_update:
128 7f2dbcad Christos Stavrakakis
            servers = servers.select_for_update()
129 7f2dbcad Christos Stavrakakis
        vm = servers.get(id=server_id, userid=user_id)
130 e221ade2 Christos Stavrakakis
        if non_deleted and vm.deleted:
131 5b0832fc Christos Stavrakakis
            raise faults.BadRequest("Server has been deleted.")
132 e221ade2 Christos Stavrakakis
        if non_suspended and vm.suspended:
133 bd40abfa Christos Stavrakakis
            raise faults.Forbidden("Administratively Suspended VM")
134 3a522cff Christos Stavrakakis
        return vm
135 d8e50a39 Giorgos Verigakis
    except ValueError:
136 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid server ID.')
137 d8e50a39 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
138 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Server not found.')
139 d8e50a39 Giorgos Verigakis
140 7f2dbcad Christos Stavrakakis
141 40777cc8 Giorgos Verigakis
def get_vm_meta(vm, key):
142 d8e50a39 Giorgos Verigakis
    """Return a VirtualMachineMetadata instance or raise ItemNotFound."""
143 aa197ee4 Vangelis Koukis
144 d8e50a39 Giorgos Verigakis
    try:
145 40777cc8 Giorgos Verigakis
        return VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
146 d8e50a39 Giorgos Verigakis
    except VirtualMachineMetadata.DoesNotExist:
147 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Metadata key not found.')
148 d8e50a39 Giorgos Verigakis
149 a08e4270 Vangelis Koukis
150 6ef51e9f Giorgos Verigakis
def get_image(image_id, user_id):
151 d8e50a39 Giorgos Verigakis
    """Return an Image instance or raise ItemNotFound."""
152 aa197ee4 Vangelis Koukis
153 b3fd98ae Christos Stavrakakis
    with image_backend(user_id) as backend:
154 cda71050 Christos Stavrakakis
        return backend.get_image(image_id)
155 3a9b3cde Giorgos Verigakis
156 a08e4270 Vangelis Koukis
157 dca7553e Christos Stavrakakis
def get_image_dict(image_id, user_id):
158 dca7553e Christos Stavrakakis
    image = {}
159 dca7553e Christos Stavrakakis
    img = get_image(image_id, user_id)
160 dca7553e Christos Stavrakakis
    properties = img.get('properties', {})
161 bcd80cd9 Christos Stavrakakis
    image["id"] = img["id"]
162 bcd80cd9 Christos Stavrakakis
    image["name"] = img["name"]
163 dca7553e Christos Stavrakakis
    image['backend_id'] = img['location']
164 dca7553e Christos Stavrakakis
    image['format'] = img['disk_format']
165 e440e835 Christos Stavrakakis
    image['metadata'] = dict((key.upper(), val)
166 dca7553e Christos Stavrakakis
                             for key, val in properties.items())
167 2cb812be Christos Stavrakakis
    image['checksum'] = img['checksum']
168 2cb812be Christos Stavrakakis
169 dca7553e Christos Stavrakakis
    return image
170 dca7553e Christos Stavrakakis
171 dca7553e Christos Stavrakakis
172 aa8230bd Christos Stavrakakis
def get_flavor(flavor_id, include_deleted=False):
173 529178b1 Giorgos Verigakis
    """Return a Flavor instance or raise ItemNotFound."""
174 aa197ee4 Vangelis Koukis
175 529178b1 Giorgos Verigakis
    try:
176 529178b1 Giorgos Verigakis
        flavor_id = int(flavor_id)
177 aa8230bd Christos Stavrakakis
        if include_deleted:
178 aa8230bd Christos Stavrakakis
            return Flavor.objects.get(id=flavor_id)
179 aa8230bd Christos Stavrakakis
        else:
180 aa8230bd Christos Stavrakakis
            return Flavor.objects.get(id=flavor_id, deleted=include_deleted)
181 6ef51e9f Giorgos Verigakis
    except (ValueError, Flavor.DoesNotExist):
182 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Flavor not found.')
183 d8e50a39 Giorgos Verigakis
184 a08e4270 Vangelis Koukis
185 9dcb5b8a Christos Stavrakakis
def get_flavor_provider(flavor):
186 9dcb5b8a Christos Stavrakakis
    """Extract provider from disk template.
187 9dcb5b8a Christos Stavrakakis

188 9dcb5b8a Christos Stavrakakis
    Provider for `ext` disk_template is encoded in the disk template
189 9dcb5b8a Christos Stavrakakis
    name, which is formed `ext_<provider_name>`. Provider is None
190 9dcb5b8a Christos Stavrakakis
    for all other disk templates.
191 9dcb5b8a Christos Stavrakakis

192 9dcb5b8a Christos Stavrakakis
    """
193 9dcb5b8a Christos Stavrakakis
    disk_template = flavor.disk_template
194 9dcb5b8a Christos Stavrakakis
    provider = None
195 9dcb5b8a Christos Stavrakakis
    if disk_template.startswith("ext"):
196 9dcb5b8a Christos Stavrakakis
        disk_template, provider = disk_template.split("_", 1)
197 9dcb5b8a Christos Stavrakakis
    return disk_template, provider
198 9dcb5b8a Christos Stavrakakis
199 9dcb5b8a Christos Stavrakakis
200 d2e73c0c Christos Stavrakakis
def get_network(network_id, user_id, for_update=False):
201 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
202 aa197ee4 Vangelis Koukis
203 e2ee7808 Giorgos Verigakis
    try:
204 7fede91e Christos Stavrakakis
        network_id = int(network_id)
205 d3406fbc Christos Stavrakakis
        objects = Network.objects
206 d2e73c0c Christos Stavrakakis
        if for_update:
207 d3406fbc Christos Stavrakakis
            objects = objects.select_for_update()
208 d3406fbc Christos Stavrakakis
        return objects.get(Q(userid=user_id) | Q(public=True), id=network_id)
209 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
210 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Network not found.')
211 e2ee7808 Giorgos Verigakis
212 a08e4270 Vangelis Koukis
213 9ae613af Christos Stavrakakis
def validate_network_params(subnet, gateway=None, subnet6=None, gateway6=None):
214 d368ec0c Christos Stavrakakis
    try:
215 d368ec0c Christos Stavrakakis
        # Use strict option to not all subnets with host bits set
216 9ae613af Christos Stavrakakis
        network = ipaddr.IPv4Network(subnet, strict=True)
217 d368ec0c Christos Stavrakakis
    except ValueError:
218 bd40abfa Christos Stavrakakis
        raise faults.BadRequest("Invalid network IPv4 subnet")
219 d368ec0c Christos Stavrakakis
220 d368ec0c Christos Stavrakakis
    # Check that network size is allowed!
221 d368ec0c Christos Stavrakakis
    if not validate_network_size(network.prefixlen):
222 bd40abfa Christos Stavrakakis
        raise faults.OverLimit(message="Unsupported network size",
223 9ae613af Christos Stavrakakis
                        details="Network mask must be in range (%s, 29]" %
224 9ae613af Christos Stavrakakis
                                MAX_CIDR_BLOCK)
225 9ae613af Christos Stavrakakis
226 9ae613af Christos Stavrakakis
    # Check that gateway belongs to network
227 9ae613af Christos Stavrakakis
    if gateway:
228 9ae613af Christos Stavrakakis
        try:
229 9ae613af Christos Stavrakakis
            gateway = ipaddr.IPv4Address(gateway)
230 9ae613af Christos Stavrakakis
        except ValueError:
231 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 gateway")
232 9ae613af Christos Stavrakakis
        if not gateway in network:
233 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 gateway")
234 9ae613af Christos Stavrakakis
235 9ae613af Christos Stavrakakis
    if subnet6:
236 9ae613af Christos Stavrakakis
        try:
237 9ae613af Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
238 9ae613af Christos Stavrakakis
            network6 = ipaddr.IPv6Network(subnet6, strict=True)
239 9ae613af Christos Stavrakakis
        except ValueError:
240 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv6 subnet")
241 9ae613af Christos Stavrakakis
        if gateway6:
242 9ae613af Christos Stavrakakis
            try:
243 9ae613af Christos Stavrakakis
                gateway6 = ipaddr.IPv6Address(gateway6)
244 9ae613af Christos Stavrakakis
            except ValueError:
245 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
246 9ae613af Christos Stavrakakis
            if not gateway6 in network6:
247 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
248 d368ec0c Christos Stavrakakis
249 d368ec0c Christos Stavrakakis
250 b14725eb Christos Stavrakakis
def validate_network_size(cidr_block):
251 b14725eb Christos Stavrakakis
    """Return True if network size is allowed."""
252 b14725eb Christos Stavrakakis
    return cidr_block <= 29 and cidr_block > MAX_CIDR_BLOCK
253 b14725eb Christos Stavrakakis
254 b14725eb Christos Stavrakakis
255 adc46059 Christos Stavrakakis
def allocate_public_address(backend):
256 adc46059 Christos Stavrakakis
    """Allocate a public IP for a vm."""
257 adc46059 Christos Stavrakakis
    for network in backend_public_networks(backend):
258 adc46059 Christos Stavrakakis
        try:
259 adc46059 Christos Stavrakakis
            address = get_network_free_address(network)
260 adc46059 Christos Stavrakakis
            return (network, address)
261 adc46059 Christos Stavrakakis
        except EmptyPool:
262 adc46059 Christos Stavrakakis
            pass
263 adc46059 Christos Stavrakakis
    return (None, None)
264 adc46059 Christos Stavrakakis
265 adc46059 Christos Stavrakakis
266 dca7553e Christos Stavrakakis
def get_public_ip(backend):
267 dca7553e Christos Stavrakakis
    """Reserve an IP from a public network.
268 dca7553e Christos Stavrakakis

269 dca7553e Christos Stavrakakis
    This method should run inside a transaction.
270 dca7553e Christos Stavrakakis

271 dca7553e Christos Stavrakakis
    """
272 85919a0f Christos Stavrakakis
273 85919a0f Christos Stavrakakis
    # Guarantee exclusive access to backend, because accessing the IP pools of
274 85919a0f Christos Stavrakakis
    # the backend networks may result in a deadlock with backend allocator
275 85919a0f Christos Stavrakakis
    # which also checks that backend networks have a free IP.
276 85919a0f Christos Stavrakakis
    backend = Backend.objects.select_for_update().get(id=backend.id)
277 85919a0f Christos Stavrakakis
278 dca7553e Christos Stavrakakis
    address = None
279 74459c12 Christos Stavrakakis
    if settings.PUBLIC_USE_POOL:
280 dca7553e Christos Stavrakakis
        (network, address) = allocate_public_address(backend)
281 dca7553e Christos Stavrakakis
    else:
282 dca7553e Christos Stavrakakis
        for net in list(backend_public_networks(backend)):
283 dca7553e Christos Stavrakakis
            pool = net.get_pool()
284 dca7553e Christos Stavrakakis
            if not pool.empty():
285 dca7553e Christos Stavrakakis
                address = 'pool'
286 dca7553e Christos Stavrakakis
                network = net
287 dca7553e Christos Stavrakakis
                break
288 dca7553e Christos Stavrakakis
    if address is None:
289 dca7553e Christos Stavrakakis
        log.error("Public networks of backend %s are full", backend)
290 bd40abfa Christos Stavrakakis
        raise faults.OverLimit("Can not allocate IP for new machine."
291 dca7553e Christos Stavrakakis
                        " Public networks are full.")
292 dca7553e Christos Stavrakakis
    return (network, address)
293 dca7553e Christos Stavrakakis
294 dca7553e Christos Stavrakakis
295 7fede91e Christos Stavrakakis
def backend_public_networks(backend):
296 7fede91e Christos Stavrakakis
    """Return available public networks of the backend.
297 7fede91e Christos Stavrakakis

298 7fede91e Christos Stavrakakis
    Iterator for non-deleted public networks that are available
299 7fede91e Christos Stavrakakis
    to the specified backend.
300 7fede91e Christos Stavrakakis

301 7fede91e Christos Stavrakakis
    """
302 6dafedf6 Christos Stavrakakis
    for network in Network.objects.filter(public=True, deleted=False,
303 6dafedf6 Christos Stavrakakis
                                          drained=False):
304 7fede91e Christos Stavrakakis
        if BackendNetwork.objects.filter(network=network,
305 7fede91e Christos Stavrakakis
                                         backend=backend).exists():
306 7fede91e Christos Stavrakakis
            yield network
307 7fede91e Christos Stavrakakis
308 7fede91e Christos Stavrakakis
309 7fede91e Christos Stavrakakis
def get_network_free_address(network):
310 7fede91e Christos Stavrakakis
    """Reserve an IP address from the IP Pool of the network.
311 7fede91e Christos Stavrakakis

312 fdc94944 Christos Stavrakakis
    Raises EmptyPool
313 7fede91e Christos Stavrakakis

314 7fede91e Christos Stavrakakis
    """
315 7fede91e Christos Stavrakakis
316 fdc94944 Christos Stavrakakis
    pool = network.get_pool()
317 fdc94944 Christos Stavrakakis
    address = pool.get()
318 7fede91e Christos Stavrakakis
    pool.save()
319 7fede91e Christos Stavrakakis
    return address
320 7fede91e Christos Stavrakakis
321 7fede91e Christos Stavrakakis
322 d44c236b Giorgos Verigakis
def get_nic(machine, network):
323 d44c236b Giorgos Verigakis
    try:
324 d44c236b Giorgos Verigakis
        return NetworkInterface.objects.get(machine=machine, network=network)
325 d44c236b Giorgos Verigakis
    except NetworkInterface.DoesNotExist:
326 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Server not connected to this network.')
327 d44c236b Giorgos Verigakis
328 7fede91e Christos Stavrakakis
329 08b079e2 Stavros Sachtouris
def get_nic_from_index(vm, nic_index):
330 08b079e2 Stavros Sachtouris
    """Returns the nic_index-th nic of a vm
331 08b079e2 Stavros Sachtouris
       Error Response Codes: itemNotFound (404), badMediaType (415)
332 08b079e2 Stavros Sachtouris
    """
333 08b079e2 Stavros Sachtouris
    matching_nics = vm.nics.filter(index=nic_index)
334 08b079e2 Stavros Sachtouris
    matching_nics_len = len(matching_nics)
335 08b079e2 Stavros Sachtouris
    if matching_nics_len < 1:
336 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('NIC not found on VM')
337 08b079e2 Stavros Sachtouris
    elif matching_nics_len > 1:
338 bd40abfa Christos Stavrakakis
        raise faults.BadMediaType('NIC index conflict on VM')
339 08b079e2 Stavros Sachtouris
    nic = matching_nics[0]
340 08b079e2 Stavros Sachtouris
    return nic
341 e2ee7808 Giorgos Verigakis
342 7fede91e Christos Stavrakakis
343 432fc8c3 Giorgos Verigakis
def render_metadata(request, metadata, use_values=False, status=200):
344 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
345 432fc8c3 Giorgos Verigakis
        data = render_to_string('metadata.xml', {'metadata': metadata})
346 432fc8c3 Giorgos Verigakis
    else:
347 b36f78fa Giorgos Verigakis
        if use_values:
348 b36f78fa Giorgos Verigakis
            d = {'metadata': {'values': metadata}}
349 b36f78fa Giorgos Verigakis
        else:
350 b36f78fa Giorgos Verigakis
            d = {'metadata': metadata}
351 432fc8c3 Giorgos Verigakis
        data = json.dumps(d)
352 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
353 432fc8c3 Giorgos Verigakis
354 a08e4270 Vangelis Koukis
355 432fc8c3 Giorgos Verigakis
def render_meta(request, meta, status=200):
356 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
357 6ef51e9f Giorgos Verigakis
        data = render_to_string('meta.xml', dict(key=key, val=val))
358 432fc8c3 Giorgos Verigakis
    else:
359 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(meta=meta))
360 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
361 432fc8c3 Giorgos Verigakis
362 a08e4270 Vangelis Koukis
363 08b079e2 Stavros Sachtouris
def construct_nic_id(nic):
364 08b079e2 Stavros Sachtouris
    return "-".join(["nic", unicode(nic.machine.id), unicode(nic.index)])
365 6dd70a5c Christos Stavrakakis
366 6dd70a5c Christos Stavrakakis
367 dca7553e Christos Stavrakakis
def verify_personality(personality):
368 6ec4694f Christos Stavrakakis
    """Verify that a a list of personalities is well formed"""
369 006c6249 Christos Stavrakakis
    if len(personality) > settings.MAX_PERSONALITY:
370 bd40abfa Christos Stavrakakis
        raise faults.OverLimit("Maximum number of personalities"
371 e440e835 Christos Stavrakakis
                        " exceeded")
372 dca7553e Christos Stavrakakis
    for p in personality:
373 dca7553e Christos Stavrakakis
        # Verify that personalities are well-formed
374 dca7553e Christos Stavrakakis
        try:
375 dca7553e Christos Stavrakakis
            assert isinstance(p, dict)
376 dca7553e Christos Stavrakakis
            keys = set(p.keys())
377 dca7553e Christos Stavrakakis
            allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
378 dca7553e Christos Stavrakakis
            assert keys.issubset(allowed)
379 dca7553e Christos Stavrakakis
            contents = p['contents']
380 dca7553e Christos Stavrakakis
            if len(contents) > settings.MAX_PERSONALITY_SIZE:
381 dca7553e Christos Stavrakakis
                # No need to decode if contents already exceed limit
382 bd40abfa Christos Stavrakakis
                raise faults.OverLimit("Maximum size of personality exceeded")
383 dca7553e Christos Stavrakakis
            if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
384 bd40abfa Christos Stavrakakis
                raise faults.OverLimit("Maximum size of personality exceeded")
385 dca7553e Christos Stavrakakis
        except AssertionError:
386 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Malformed personality in request")
387 2a599282 Christos Stavrakakis
388 2a599282 Christos Stavrakakis
389 b7d38981 Dimitris Aragiorgis
def values_from_flavor(flavor):
390 b7d38981 Dimitris Aragiorgis
    """Get Ganeti connectivity info from flavor type.
391 b7d38981 Dimitris Aragiorgis

392 b7d38981 Dimitris Aragiorgis
    If link or mac_prefix equals to "pool", then the resources
393 b7d38981 Dimitris Aragiorgis
    are allocated from the corresponding Pools.
394 b7d38981 Dimitris Aragiorgis

395 b7d38981 Dimitris Aragiorgis
    """
396 b7d38981 Dimitris Aragiorgis
    try:
397 b7d38981 Dimitris Aragiorgis
        flavor = Network.FLAVORS[flavor]
398 b7d38981 Dimitris Aragiorgis
    except KeyError:
399 bd40abfa Christos Stavrakakis
        raise faults.BadRequest("Unknown network flavor")
400 b7d38981 Dimitris Aragiorgis
401 b7d38981 Dimitris Aragiorgis
    mode = flavor.get("mode")
402 b7d38981 Dimitris Aragiorgis
403 b7d38981 Dimitris Aragiorgis
    link = flavor.get("link")
404 b7d38981 Dimitris Aragiorgis
    if link == "pool":
405 b7d38981 Dimitris Aragiorgis
        link = allocate_resource("bridge")
406 b7d38981 Dimitris Aragiorgis
407 b7d38981 Dimitris Aragiorgis
    mac_prefix = flavor.get("mac_prefix")
408 b7d38981 Dimitris Aragiorgis
    if mac_prefix == "pool":
409 b7d38981 Dimitris Aragiorgis
        mac_prefix = allocate_resource("mac_prefix")
410 b7d38981 Dimitris Aragiorgis
411 b7d38981 Dimitris Aragiorgis
    tags = flavor.get("tags")
412 b7d38981 Dimitris Aragiorgis
413 b7d38981 Dimitris Aragiorgis
    return mode, link, mac_prefix, tags
414 b7d38981 Dimitris Aragiorgis
415 b7d38981 Dimitris Aragiorgis
416 b7d38981 Dimitris Aragiorgis
def allocate_resource(res_type):
417 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
418 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
419 b7d38981 Dimitris Aragiorgis
    value = pool.get()
420 b7d38981 Dimitris Aragiorgis
    pool.save()
421 b7d38981 Dimitris Aragiorgis
    return value
422 b7d38981 Dimitris Aragiorgis
423 b7d38981 Dimitris Aragiorgis
424 b7d38981 Dimitris Aragiorgis
def release_resource(res_type, value):
425 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
426 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
427 b7d38981 Dimitris Aragiorgis
    pool.put(value)
428 b7d38981 Dimitris Aragiorgis
    pool.save()
429 b7d38981 Dimitris Aragiorgis
430 b7d38981 Dimitris Aragiorgis
431 b7d38981 Dimitris Aragiorgis
def get_pool_table(res_type):
432 b7d38981 Dimitris Aragiorgis
    if res_type == "bridge":
433 b7d38981 Dimitris Aragiorgis
        return BridgePoolTable
434 b7d38981 Dimitris Aragiorgis
    elif res_type == "mac_prefix":
435 b7d38981 Dimitris Aragiorgis
        return MacPrefixPoolTable
436 b7d38981 Dimitris Aragiorgis
    else:
437 b7d38981 Dimitris Aragiorgis
        raise Exception("Unknown resource type")
438 55f562a4 Kostas Papadimitriou
439 55f562a4 Kostas Papadimitriou
440 55f562a4 Kostas Papadimitriou
def get_existing_users():
441 55f562a4 Kostas Papadimitriou
    """
442 55f562a4 Kostas Papadimitriou
    Retrieve user ids stored in cyclades user agnostic models.
443 55f562a4 Kostas Papadimitriou
    """
444 55f562a4 Kostas Papadimitriou
    # also check PublicKeys a user with no servers/networks exist
445 55f562a4 Kostas Papadimitriou
    from synnefo.ui.userdata.models import PublicKeyPair
446 55f562a4 Kostas Papadimitriou
    from synnefo.db.models import VirtualMachine, Network
447 55f562a4 Kostas Papadimitriou
448 55f562a4 Kostas Papadimitriou
    keypairusernames = PublicKeyPair.objects.filter().values_list('user',
449 e440e835 Christos Stavrakakis
                                                                  flat=True)
450 55f562a4 Kostas Papadimitriou
    serverusernames = VirtualMachine.objects.filter().values_list('userid',
451 e440e835 Christos Stavrakakis
                                                                  flat=True)
452 55f562a4 Kostas Papadimitriou
    networkusernames = Network.objects.filter().values_list('userid',
453 55f562a4 Kostas Papadimitriou
                                                            flat=True)
454 55f562a4 Kostas Papadimitriou
455 e440e835 Christos Stavrakakis
    return set(list(keypairusernames) + list(serverusernames) +
456 e440e835 Christos Stavrakakis
               list(networkusernames))