Statistics
| Branch: | Tag: | Revision:

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

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

81 62eac5a6 Giorgos Verigakis
    We generate a windows compliant password: it must contain at least
82 dca2a31f Giorgos Verigakis
    one charachter from each of the groups: upper case, lower case, digits.
83 dca2a31f Giorgos Verigakis
    """
84 ce55f211 Kostas Papadimitriou
85 dca2a31f Giorgos Verigakis
    pool = lowercase + uppercase + digits
86 dca2a31f Giorgos Verigakis
    lowerset = set(lowercase)
87 dca2a31f Giorgos Verigakis
    upperset = set(uppercase)
88 dca2a31f Giorgos Verigakis
    digitset = set(digits)
89 dca2a31f Giorgos Verigakis
    length = 10
90 ce55f211 Kostas Papadimitriou
91 62eac5a6 Giorgos Verigakis
    password = ''.join(choice(pool) for i in range(length - 2))
92 ce55f211 Kostas Papadimitriou
93 62eac5a6 Giorgos Verigakis
    # Make sure the password is compliant
94 62eac5a6 Giorgos Verigakis
    chars = set(password)
95 62eac5a6 Giorgos Verigakis
    if not chars & lowerset:
96 62eac5a6 Giorgos Verigakis
        password += choice(lowercase)
97 62eac5a6 Giorgos Verigakis
    if not chars & upperset:
98 62eac5a6 Giorgos Verigakis
        password += choice(uppercase)
99 62eac5a6 Giorgos Verigakis
    if not chars & digitset:
100 62eac5a6 Giorgos Verigakis
        password += choice(digits)
101 ce55f211 Kostas Papadimitriou
102 62eac5a6 Giorgos Verigakis
    # Pad if necessary to reach required length
103 62eac5a6 Giorgos Verigakis
    password += ''.join(choice(pool) for i in range(length - len(password)))
104 ce55f211 Kostas Papadimitriou
105 dca2a31f Giorgos Verigakis
    return password
106 dca2a31f Giorgos Verigakis
107 d8e50a39 Giorgos Verigakis
108 c738c935 Giorgos Verigakis
def zeropad(s):
109 c738c935 Giorgos Verigakis
    """Add zeros at the end of a string in order to make its length
110 c738c935 Giorgos Verigakis
       a multiple of 16."""
111 d1387ed7 Christodoulos Psaltis
112 c738c935 Giorgos Verigakis
    npad = 16 - len(s) % 16
113 c738c935 Giorgos Verigakis
    return s + '\x00' * npad
114 c738c935 Giorgos Verigakis
115 a08e4270 Vangelis Koukis
116 c738c935 Giorgos Verigakis
def encrypt(plaintext):
117 c738c935 Giorgos Verigakis
    # Make sure key is 32 bytes long
118 c738c935 Giorgos Verigakis
    key = sha256(settings.SECRET_KEY).digest()
119 d1387ed7 Christodoulos Psaltis
120 c738c935 Giorgos Verigakis
    aes = AES.new(key)
121 c738c935 Giorgos Verigakis
    enc = aes.encrypt(zeropad(plaintext))
122 c738c935 Giorgos Verigakis
    return b64encode(enc)
123 c738c935 Giorgos Verigakis
124 7e2f9d4b Giorgos Verigakis
125 7f2dbcad Christos Stavrakakis
def get_vm(server_id, user_id, for_update=False, non_deleted=False,
126 b3a43976 Christos Stavrakakis
           non_suspended=False, prefetch_related=None):
127 e221ade2 Christos Stavrakakis
    """Find a VirtualMachine instance based on ID and owner."""
128 aa197ee4 Vangelis Koukis
129 d8e50a39 Giorgos Verigakis
    try:
130 d8e50a39 Giorgos Verigakis
        server_id = int(server_id)
131 7f2dbcad Christos Stavrakakis
        servers = VirtualMachine.objects
132 7f2dbcad Christos Stavrakakis
        if for_update:
133 7f2dbcad Christos Stavrakakis
            servers = servers.select_for_update()
134 b3a43976 Christos Stavrakakis
        if prefetch_related is not None:
135 b3a43976 Christos Stavrakakis
            servers = servers.prefetch_related(prefetch_related)
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 bcd80cd9 Christos Stavrakakis
    image["id"] = img["id"]
168 bcd80cd9 Christos Stavrakakis
    image["name"] = img["name"]
169 c172f4ab Christos Stavrakakis
    image["format"] = img["disk_format"]
170 c172f4ab Christos Stavrakakis
    image["checksum"] = img["checksum"]
171 c172f4ab Christos Stavrakakis
    image["location"] = img["location"]
172 c172f4ab Christos Stavrakakis
173 c172f4ab Christos Stavrakakis
    checksum = image["checksum"] = img["checksum"]
174 c172f4ab Christos Stavrakakis
    size = image["size"] = img["size"]
175 c172f4ab Christos Stavrakakis
    image["backend_id"] = PITHOSMAP_PREFIX + "/".join([checksum, str(size)])
176 c172f4ab Christos Stavrakakis
177 c172f4ab Christos Stavrakakis
    properties = img.get("properties", {})
178 c172f4ab Christos Stavrakakis
    image["metadata"] = dict((key.upper(), val)
179 dca7553e Christos Stavrakakis
                             for key, val in properties.items())
180 c172f4ab Christos Stavrakakis
181 dca7553e Christos Stavrakakis
    return image
182 dca7553e Christos Stavrakakis
183 dca7553e Christos Stavrakakis
184 aa8230bd Christos Stavrakakis
def get_flavor(flavor_id, include_deleted=False):
185 529178b1 Giorgos Verigakis
    """Return a Flavor instance or raise ItemNotFound."""
186 aa197ee4 Vangelis Koukis
187 529178b1 Giorgos Verigakis
    try:
188 529178b1 Giorgos Verigakis
        flavor_id = int(flavor_id)
189 aa8230bd Christos Stavrakakis
        if include_deleted:
190 aa8230bd Christos Stavrakakis
            return Flavor.objects.get(id=flavor_id)
191 aa8230bd Christos Stavrakakis
        else:
192 aa8230bd Christos Stavrakakis
            return Flavor.objects.get(id=flavor_id, deleted=include_deleted)
193 6ef51e9f Giorgos Verigakis
    except (ValueError, Flavor.DoesNotExist):
194 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Flavor not found.')
195 d8e50a39 Giorgos Verigakis
196 a08e4270 Vangelis Koukis
197 9dcb5b8a Christos Stavrakakis
def get_flavor_provider(flavor):
198 9dcb5b8a Christos Stavrakakis
    """Extract provider from disk template.
199 9dcb5b8a Christos Stavrakakis

200 9dcb5b8a Christos Stavrakakis
    Provider for `ext` disk_template is encoded in the disk template
201 9dcb5b8a Christos Stavrakakis
    name, which is formed `ext_<provider_name>`. Provider is None
202 9dcb5b8a Christos Stavrakakis
    for all other disk templates.
203 9dcb5b8a Christos Stavrakakis

204 9dcb5b8a Christos Stavrakakis
    """
205 9dcb5b8a Christos Stavrakakis
    disk_template = flavor.disk_template
206 9dcb5b8a Christos Stavrakakis
    provider = None
207 9dcb5b8a Christos Stavrakakis
    if disk_template.startswith("ext"):
208 9dcb5b8a Christos Stavrakakis
        disk_template, provider = disk_template.split("_", 1)
209 9dcb5b8a Christos Stavrakakis
    return disk_template, provider
210 9dcb5b8a Christos Stavrakakis
211 95a213d4 Christos Stavrakakis
212 9e8be4fb Christos Stavrakakis
def get_network(network_id, user_id, for_update=False, non_deleted=False):
213 e2ee7808 Giorgos Verigakis
    """Return a Network instance or raise ItemNotFound."""
214 aa197ee4 Vangelis Koukis
215 e2ee7808 Giorgos Verigakis
    try:
216 7fede91e Christos Stavrakakis
        network_id = int(network_id)
217 a96e84cf Christos Stavrakakis
        objects = Network.objects.prefetch_related("subnets")
218 d2e73c0c Christos Stavrakakis
        if for_update:
219 d3406fbc Christos Stavrakakis
            objects = objects.select_for_update()
220 9e8be4fb Christos Stavrakakis
        network = objects.get(Q(userid=user_id) | Q(public=True),
221 9e8be4fb Christos Stavrakakis
                              id=network_id)
222 9e8be4fb Christos Stavrakakis
        if non_deleted and network.deleted:
223 f8675683 Christos Stavrakakis
            raise faults.BadRequest("Network has been deleted.")
224 9e8be4fb Christos Stavrakakis
        return network
225 6ef51e9f Giorgos Verigakis
    except (ValueError, Network.DoesNotExist):
226 710b1c43 Christos Stavrakakis
        raise faults.ItemNotFound('Network %s not found.' % network_id)
227 95a213d4 Christos Stavrakakis
228 95a213d4 Christos Stavrakakis
229 95a213d4 Christos Stavrakakis
def get_port(port_id, user_id, for_update=False):
230 0baa1e3d Buildbot
    """
231 95a213d4 Christos Stavrakakis
    Return a NetworkInteface instance or raise ItemNotFound.
232 0baa1e3d Buildbot
    """
233 0baa1e3d Buildbot
    try:
234 593851e0 Buildbot
        objects = NetworkInterface.objects
235 593851e0 Buildbot
        if for_update:
236 593851e0 Buildbot
            objects = objects.select_for_update()
237 593851e0 Buildbot
238 0069a20c Marios Kogias
        if not user_id:
239 0069a20c Marios Kogias
            port = objects.get(id=port_id)
240 0069a20c Marios Kogias
        else:
241 0069a20c Marios Kogias
            port = objects.get(network__userid=user_id, id=port_id)
242 593851e0 Buildbot
243 593851e0 Buildbot
        if (port.device_owner != "vm") and for_update:
244 95a213d4 Christos Stavrakakis
            raise faults.BadRequest('Can not update non vm port')
245 593851e0 Buildbot
246 593851e0 Buildbot
        return port
247 95a213d4 Christos Stavrakakis
    except (ValueError, NetworkInterface.DoesNotExist):
248 95a213d4 Christos Stavrakakis
        raise faults.ItemNotFound('Port not found.')
249 95a213d4 Christos Stavrakakis
250 0711e5aa Christos Stavrakakis
251 a1713485 Marios Kogias
def get_security_group(sg_id):
252 a1713485 Marios Kogias
    try:
253 a1713485 Marios Kogias
        sg = SecurityGroup.objects.get(id=sg_id)
254 a1713485 Marios Kogias
        return sg
255 a1713485 Marios Kogias
    except (ValueError, SecurityGroup.DoesNotExist):
256 a1713485 Marios Kogias
        raise faults.ItemNotFound("Not valid security group")
257 a08e4270 Vangelis Koukis
258 0711e5aa Christos Stavrakakis
259 710b1c43 Christos Stavrakakis
def get_floating_ip_by_address(userid, address, for_update=False):
260 f8675683 Christos Stavrakakis
    try:
261 326c3ec8 Christos Stavrakakis
        objects = IPAddress.objects
262 f8675683 Christos Stavrakakis
        if for_update:
263 f8675683 Christos Stavrakakis
            objects = objects.select_for_update()
264 710b1c43 Christos Stavrakakis
        return objects.get(userid=userid, floating_ip=True,
265 710b1c43 Christos Stavrakakis
                           address=address, deleted=False)
266 326c3ec8 Christos Stavrakakis
    except IPAddress.DoesNotExist:
267 f8675683 Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP does not exist.")
268 f8675683 Christos Stavrakakis
269 f8675683 Christos Stavrakakis
270 710b1c43 Christos Stavrakakis
def get_floating_ip_by_id(userid, floating_ip_id, for_update=False):
271 710b1c43 Christos Stavrakakis
    try:
272 710b1c43 Christos Stavrakakis
        objects = IPAddress.objects
273 710b1c43 Christos Stavrakakis
        if for_update:
274 710b1c43 Christos Stavrakakis
            objects = objects.select_for_update()
275 d9c36253 Marios Kogias
        return objects.get(id=floating_ip_id, floating_ip=True,
276 0711e5aa Christos Stavrakakis
                           userid=userid, deleted=False)
277 710b1c43 Christos Stavrakakis
    except IPAddress.DoesNotExist:
278 710b1c43 Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP %s does not exist." %
279 710b1c43 Christos Stavrakakis
                                  floating_ip_id)
280 dca7553e Christos Stavrakakis
281 dca7553e Christos Stavrakakis
282 710b1c43 Christos Stavrakakis
def allocate_ip_from_pools(pool_rows, userid, address=None, floating_ip=False):
283 710b1c43 Christos Stavrakakis
    """Try to allocate a value from a number of pools.
284 7fede91e Christos Stavrakakis

285 710b1c43 Christos Stavrakakis
    This function takes as argument a number of PoolTable objects and tries to
286 710b1c43 Christos Stavrakakis
    allocate a value from them. If all pools are empty EmptyPool is raised.
287 7fede91e Christos Stavrakakis

288 7fede91e Christos Stavrakakis
    """
289 710b1c43 Christos Stavrakakis
    for pool_row in pool_rows:
290 710b1c43 Christos Stavrakakis
        pool = pool_row.pool
291 660b9f3b Christos Stavrakakis
        try:
292 710b1c43 Christos Stavrakakis
            value = pool.get(value=address)
293 710b1c43 Christos Stavrakakis
            pool.save()
294 710b1c43 Christos Stavrakakis
            subnet = pool_row.subnet
295 710b1c43 Christos Stavrakakis
            ipaddress = IPAddress.objects.create(subnet=subnet,
296 710b1c43 Christos Stavrakakis
                                                 network=subnet.network,
297 710b1c43 Christos Stavrakakis
                                                 userid=userid,
298 710b1c43 Christos Stavrakakis
                                                 address=value,
299 710b1c43 Christos Stavrakakis
                                                 floating_ip=floating_ip)
300 710b1c43 Christos Stavrakakis
            return ipaddress
301 710b1c43 Christos Stavrakakis
        except pools.EmptyPool:
302 660b9f3b Christos Stavrakakis
            pass
303 710b1c43 Christos Stavrakakis
    raise pools.EmptyPool("No more IP addresses available on pools %s" %
304 710b1c43 Christos Stavrakakis
                          pool_rows)
305 710b1c43 Christos Stavrakakis
306 710b1c43 Christos Stavrakakis
307 710b1c43 Christos Stavrakakis
def allocate_ip(network, userid, address=None, floating_ip=False):
308 710b1c43 Christos Stavrakakis
    """Try to allocate an IP from networks IP pools."""
309 710b1c43 Christos Stavrakakis
    ip_pools = IPPoolTable.objects.select_for_update()\
310 710b1c43 Christos Stavrakakis
        .filter(subnet__network=network)
311 710b1c43 Christos Stavrakakis
    try:
312 710b1c43 Christos Stavrakakis
        return allocate_ip_from_pools(ip_pools, userid, address=address,
313 710b1c43 Christos Stavrakakis
                                      floating_ip=floating_ip)
314 710b1c43 Christos Stavrakakis
    except pools.EmptyPool:
315 710b1c43 Christos Stavrakakis
        raise faults.Conflict("No more IP addresses available on network %s"
316 710b1c43 Christos Stavrakakis
                              % network.id)
317 710b1c43 Christos Stavrakakis
    except pools.ValueNotAvailable:
318 710b1c43 Christos Stavrakakis
        raise faults.Conflict("IP address %s is already used." % address)
319 ae994d2e Christos Stavrakakis
    except pools.InvalidValue:
320 ae994d2e Christos Stavrakakis
        raise faults.BadRequest("Address %s does not belong to network %s" %
321 ae994d2e Christos Stavrakakis
                                (address, network.id))
322 710b1c43 Christos Stavrakakis
323 710b1c43 Christos Stavrakakis
324 710b1c43 Christos Stavrakakis
def allocate_public_ip(userid, floating_ip=False, backend=None):
325 710b1c43 Christos Stavrakakis
    """Try to allocate a public or floating IP address.
326 7fede91e Christos Stavrakakis

327 710b1c43 Christos Stavrakakis
    Try to allocate a a public IPv4 address from one of the available networks.
328 710b1c43 Christos Stavrakakis
    If 'floating_ip' is set, only networks which are floating IP pools will be
329 710b1c43 Christos Stavrakakis
    used and the IPAddress that will be created will be marked as a floating
330 710b1c43 Christos Stavrakakis
    IP. If 'backend' is set, only the networks that exist in this backend will
331 710b1c43 Christos Stavrakakis
    be used.
332 710b1c43 Christos Stavrakakis

333 710b1c43 Christos Stavrakakis
    """
334 7fede91e Christos Stavrakakis
335 710b1c43 Christos Stavrakakis
    ip_pool_rows = IPPoolTable.objects.select_for_update()\
336 710b1c43 Christos Stavrakakis
        .prefetch_related("subnet__network")\
337 710b1c43 Christos Stavrakakis
        .filter(subnet__deleted=False)\
338 710b1c43 Christos Stavrakakis
        .filter(subnet__network__public=True)\
339 710b1c43 Christos Stavrakakis
        .filter(subnet__network__drained=False)
340 710b1c43 Christos Stavrakakis
    if floating_ip:
341 710b1c43 Christos Stavrakakis
        ip_pool_rows = ip_pool_rows\
342 710b1c43 Christos Stavrakakis
            .filter(subnet__network__floating_ip_pool=True)
343 710b1c43 Christos Stavrakakis
    if backend is not None:
344 710b1c43 Christos Stavrakakis
        ip_pool_rows = ip_pool_rows\
345 710b1c43 Christos Stavrakakis
            .filter(subnet__network__backend_networks__backend=backend)
346 7fede91e Christos Stavrakakis
347 34c03a51 Christos Stavrakakis
    try:
348 710b1c43 Christos Stavrakakis
        return allocate_ip_from_pools(ip_pool_rows, userid,
349 710b1c43 Christos Stavrakakis
                                      floating_ip=floating_ip)
350 710b1c43 Christos Stavrakakis
    except pools.EmptyPool:
351 710b1c43 Christos Stavrakakis
        ip_type = "floating" if floating_ip else "public"
352 710b1c43 Christos Stavrakakis
        log_msg = "Failed to allocate a %s IP. Reason:" % ip_type
353 710b1c43 Christos Stavrakakis
        if ip_pool_rows:
354 710b1c43 Christos Stavrakakis
            log_msg += " No network exists."
355 710b1c43 Christos Stavrakakis
        else:
356 710b1c43 Christos Stavrakakis
            log_msg += " All network are full."
357 710b1c43 Christos Stavrakakis
        if backend is not None:
358 710b1c43 Christos Stavrakakis
            log_msg += " Backend: %s" % backend
359 710b1c43 Christos Stavrakakis
        log.error(log_msg)
360 710b1c43 Christos Stavrakakis
        exception_msg = "Can not allocate a %s IP address." % ip_type
361 710b1c43 Christos Stavrakakis
        raise faults.ServiceUnavailable(exception_msg)
362 710b1c43 Christos Stavrakakis
363 710b1c43 Christos Stavrakakis
364 710b1c43 Christos Stavrakakis
def backend_has_free_public_ip(backend):
365 710b1c43 Christos Stavrakakis
    """Check if a backend has a free public IPv4 address."""
366 710b1c43 Christos Stavrakakis
    ip_pool_rows = IPPoolTable.objects.select_for_update()\
367 710b1c43 Christos Stavrakakis
        .filter(subnet__network__public=True)\
368 710b1c43 Christos Stavrakakis
        .filter(subnet__network__drained=False)\
369 710b1c43 Christos Stavrakakis
        .filter(subnet__deleted=False)\
370 710b1c43 Christos Stavrakakis
        .filter(subnet__network__backend_networks__backend=backend)
371 710b1c43 Christos Stavrakakis
    for pool_row in ip_pool_rows:
372 710b1c43 Christos Stavrakakis
        pool = pool_row.pool
373 710b1c43 Christos Stavrakakis
        if pool.empty():
374 710b1c43 Christos Stavrakakis
            continue
375 710b1c43 Christos Stavrakakis
        else:
376 710b1c43 Christos Stavrakakis
            return True
377 710b1c43 Christos Stavrakakis
378 710b1c43 Christos Stavrakakis
379 710b1c43 Christos Stavrakakis
def backend_public_networks(backend):
380 710b1c43 Christos Stavrakakis
    return Network.objects.filter(deleted=False, public=True,
381 710b1c43 Christos Stavrakakis
                                  backend_networks__backend=backend)
382 7fede91e Christos Stavrakakis
383 7fede91e Christos Stavrakakis
384 c988fcca Christos Stavrakakis
def get_vm_nic(vm, nic_id):
385 d0545590 Christos Stavrakakis
    """Get a VMs NIC by its ID."""
386 d44c236b Giorgos Verigakis
    try:
387 7c714455 Christos Stavrakakis
        return vm.nics.get(id=nic_id)
388 d44c236b Giorgos Verigakis
    except NetworkInterface.DoesNotExist:
389 d0545590 Christos Stavrakakis
        raise faults.ItemNotFound("NIC '%s' not found" % nic_id)
390 d44c236b Giorgos Verigakis
391 7fede91e Christos Stavrakakis
392 c988fcca Christos Stavrakakis
def get_nic(nic_id):
393 c988fcca Christos Stavrakakis
    try:
394 c988fcca Christos Stavrakakis
        return NetworkInterface.objects.get(id=nic_id)
395 c988fcca Christos Stavrakakis
    except NetworkInterface.DoesNotExist:
396 c988fcca Christos Stavrakakis
        raise faults.ItemNotFound("NIC '%s' not found" % nic_id)
397 c988fcca Christos Stavrakakis
398 c988fcca Christos Stavrakakis
399 432fc8c3 Giorgos Verigakis
def render_metadata(request, metadata, use_values=False, status=200):
400 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
401 432fc8c3 Giorgos Verigakis
        data = render_to_string('metadata.xml', {'metadata': metadata})
402 432fc8c3 Giorgos Verigakis
    else:
403 b36f78fa Giorgos Verigakis
        if use_values:
404 b36f78fa Giorgos Verigakis
            d = {'metadata': {'values': metadata}}
405 b36f78fa Giorgos Verigakis
        else:
406 b36f78fa Giorgos Verigakis
            d = {'metadata': metadata}
407 432fc8c3 Giorgos Verigakis
        data = json.dumps(d)
408 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
409 432fc8c3 Giorgos Verigakis
410 a08e4270 Vangelis Koukis
411 432fc8c3 Giorgos Verigakis
def render_meta(request, meta, status=200):
412 432fc8c3 Giorgos Verigakis
    if request.serialization == 'xml':
413 32e4e343 Christos Stavrakakis
        key, val = meta.items()[0]
414 6ef51e9f Giorgos Verigakis
        data = render_to_string('meta.xml', dict(key=key, val=val))
415 432fc8c3 Giorgos Verigakis
    else:
416 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(meta=meta))
417 432fc8c3 Giorgos Verigakis
    return HttpResponse(data, status=status)
418 432fc8c3 Giorgos Verigakis
419 a08e4270 Vangelis Koukis
420 dca7553e Christos Stavrakakis
def verify_personality(personality):
421 6ec4694f Christos Stavrakakis
    """Verify that a a list of personalities is well formed"""
422 006c6249 Christos Stavrakakis
    if len(personality) > settings.MAX_PERSONALITY:
423 bd40abfa Christos Stavrakakis
        raise faults.OverLimit("Maximum number of personalities"
424 32e4e343 Christos Stavrakakis
                               " exceeded")
425 dca7553e Christos Stavrakakis
    for p in personality:
426 dca7553e Christos Stavrakakis
        # Verify that personalities are well-formed
427 dca7553e Christos Stavrakakis
        try:
428 dca7553e Christos Stavrakakis
            assert isinstance(p, dict)
429 dca7553e Christos Stavrakakis
            keys = set(p.keys())
430 dca7553e Christos Stavrakakis
            allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
431 dca7553e Christos Stavrakakis
            assert keys.issubset(allowed)
432 dca7553e Christos Stavrakakis
            contents = p['contents']
433 dca7553e Christos Stavrakakis
            if len(contents) > settings.MAX_PERSONALITY_SIZE:
434 dca7553e Christos Stavrakakis
                # No need to decode if contents already exceed limit
435 bd40abfa Christos Stavrakakis
                raise faults.OverLimit("Maximum size of personality exceeded")
436 dca7553e Christos Stavrakakis
            if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
437 bd40abfa Christos Stavrakakis
                raise faults.OverLimit("Maximum size of personality exceeded")
438 dca7553e Christos Stavrakakis
        except AssertionError:
439 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Malformed personality in request")
440 2a599282 Christos Stavrakakis
441 2a599282 Christos Stavrakakis
442 b7d38981 Dimitris Aragiorgis
def values_from_flavor(flavor):
443 b7d38981 Dimitris Aragiorgis
    """Get Ganeti connectivity info from flavor type.
444 b7d38981 Dimitris Aragiorgis

445 b7d38981 Dimitris Aragiorgis
    If link or mac_prefix equals to "pool", then the resources
446 b7d38981 Dimitris Aragiorgis
    are allocated from the corresponding Pools.
447 b7d38981 Dimitris Aragiorgis

448 b7d38981 Dimitris Aragiorgis
    """
449 b7d38981 Dimitris Aragiorgis
    try:
450 b7d38981 Dimitris Aragiorgis
        flavor = Network.FLAVORS[flavor]
451 b7d38981 Dimitris Aragiorgis
    except KeyError:
452 bd40abfa Christos Stavrakakis
        raise faults.BadRequest("Unknown network flavor")
453 b7d38981 Dimitris Aragiorgis
454 b7d38981 Dimitris Aragiorgis
    mode = flavor.get("mode")
455 b7d38981 Dimitris Aragiorgis
456 b7d38981 Dimitris Aragiorgis
    link = flavor.get("link")
457 b7d38981 Dimitris Aragiorgis
    if link == "pool":
458 b7d38981 Dimitris Aragiorgis
        link = allocate_resource("bridge")
459 b7d38981 Dimitris Aragiorgis
460 b7d38981 Dimitris Aragiorgis
    mac_prefix = flavor.get("mac_prefix")
461 b7d38981 Dimitris Aragiorgis
    if mac_prefix == "pool":
462 b7d38981 Dimitris Aragiorgis
        mac_prefix = allocate_resource("mac_prefix")
463 b7d38981 Dimitris Aragiorgis
464 b7d38981 Dimitris Aragiorgis
    tags = flavor.get("tags")
465 b7d38981 Dimitris Aragiorgis
466 b7d38981 Dimitris Aragiorgis
    return mode, link, mac_prefix, tags
467 b7d38981 Dimitris Aragiorgis
468 b7d38981 Dimitris Aragiorgis
469 b7d38981 Dimitris Aragiorgis
def allocate_resource(res_type):
470 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
471 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
472 b7d38981 Dimitris Aragiorgis
    value = pool.get()
473 b7d38981 Dimitris Aragiorgis
    pool.save()
474 b7d38981 Dimitris Aragiorgis
    return value
475 b7d38981 Dimitris Aragiorgis
476 b7d38981 Dimitris Aragiorgis
477 b7d38981 Dimitris Aragiorgis
def release_resource(res_type, value):
478 b7d38981 Dimitris Aragiorgis
    table = get_pool_table(res_type)
479 b7d38981 Dimitris Aragiorgis
    pool = table.get_pool()
480 b7d38981 Dimitris Aragiorgis
    pool.put(value)
481 b7d38981 Dimitris Aragiorgis
    pool.save()
482 b7d38981 Dimitris Aragiorgis
483 b7d38981 Dimitris Aragiorgis
484 b7d38981 Dimitris Aragiorgis
def get_pool_table(res_type):
485 b7d38981 Dimitris Aragiorgis
    if res_type == "bridge":
486 b7d38981 Dimitris Aragiorgis
        return BridgePoolTable
487 b7d38981 Dimitris Aragiorgis
    elif res_type == "mac_prefix":
488 b7d38981 Dimitris Aragiorgis
        return MacPrefixPoolTable
489 b7d38981 Dimitris Aragiorgis
    else:
490 b7d38981 Dimitris Aragiorgis
        raise Exception("Unknown resource type")
491 55f562a4 Kostas Papadimitriou
492 55f562a4 Kostas Papadimitriou
493 55f562a4 Kostas Papadimitriou
def get_existing_users():
494 55f562a4 Kostas Papadimitriou
    """
495 55f562a4 Kostas Papadimitriou
    Retrieve user ids stored in cyclades user agnostic models.
496 55f562a4 Kostas Papadimitriou
    """
497 55f562a4 Kostas Papadimitriou
    # also check PublicKeys a user with no servers/networks exist
498 b47b110d Kostas Papadimitriou
    from synnefo.userdata.models import PublicKeyPair
499 55f562a4 Kostas Papadimitriou
    from synnefo.db.models import VirtualMachine, Network
500 55f562a4 Kostas Papadimitriou
501 55f562a4 Kostas Papadimitriou
    keypairusernames = PublicKeyPair.objects.filter().values_list('user',
502 e440e835 Christos Stavrakakis
                                                                  flat=True)
503 55f562a4 Kostas Papadimitriou
    serverusernames = VirtualMachine.objects.filter().values_list('userid',
504 e440e835 Christos Stavrakakis
                                                                  flat=True)
505 55f562a4 Kostas Papadimitriou
    networkusernames = Network.objects.filter().values_list('userid',
506 55f562a4 Kostas Papadimitriou
                                                            flat=True)
507 55f562a4 Kostas Papadimitriou
508 e440e835 Christos Stavrakakis
    return set(list(keypairusernames) + list(serverusernames) +
509 e440e835 Christos Stavrakakis
               list(networkusernames))
510 1b696c26 Christos Stavrakakis
511 1b696c26 Christos Stavrakakis
512 1b696c26 Christos Stavrakakis
def vm_to_links(vm_id):
513 73fbaad3 Christos Stavrakakis
    href = join_urls(SERVERS_URL, str(vm_id))
514 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
515 1b696c26 Christos Stavrakakis
516 1b696c26 Christos Stavrakakis
517 1b696c26 Christos Stavrakakis
def network_to_links(network_id):
518 73fbaad3 Christos Stavrakakis
    href = join_urls(NETWORKS_URL, str(network_id))
519 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
520 1b696c26 Christos Stavrakakis
521 1b696c26 Christos Stavrakakis
522 1b696c26 Christos Stavrakakis
def flavor_to_links(flavor_id):
523 73fbaad3 Christos Stavrakakis
    href = join_urls(FLAVORS_URL, str(flavor_id))
524 73fbaad3 Christos Stavrakakis
    return [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
525 1b696c26 Christos Stavrakakis
526 1b696c26 Christos Stavrakakis
527 1b696c26 Christos Stavrakakis
def image_to_links(image_id):
528 73fbaad3 Christos Stavrakakis
    href = join_urls(IMAGES_URL, str(image_id))
529 73fbaad3 Christos Stavrakakis
    links = [{"rel": rel, "href": href} for rel in ("self", "bookmark")]
530 1b696c26 Christos Stavrakakis
    links.append({"rel": "alternate",
531 73fbaad3 Christos Stavrakakis
                  "href": join_urls(IMAGES_PLANKTON_URL, str(image_id))})
532 1b696c26 Christos Stavrakakis
    return links
533 41a7fae7 Christos Stavrakakis
534 32e4e343 Christos Stavrakakis
535 41a7fae7 Christos Stavrakakis
def start_action(vm, action, jobId):
536 41a7fae7 Christos Stavrakakis
    vm.action = action
537 41a7fae7 Christos Stavrakakis
    vm.backendjobid = jobId
538 41a7fae7 Christos Stavrakakis
    vm.backendopcode = None
539 41a7fae7 Christos Stavrakakis
    vm.backendjobstatus = None
540 41a7fae7 Christos Stavrakakis
    vm.backendlogmsg = None
541 41a7fae7 Christos Stavrakakis
    vm.save()