Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (18 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 710b1c43 Christos Stavrakakis
                               Network, NetworkInterface, BridgePoolTable,
51 710b1c43 Christos Stavrakakis
                               MacPrefixPoolTable, IPAddress, IPPoolTable)
52 710b1c43 Christos Stavrakakis
from synnefo.db import pools
53 6dd70a5c Christos Stavrakakis
54 b3fd98ae Christos Stavrakakis
from synnefo.plankton.utils import image_backend
55 9e98ba3c Giorgos Verigakis
56 1b696c26 Christos Stavrakakis
from synnefo.cyclades_settings import cyclades_services, BASE_HOST
57 1b696c26 Christos Stavrakakis
from synnefo.lib.services import get_service_path
58 1b696c26 Christos Stavrakakis
from synnefo.lib import join_urls
59 1b696c26 Christos Stavrakakis
60 1b696c26 Christos Stavrakakis
COMPUTE_URL = \
61 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
62 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "compute", version="v2.0"))
63 1b696c26 Christos Stavrakakis
SERVERS_URL = join_urls(COMPUTE_URL, "servers/")
64 1b696c26 Christos Stavrakakis
NETWORKS_URL = join_urls(COMPUTE_URL, "networks/")
65 1b696c26 Christos Stavrakakis
FLAVORS_URL = join_urls(COMPUTE_URL, "flavors/")
66 1b696c26 Christos Stavrakakis
IMAGES_URL = join_urls(COMPUTE_URL, "images/")
67 1b696c26 Christos Stavrakakis
PLANKTON_URL = \
68 1b696c26 Christos Stavrakakis
    join_urls(BASE_HOST,
69 1b696c26 Christos Stavrakakis
              get_service_path(cyclades_services, "image", version="v1.0"))
70 1b696c26 Christos Stavrakakis
IMAGES_PLANKTON_URL = join_urls(PLANKTON_URL, "images/")
71 1b696c26 Christos Stavrakakis
72 c172f4ab Christos Stavrakakis
PITHOSMAP_PREFIX = "pithosmap://"
73 9e98ba3c Giorgos Verigakis
74 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
75 9e98ba3c Giorgos Verigakis
76 7e2f9d4b Giorgos Verigakis
77 dca2a31f Giorgos Verigakis
def random_password():
78 dca2a31f Giorgos Verigakis
    """Generates a random password
79 ce55f211 Kostas Papadimitriou

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

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

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

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

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

315 710b1c43 Christos Stavrakakis
    Try to allocate a a public IPv4 address from one of the available networks.
316 710b1c43 Christos Stavrakakis
    If 'floating_ip' is set, only networks which are floating IP pools will be
317 710b1c43 Christos Stavrakakis
    used and the IPAddress that will be created will be marked as a floating
318 710b1c43 Christos Stavrakakis
    IP. If 'backend' is set, only the networks that exist in this backend will
319 710b1c43 Christos Stavrakakis
    be used.
320 710b1c43 Christos Stavrakakis

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

433 b7d38981 Dimitris Aragiorgis
    If link or mac_prefix equals to "pool", then the resources
434 b7d38981 Dimitris Aragiorgis
    are allocated from the corresponding Pools.
435 b7d38981 Dimitris Aragiorgis

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