Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (16.4 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 1b696c26 Christos Stavrakakis
from synnefo.cyclades_settings import cyclades_services, BASE_HOST
70 1b696c26 Christos Stavrakakis
from synnefo.lib.services import get_service_path
71 1b696c26 Christos Stavrakakis
from synnefo.lib import join_urls
72 1b696c26 Christos Stavrakakis
73 1b696c26 Christos Stavrakakis
COMPUTE_URL = \
74 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
75 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "compute", version="v2.0"))
76 1b696c26 Christos Stavrakakis
SERVERS_URL = join_urls(COMPUTE_URL, "servers/")
77 1b696c26 Christos Stavrakakis
NETWORKS_URL = join_urls(COMPUTE_URL, "networks/")
78 1b696c26 Christos Stavrakakis
FLAVORS_URL = join_urls(COMPUTE_URL, "flavors/")
79 1b696c26 Christos Stavrakakis
IMAGES_URL = join_urls(COMPUTE_URL, "images/")
80 1b696c26 Christos Stavrakakis
PLANKTON_URL = \
81 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
82 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "image", version="v1.0"))
83 1b696c26 Christos Stavrakakis
IMAGES_PLANKTON_URL = join_urls(PLANKTON_URL, "images/")
84 1b696c26 Christos Stavrakakis
85 9e98ba3c Giorgos Verigakis
86 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
87 9e98ba3c Giorgos Verigakis
88 7e2f9d4b Giorgos Verigakis
89 dca2a31f Giorgos Verigakis
def random_password():
90 dca2a31f Giorgos Verigakis
    """Generates a random password
91 ce55f211 Kostas Papadimitriou

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

204 9dcb5b8a Christos Stavrakakis
    Provider for `ext` disk_template is encoded in the disk template
205 9dcb5b8a Christos Stavrakakis
    name, which is formed `ext_<provider_name>`. Provider is None
206 9dcb5b8a Christos Stavrakakis
    for all other disk templates.
207 9dcb5b8a Christos Stavrakakis

208 9dcb5b8a Christos Stavrakakis
    """
209 9dcb5b8a Christos Stavrakakis
    disk_template = flavor.disk_template
210 9dcb5b8a Christos Stavrakakis
    provider = None
211 9dcb5b8a Christos Stavrakakis
    if disk_template.startswith("ext"):
212 9dcb5b8a Christos Stavrakakis
        disk_template, provider = disk_template.split("_", 1)
213 9dcb5b8a Christos Stavrakakis
    return disk_template, provider
214 9dcb5b8a Christos Stavrakakis
215 9dcb5b8a Christos Stavrakakis
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 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Network not found.')
227 e2ee7808 Giorgos Verigakis
228 a08e4270 Vangelis Koukis
229 9ae613af Christos Stavrakakis
def validate_network_params(subnet, gateway=None, subnet6=None, gateway6=None):
230 d368ec0c Christos Stavrakakis
    try:
231 d368ec0c Christos Stavrakakis
        # Use strict option to not all subnets with host bits set
232 9ae613af Christos Stavrakakis
        network = ipaddr.IPv4Network(subnet, strict=True)
233 d368ec0c Christos Stavrakakis
    except ValueError:
234 bd40abfa Christos Stavrakakis
        raise faults.BadRequest("Invalid network IPv4 subnet")
235 d368ec0c Christos Stavrakakis
236 d368ec0c Christos Stavrakakis
    # Check that network size is allowed!
237 d368ec0c Christos Stavrakakis
    if not validate_network_size(network.prefixlen):
238 bd40abfa Christos Stavrakakis
        raise faults.OverLimit(message="Unsupported network size",
239 9ae613af Christos Stavrakakis
                        details="Network mask must be in range (%s, 29]" %
240 9ae613af Christos Stavrakakis
                                MAX_CIDR_BLOCK)
241 9ae613af Christos Stavrakakis
242 9ae613af Christos Stavrakakis
    # Check that gateway belongs to network
243 9ae613af Christos Stavrakakis
    if gateway:
244 9ae613af Christos Stavrakakis
        try:
245 9ae613af Christos Stavrakakis
            gateway = ipaddr.IPv4Address(gateway)
246 9ae613af Christos Stavrakakis
        except ValueError:
247 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 gateway")
248 9ae613af Christos Stavrakakis
        if not gateway in network:
249 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 gateway")
250 9ae613af Christos Stavrakakis
251 9ae613af Christos Stavrakakis
    if subnet6:
252 9ae613af Christos Stavrakakis
        try:
253 9ae613af Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
254 9ae613af Christos Stavrakakis
            network6 = ipaddr.IPv6Network(subnet6, strict=True)
255 9ae613af Christos Stavrakakis
        except ValueError:
256 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv6 subnet")
257 9ae613af Christos Stavrakakis
        if gateway6:
258 9ae613af Christos Stavrakakis
            try:
259 9ae613af Christos Stavrakakis
                gateway6 = ipaddr.IPv6Address(gateway6)
260 9ae613af Christos Stavrakakis
            except ValueError:
261 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
262 9ae613af Christos Stavrakakis
            if not gateway6 in network6:
263 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
264 d368ec0c Christos Stavrakakis
265 d368ec0c Christos Stavrakakis
266 b14725eb Christos Stavrakakis
def validate_network_size(cidr_block):
267 b14725eb Christos Stavrakakis
    """Return True if network size is allowed."""
268 b14725eb Christos Stavrakakis
    return cidr_block <= 29 and cidr_block > MAX_CIDR_BLOCK
269 b14725eb Christos Stavrakakis
270 b14725eb Christos Stavrakakis
271 adc46059 Christos Stavrakakis
def allocate_public_address(backend):
272 adc46059 Christos Stavrakakis
    """Allocate a public IP for a vm."""
273 adc46059 Christos Stavrakakis
    for network in backend_public_networks(backend):
274 adc46059 Christos Stavrakakis
        try:
275 adc46059 Christos Stavrakakis
            address = get_network_free_address(network)
276 34c03a51 Christos Stavrakakis
        except faults.OverLimit:
277 adc46059 Christos Stavrakakis
            pass
278 34c03a51 Christos Stavrakakis
        else:
279 34c03a51 Christos Stavrakakis
            return (network, address)
280 adc46059 Christos Stavrakakis
    return (None, None)
281 adc46059 Christos Stavrakakis
282 adc46059 Christos Stavrakakis
283 dca7553e Christos Stavrakakis
def get_public_ip(backend):
284 dca7553e Christos Stavrakakis
    """Reserve an IP from a public network.
285 dca7553e Christos Stavrakakis

286 dca7553e Christos Stavrakakis
    This method should run inside a transaction.
287 dca7553e Christos Stavrakakis

288 dca7553e Christos Stavrakakis
    """
289 85919a0f Christos Stavrakakis
290 85919a0f Christos Stavrakakis
    # Guarantee exclusive access to backend, because accessing the IP pools of
291 85919a0f Christos Stavrakakis
    # the backend networks may result in a deadlock with backend allocator
292 85919a0f Christos Stavrakakis
    # which also checks that backend networks have a free IP.
293 85919a0f Christos Stavrakakis
    backend = Backend.objects.select_for_update().get(id=backend.id)
294 85919a0f Christos Stavrakakis
295 dca7553e Christos Stavrakakis
    address = None
296 74459c12 Christos Stavrakakis
    if settings.PUBLIC_USE_POOL:
297 dca7553e Christos Stavrakakis
        (network, address) = allocate_public_address(backend)
298 dca7553e Christos Stavrakakis
    else:
299 dca7553e Christos Stavrakakis
        for net in list(backend_public_networks(backend)):
300 dca7553e Christos Stavrakakis
            pool = net.get_pool()
301 dca7553e Christos Stavrakakis
            if not pool.empty():
302 dca7553e Christos Stavrakakis
                address = 'pool'
303 dca7553e Christos Stavrakakis
                network = net
304 dca7553e Christos Stavrakakis
                break
305 dca7553e Christos Stavrakakis
    if address is None:
306 dca7553e Christos Stavrakakis
        log.error("Public networks of backend %s are full", backend)
307 bd40abfa Christos Stavrakakis
        raise faults.OverLimit("Can not allocate IP for new machine."
308 dca7553e Christos Stavrakakis
                        " Public networks are full.")
309 dca7553e Christos Stavrakakis
    return (network, address)
310 dca7553e Christos Stavrakakis
311 dca7553e Christos Stavrakakis
312 7fede91e Christos Stavrakakis
def backend_public_networks(backend):
313 7fede91e Christos Stavrakakis
    """Return available public networks of the backend.
314 7fede91e Christos Stavrakakis

315 7fede91e Christos Stavrakakis
    Iterator for non-deleted public networks that are available
316 7fede91e Christos Stavrakakis
    to the specified backend.
317 7fede91e Christos Stavrakakis

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

409 b7d38981 Dimitris Aragiorgis
    If link or mac_prefix equals to "pool", then the resources
410 b7d38981 Dimitris Aragiorgis
    are allocated from the corresponding Pools.
411 b7d38981 Dimitris Aragiorgis

412 b7d38981 Dimitris Aragiorgis
    """
413 b7d38981 Dimitris Aragiorgis
    try:
414 b7d38981 Dimitris Aragiorgis
        flavor = Network.FLAVORS[flavor]
415 b7d38981 Dimitris Aragiorgis
    except KeyError:
416 bd40abfa Christos Stavrakakis
        raise faults.BadRequest("Unknown network flavor")
417 b7d38981 Dimitris Aragiorgis
418 b7d38981 Dimitris Aragiorgis
    mode = flavor.get("mode")
419 b7d38981 Dimitris Aragiorgis
420 b7d38981 Dimitris Aragiorgis
    link = flavor.get("link")
421 b7d38981 Dimitris Aragiorgis
    if link == "pool":
422 b7d38981 Dimitris Aragiorgis
        link = allocate_resource("bridge")
423 b7d38981 Dimitris Aragiorgis
424 b7d38981 Dimitris Aragiorgis
    mac_prefix = flavor.get("mac_prefix")
425 b7d38981 Dimitris Aragiorgis
    if mac_prefix == "pool":
426 b7d38981 Dimitris Aragiorgis
        mac_prefix = allocate_resource("mac_prefix")
427 b7d38981 Dimitris Aragiorgis
428 b7d38981 Dimitris Aragiorgis
    tags = flavor.get("tags")
429 b7d38981 Dimitris Aragiorgis
430 b7d38981 Dimitris Aragiorgis
    return mode, link, mac_prefix, tags
431 b7d38981 Dimitris Aragiorgis
432 b7d38981 Dimitris Aragiorgis
433 b7d38981 Dimitris Aragiorgis
def allocate_resource(res_type):
434 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
435 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
436 b7d38981 Dimitris Aragiorgis
    value = pool.get()
437 b7d38981 Dimitris Aragiorgis
    pool.save()
438 b7d38981 Dimitris Aragiorgis
    return value
439 b7d38981 Dimitris Aragiorgis
440 b7d38981 Dimitris Aragiorgis
441 b7d38981 Dimitris Aragiorgis
def release_resource(res_type, value):
442 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
443 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
444 b7d38981 Dimitris Aragiorgis
    pool.put(value)
445 b7d38981 Dimitris Aragiorgis
    pool.save()
446 b7d38981 Dimitris Aragiorgis
447 b7d38981 Dimitris Aragiorgis
448 b7d38981 Dimitris Aragiorgis
def get_pool_table(res_type):
449 b7d38981 Dimitris Aragiorgis
    if res_type == "bridge":
450 b7d38981 Dimitris Aragiorgis
        return BridgePoolTable
451 b7d38981 Dimitris Aragiorgis
    elif res_type == "mac_prefix":
452 b7d38981 Dimitris Aragiorgis
        return MacPrefixPoolTable
453 b7d38981 Dimitris Aragiorgis
    else:
454 b7d38981 Dimitris Aragiorgis
        raise Exception("Unknown resource type")
455 55f562a4 Kostas Papadimitriou
456 55f562a4 Kostas Papadimitriou
457 55f562a4 Kostas Papadimitriou
def get_existing_users():
458 55f562a4 Kostas Papadimitriou
    """
459 55f562a4 Kostas Papadimitriou
    Retrieve user ids stored in cyclades user agnostic models.
460 55f562a4 Kostas Papadimitriou
    """
461 55f562a4 Kostas Papadimitriou
    # also check PublicKeys a user with no servers/networks exist
462 b47b110d Kostas Papadimitriou
    from synnefo.userdata.models import PublicKeyPair
463 55f562a4 Kostas Papadimitriou
    from synnefo.db.models import VirtualMachine, Network
464 55f562a4 Kostas Papadimitriou
465 55f562a4 Kostas Papadimitriou
    keypairusernames = PublicKeyPair.objects.filter().values_list('user',
466 e440e835 Christos Stavrakakis
                                                                  flat=True)
467 55f562a4 Kostas Papadimitriou
    serverusernames = VirtualMachine.objects.filter().values_list('userid',
468 e440e835 Christos Stavrakakis
                                                                  flat=True)
469 55f562a4 Kostas Papadimitriou
    networkusernames = Network.objects.filter().values_list('userid',
470 55f562a4 Kostas Papadimitriou
                                                            flat=True)
471 55f562a4 Kostas Papadimitriou
472 e440e835 Christos Stavrakakis
    return set(list(keypairusernames) + list(serverusernames) +
473 e440e835 Christos Stavrakakis
               list(networkusernames))
474 1b696c26 Christos Stavrakakis
475 1b696c26 Christos Stavrakakis
476 1b696c26 Christos Stavrakakis
def vm_to_links(vm_id):
477 73fbaad3 Christos Stavrakakis
    href = join_urls(SERVERS_URL, str(vm_id))
478 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
479 1b696c26 Christos Stavrakakis
480 1b696c26 Christos Stavrakakis
481 1b696c26 Christos Stavrakakis
def network_to_links(network_id):
482 73fbaad3 Christos Stavrakakis
    href = join_urls(NETWORKS_URL, str(network_id))
483 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
484 1b696c26 Christos Stavrakakis
485 1b696c26 Christos Stavrakakis
486 1b696c26 Christos Stavrakakis
def flavor_to_links(flavor_id):
487 73fbaad3 Christos Stavrakakis
    href = join_urls(FLAVORS_URL, str(flavor_id))
488 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
489 1b696c26 Christos Stavrakakis
490 1b696c26 Christos Stavrakakis
491 1b696c26 Christos Stavrakakis
def image_to_links(image_id):
492 73fbaad3 Christos Stavrakakis
    href = join_urls(IMAGES_URL, str(image_id))
493 73fbaad3 Christos Stavrakakis
    links = [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
494 1b696c26 Christos Stavrakakis
    links.append({"rel": "alternate",
495 73fbaad3 Christos Stavrakakis
                  "href": join_urls(IMAGES_PLANKTON_URL, str(image_id))})
496 1b696c26 Christos Stavrakakis
    return links
497 41a7fae7 Christos Stavrakakis
498 41a7fae7 Christos Stavrakakis
def start_action(vm, action, jobId):
499 41a7fae7 Christos Stavrakakis
    vm.action = action
500 41a7fae7 Christos Stavrakakis
    vm.backendjobid = jobId
501 41a7fae7 Christos Stavrakakis
    vm.backendopcode = None
502 41a7fae7 Christos Stavrakakis
    vm.backendjobstatus = None
503 41a7fae7 Christos Stavrakakis
    vm.backendlogmsg = None
504 41a7fae7 Christos Stavrakakis
    vm.save()