Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (16.6 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 9ae613af Christos Stavrakakis
import ipaddr
35 c738c935 Giorgos Verigakis
36 dca7553e Christos Stavrakakis
from base64 import b64encode, b64decode
37 c738c935 Giorgos Verigakis
from hashlib import sha256
38 2035039b Giorgos Verigakis
from logging import getLogger
39 d8e50a39 Giorgos Verigakis
from random import choice
40 dca2a31f Giorgos Verigakis
from string import digits, lowercase, uppercase
41 2035039b Giorgos Verigakis
42 c738c935 Giorgos Verigakis
from Crypto.Cipher import AES
43 529178b1 Giorgos Verigakis
44 d8e50a39 Giorgos Verigakis
from django.conf import settings
45 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
46 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
47 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
48 d3406fbc Christos Stavrakakis
from django.db.models import Q
49 7e2f9d4b Giorgos Verigakis
50 bd40abfa Christos Stavrakakis
from snf_django.lib.api import faults
51 6ef51e9f Giorgos Verigakis
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
52 7fede91e Christos Stavrakakis
                               Network, BackendNetwork, NetworkInterface,
53 f8675683 Christos Stavrakakis
                               BridgePoolTable, MacPrefixPoolTable, Backend,
54 f8675683 Christos Stavrakakis
                               FloatingIP)
55 adc46059 Christos Stavrakakis
from synnefo.db.pools import EmptyPool
56 6dd70a5c Christos Stavrakakis
57 b3fd98ae Christos Stavrakakis
from synnefo.plankton.utils import image_backend
58 b14725eb Christos Stavrakakis
from synnefo.settings import MAX_CIDR_BLOCK
59 9e98ba3c Giorgos Verigakis
60 1b696c26 Christos Stavrakakis
from synnefo.cyclades_settings import cyclades_services, BASE_HOST
61 1b696c26 Christos Stavrakakis
from synnefo.lib.services import get_service_path
62 1b696c26 Christos Stavrakakis
from synnefo.lib import join_urls
63 1b696c26 Christos Stavrakakis
64 1b696c26 Christos Stavrakakis
COMPUTE_URL = \
65 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
66 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "compute", version="v2.0"))
67 1b696c26 Christos Stavrakakis
SERVERS_URL = join_urls(COMPUTE_URL, "servers/")
68 1b696c26 Christos Stavrakakis
NETWORKS_URL = join_urls(COMPUTE_URL, "networks/")
69 1b696c26 Christos Stavrakakis
FLAVORS_URL = join_urls(COMPUTE_URL, "flavors/")
70 1b696c26 Christos Stavrakakis
IMAGES_URL = join_urls(COMPUTE_URL, "images/")
71 1b696c26 Christos Stavrakakis
PLANKTON_URL = \
72 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
73 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "image", version="v1.0"))
74 1b696c26 Christos Stavrakakis
IMAGES_PLANKTON_URL = join_urls(PLANKTON_URL, "images/")
75 1b696c26 Christos Stavrakakis
76 9e98ba3c Giorgos Verigakis
77 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
78 9e98ba3c Giorgos Verigakis
79 7e2f9d4b Giorgos Verigakis
80 dca2a31f Giorgos Verigakis
def random_password():
81 dca2a31f Giorgos Verigakis
    """Generates a random password
82 ce55f211 Kostas Papadimitriou

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

195 9dcb5b8a Christos Stavrakakis
    Provider for `ext` disk_template is encoded in the disk template
196 9dcb5b8a Christos Stavrakakis
    name, which is formed `ext_<provider_name>`. Provider is None
197 9dcb5b8a Christos Stavrakakis
    for all other disk templates.
198 9dcb5b8a Christos Stavrakakis

199 9dcb5b8a Christos Stavrakakis
    """
200 9dcb5b8a Christos Stavrakakis
    disk_template = flavor.disk_template
201 9dcb5b8a Christos Stavrakakis
    provider = None
202 9dcb5b8a Christos Stavrakakis
    if disk_template.startswith("ext"):
203 9dcb5b8a Christos Stavrakakis
        disk_template, provider = disk_template.split("_", 1)
204 9dcb5b8a Christos Stavrakakis
    return disk_template, provider
205 9dcb5b8a Christos Stavrakakis
206 9dcb5b8a Christos Stavrakakis
207 9e8be4fb Christos Stavrakakis
def get_network(network_id, user_id, for_update=False, non_deleted=False):
208 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
209 aa197ee4 Vangelis Koukis
210 e2ee7808 Giorgos Verigakis
    try:
211 7fede91e Christos Stavrakakis
        network_id = int(network_id)
212 d3406fbc Christos Stavrakakis
        objects = Network.objects
213 d2e73c0c Christos Stavrakakis
        if for_update:
214 d3406fbc Christos Stavrakakis
            objects = objects.select_for_update()
215 9e8be4fb Christos Stavrakakis
        network = objects.get(Q(userid=user_id) | Q(public=True),
216 9e8be4fb Christos Stavrakakis
                              id=network_id)
217 9e8be4fb Christos Stavrakakis
        if non_deleted and network.deleted:
218 f8675683 Christos Stavrakakis
            raise faults.BadRequest("Network has been deleted.")
219 9e8be4fb Christos Stavrakakis
        return network
220 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
221 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Network not found.')
222 e2ee7808 Giorgos Verigakis
223 a08e4270 Vangelis Koukis
224 f8675683 Christos Stavrakakis
def get_floating_ip(user_id, ipv4, for_update=False):
225 f8675683 Christos Stavrakakis
    try:
226 f8675683 Christos Stavrakakis
        objects = FloatingIP.objects
227 f8675683 Christos Stavrakakis
        if for_update:
228 f8675683 Christos Stavrakakis
            objects = objects.select_for_update()
229 f8675683 Christos Stavrakakis
        return objects.get(userid=user_id, ipv4=ipv4, deleted=False)
230 f8675683 Christos Stavrakakis
    except FloatingIP.DoesNotExist:
231 f8675683 Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP does not exist.")
232 f8675683 Christos Stavrakakis
233 f8675683 Christos Stavrakakis
234 5aeb4e93 Christos Stavrakakis
def validate_network_params(subnet=None, gateway=None, subnet6=None,
235 5aeb4e93 Christos Stavrakakis
                            gateway6=None):
236 5aeb4e93 Christos Stavrakakis
    if (subnet is None) and (subnet6 is None):
237 5aeb4e93 Christos Stavrakakis
        raise faults.BadRequest("subnet or subnet6 is required")
238 9ae613af Christos Stavrakakis
239 5aeb4e93 Christos Stavrakakis
    if subnet:
240 9ae613af Christos Stavrakakis
        try:
241 5aeb4e93 Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
242 5aeb4e93 Christos Stavrakakis
            network = ipaddr.IPv4Network(subnet, strict=True)
243 9ae613af Christos Stavrakakis
        except ValueError:
244 5aeb4e93 Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 subnet")
245 5aeb4e93 Christos Stavrakakis
246 5aeb4e93 Christos Stavrakakis
        # Check that network size is allowed!
247 5aeb4e93 Christos Stavrakakis
        if not validate_network_size(network.prefixlen):
248 5aeb4e93 Christos Stavrakakis
            raise faults.OverLimit(message="Unsupported network size",
249 5aeb4e93 Christos Stavrakakis
                                   details="Network mask must be in range"
250 5aeb4e93 Christos Stavrakakis
                                           " (%s, 29]" % MAX_CIDR_BLOCK)
251 5aeb4e93 Christos Stavrakakis
        if gateway:  # Check that gateway belongs to network
252 5aeb4e93 Christos Stavrakakis
            try:
253 5aeb4e93 Christos Stavrakakis
                gateway = ipaddr.IPv4Address(gateway)
254 5aeb4e93 Christos Stavrakakis
            except ValueError:
255 5aeb4e93 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
256 5aeb4e93 Christos Stavrakakis
            if not gateway in network:
257 5aeb4e93 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
258 9ae613af Christos Stavrakakis
259 9ae613af Christos Stavrakakis
    if subnet6:
260 9ae613af Christos Stavrakakis
        try:
261 9ae613af Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
262 9ae613af Christos Stavrakakis
            network6 = ipaddr.IPv6Network(subnet6, strict=True)
263 9ae613af Christos Stavrakakis
        except ValueError:
264 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv6 subnet")
265 9ae613af Christos Stavrakakis
        if gateway6:
266 9ae613af Christos Stavrakakis
            try:
267 9ae613af Christos Stavrakakis
                gateway6 = ipaddr.IPv6Address(gateway6)
268 9ae613af Christos Stavrakakis
            except ValueError:
269 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
270 9ae613af Christos Stavrakakis
            if not gateway6 in network6:
271 bd40abfa Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
272 d368ec0c Christos Stavrakakis
273 d368ec0c Christos Stavrakakis
274 b14725eb Christos Stavrakakis
def validate_network_size(cidr_block):
275 b14725eb Christos Stavrakakis
    """Return True if network size is allowed."""
276 b14725eb Christos Stavrakakis
    return cidr_block <= 29 and cidr_block > MAX_CIDR_BLOCK
277 b14725eb Christos Stavrakakis
278 b14725eb Christos Stavrakakis
279 adc46059 Christos Stavrakakis
def allocate_public_address(backend):
280 660b9f3b Christos Stavrakakis
    """Get a public IP for any available network of a backend."""
281 85919a0f Christos Stavrakakis
    # Guarantee exclusive access to backend, because accessing the IP pools of
282 85919a0f Christos Stavrakakis
    # the backend networks may result in a deadlock with backend allocator
283 85919a0f Christos Stavrakakis
    # which also checks that backend networks have a free IP.
284 85919a0f Christos Stavrakakis
    backend = Backend.objects.select_for_update().get(id=backend.id)
285 660b9f3b Christos Stavrakakis
    public_networks = backend_public_networks(backend)
286 660b9f3b Christos Stavrakakis
    return get_free_ip(public_networks)
287 dca7553e Christos Stavrakakis
288 dca7553e Christos Stavrakakis
289 7fede91e Christos Stavrakakis
def backend_public_networks(backend):
290 7fede91e Christos Stavrakakis
    """Return available public networks of the backend.
291 7fede91e Christos Stavrakakis

292 7fede91e Christos Stavrakakis
    Iterator for non-deleted public networks that are available
293 7fede91e Christos Stavrakakis
    to the specified backend.
294 7fede91e Christos Stavrakakis

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

400 b7d38981 Dimitris Aragiorgis
    If link or mac_prefix equals to "pool", then the resources
401 b7d38981 Dimitris Aragiorgis
    are allocated from the corresponding Pools.
402 b7d38981 Dimitris Aragiorgis

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