Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / backend_allocator.py @ 1da50fe3

History | View | Annotate | Download (6.3 kB)

1 cc7c0f44 Christos Stavrakakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 cc7c0f44 Christos Stavrakakis
#
3 cc7c0f44 Christos Stavrakakis
# Redistribution and use in source and binary forms, with or without
4 cc7c0f44 Christos Stavrakakis
# modification, are permitted provided that the following conditions
5 cc7c0f44 Christos Stavrakakis
# are met:
6 cc7c0f44 Christos Stavrakakis
#
7 cc7c0f44 Christos Stavrakakis
#   1. Redistributions of source code must retain the above copyright
8 cc7c0f44 Christos Stavrakakis
#      notice, this list of conditions and the following disclaimer.
9 cc7c0f44 Christos Stavrakakis
#
10 cc7c0f44 Christos Stavrakakis
#  2. Redistributions in binary form must reproduce the above copyright
11 cc7c0f44 Christos Stavrakakis
#     notice, this list of conditions and the following disclaimer in the
12 cc7c0f44 Christos Stavrakakis
#     documentation and/or other materials provided with the distribution.
13 cc7c0f44 Christos Stavrakakis
#
14 cc7c0f44 Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 cc7c0f44 Christos Stavrakakis
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 cc7c0f44 Christos Stavrakakis
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 cc7c0f44 Christos Stavrakakis
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 cc7c0f44 Christos Stavrakakis
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 cc7c0f44 Christos Stavrakakis
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 cc7c0f44 Christos Stavrakakis
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 cc7c0f44 Christos Stavrakakis
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 cc7c0f44 Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 cc7c0f44 Christos Stavrakakis
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 cc7c0f44 Christos Stavrakakis
# SUCH DAMAGE.
25 cc7c0f44 Christos Stavrakakis
#
26 cc7c0f44 Christos Stavrakakis
# The views and conclusions contained in the software and documentation are
27 cc7c0f44 Christos Stavrakakis
# those of the authors and should not be interpreted as representing official
28 cc7c0f44 Christos Stavrakakis
# policies, either expressed or implied, of GRNET S.A.
29 cc7c0f44 Christos Stavrakakis
30 47d1d754 Christos Stavrakakis
import logging
31 cc7c0f44 Christos Stavrakakis
import datetime
32 cc7c0f44 Christos Stavrakakis
from django.utils import importlib
33 cc7c0f44 Christos Stavrakakis
34 5dd9d123 Christos Stavrakakis
from synnefo.settings import (BACKEND_ALLOCATOR_MODULE, BACKEND_REFRESH_MIN,
35 8f2aa316 Christos Stavrakakis
                              BACKEND_PER_USER, ARCHIPELAGO_BACKENDS,
36 8f2aa316 Christos Stavrakakis
                              DEFAULT_INSTANCE_NETWORKS)
37 cc7c0f44 Christos Stavrakakis
from synnefo.db.models import Backend
38 1da50fe3 Christos Stavrakakis
from synnefo.logic.backend import update_backend_resources
39 f96f60fd Christos Stavrakakis
from synnefo.api.util import backend_public_networks
40 cc7c0f44 Christos Stavrakakis
41 47d1d754 Christos Stavrakakis
log = logging.getLogger(__name__)
42 47d1d754 Christos Stavrakakis
43 cc7c0f44 Christos Stavrakakis
44 cc7c0f44 Christos Stavrakakis
class BackendAllocator():
45 cc7c0f44 Christos Stavrakakis
    """Wrapper class for instance allocation.
46 cc7c0f44 Christos Stavrakakis

47 cc7c0f44 Christos Stavrakakis
    """
48 cc7c0f44 Christos Stavrakakis
    def __init__(self):
49 cc7c0f44 Christos Stavrakakis
        self.strategy_mod =\
50 5dd9d123 Christos Stavrakakis
            importlib.import_module(BACKEND_ALLOCATOR_MODULE)
51 cc7c0f44 Christos Stavrakakis
52 5dd9d123 Christos Stavrakakis
    def allocate(self, userid, flavor):
53 adc46059 Christos Stavrakakis
        """Allocate a vm of the specified flavor to a backend.
54 adc46059 Christos Stavrakakis

55 adc46059 Christos Stavrakakis
        Warning!!: An explicit commit is required after calling this function,
56 adc46059 Christos Stavrakakis
        in order to release the locks acquired by the get_available_backends
57 adc46059 Christos Stavrakakis
        function.
58 adc46059 Christos Stavrakakis

59 adc46059 Christos Stavrakakis
        """
60 5dd9d123 Christos Stavrakakis
61 5dd9d123 Christos Stavrakakis
        backend = None
62 5dd9d123 Christos Stavrakakis
        backend = get_backend_for_user(userid)
63 5dd9d123 Christos Stavrakakis
        if backend:
64 5dd9d123 Christos Stavrakakis
            return backend
65 5dd9d123 Christos Stavrakakis
66 cc7c0f44 Christos Stavrakakis
        # Get the size of the vm
67 cc7c0f44 Christos Stavrakakis
        disk = flavor_disk(flavor)
68 cc7c0f44 Christos Stavrakakis
        ram = flavor.ram
69 cc7c0f44 Christos Stavrakakis
        cpu = flavor.cpu
70 cc7c0f44 Christos Stavrakakis
        vm = {'ram': ram, 'disk': disk, 'cpu': cpu}
71 cc7c0f44 Christos Stavrakakis
72 47d1d754 Christos Stavrakakis
        log.debug("Allocating VM: %r", vm)
73 47d1d754 Christos Stavrakakis
74 cc7c0f44 Christos Stavrakakis
        # Get available backends
75 cc7c0f44 Christos Stavrakakis
        available_backends = get_available_backends()
76 cc7c0f44 Christos Stavrakakis
77 2e1e6844 Christos Stavrakakis
        # Temporary fix for distinquishing archipelagos capable backends
78 2e1e6844 Christos Stavrakakis
        available_backends = filter_archipelagos_backends(available_backends,
79 2e1e6844 Christos Stavrakakis
                                                          flavor.disk_template)
80 9cf4a3c0 Christos Stavrakakis
        # Refresh backends, if needed
81 9cf4a3c0 Christos Stavrakakis
        refresh_backends_stats(available_backends)
82 9cf4a3c0 Christos Stavrakakis
83 cc7c0f44 Christos Stavrakakis
        if not available_backends:
84 cc7c0f44 Christos Stavrakakis
            return None
85 cc7c0f44 Christos Stavrakakis
86 cc7c0f44 Christos Stavrakakis
        # Find the best backend to host the vm, based on the allocation
87 cc7c0f44 Christos Stavrakakis
        # strategy
88 7fede91e Christos Stavrakakis
        backend = self.strategy_mod.allocate(available_backends, vm)
89 cc7c0f44 Christos Stavrakakis
90 47d1d754 Christos Stavrakakis
        log.info("Allocated VM %r, in backend %s", vm, backend)
91 47d1d754 Christos Stavrakakis
92 cc7c0f44 Christos Stavrakakis
        # Reduce the free resources of the selected backend by the size of
93 cc7c0f44 Christos Stavrakakis
        # the vm
94 cc7c0f44 Christos Stavrakakis
        reduce_backend_resources(backend, vm)
95 cc7c0f44 Christos Stavrakakis
96 cc7c0f44 Christos Stavrakakis
        return backend
97 cc7c0f44 Christos Stavrakakis
98 cc7c0f44 Christos Stavrakakis
99 cc7c0f44 Christos Stavrakakis
def get_available_backends():
100 cc7c0f44 Christos Stavrakakis
    """Get available backends from db.
101 cc7c0f44 Christos Stavrakakis

102 cc7c0f44 Christos Stavrakakis
    """
103 f96f60fd Christos Stavrakakis
    backends = list(Backend.objects.select_for_update().filter(drained=False,
104 f96f60fd Christos Stavrakakis
                                                               offline=False))
105 8f2aa316 Christos Stavrakakis
    if "SNF:ANY_PUBLIC" in DEFAULT_INSTANCE_NETWORKS:
106 8f2aa316 Christos Stavrakakis
        backends = filter(lambda x: has_free_ip(x), backends)
107 8f2aa316 Christos Stavrakakis
    return backends
108 f96f60fd Christos Stavrakakis
109 f96f60fd Christos Stavrakakis
110 2e1e6844 Christos Stavrakakis
def filter_archipelagos_backends(available_backends, disk_template):
111 e8aa2f64 Christos Stavrakakis
    if disk_template == "ext":
112 776d2a3f Christos Stavrakakis
        available_backends = filter(lambda x: x.id in ARCHIPELAGO_BACKENDS,
113 2e1e6844 Christos Stavrakakis
                                    available_backends)
114 2e1e6844 Christos Stavrakakis
    else:
115 776d2a3f Christos Stavrakakis
        available_backends = filter(lambda x: x.id not in ARCHIPELAGO_BACKENDS,
116 2e1e6844 Christos Stavrakakis
                                    available_backends)
117 2e1e6844 Christos Stavrakakis
    return available_backends
118 2e1e6844 Christos Stavrakakis
119 2e1e6844 Christos Stavrakakis
120 f96f60fd Christos Stavrakakis
def has_free_ip(backend):
121 f96f60fd Christos Stavrakakis
    """Find if Backend has any free public IP."""
122 f96f60fd Christos Stavrakakis
    for network in backend_public_networks(backend):
123 f96f60fd Christos Stavrakakis
        if not network.get_pool().empty():
124 f96f60fd Christos Stavrakakis
            return True
125 cab31c74 Christos Stavrakakis
    log.warning("No available network in backend %r", backend)
126 f96f60fd Christos Stavrakakis
    return False
127 cc7c0f44 Christos Stavrakakis
128 cc7c0f44 Christos Stavrakakis
129 cc7c0f44 Christos Stavrakakis
def flavor_disk(flavor):
130 cc7c0f44 Christos Stavrakakis
    """ Get flavor's 'real' disk size
131 cc7c0f44 Christos Stavrakakis

132 cc7c0f44 Christos Stavrakakis
    """
133 cc7c0f44 Christos Stavrakakis
    if flavor.disk_template == 'drbd':
134 cc7c0f44 Christos Stavrakakis
        return flavor.disk * 1024 * 2
135 cc7c0f44 Christos Stavrakakis
    else:
136 cc7c0f44 Christos Stavrakakis
        return flavor.disk * 1024
137 cc7c0f44 Christos Stavrakakis
138 cc7c0f44 Christos Stavrakakis
139 cc7c0f44 Christos Stavrakakis
def reduce_backend_resources(backend, vm):
140 cc7c0f44 Christos Stavrakakis
    """ Conservatively update the resources of a backend.
141 cc7c0f44 Christos Stavrakakis

142 cc7c0f44 Christos Stavrakakis
    Reduce the free resources of the backend by the size of the of the vm that
143 cc7c0f44 Christos Stavrakakis
    will host. This is an underestimation of the backend capabilities.
144 cc7c0f44 Christos Stavrakakis

145 cc7c0f44 Christos Stavrakakis
    """
146 cc7c0f44 Christos Stavrakakis
147 cc7c0f44 Christos Stavrakakis
    new_mfree = backend.mfree - vm['ram']
148 cc7c0f44 Christos Stavrakakis
    new_dfree = backend.dfree - vm['disk']
149 cc7c0f44 Christos Stavrakakis
    backend.mfree = 0 if new_mfree < 0 else new_mfree
150 cc7c0f44 Christos Stavrakakis
    backend.dfree = 0 if new_dfree < 0 else new_dfree
151 cc7c0f44 Christos Stavrakakis
    backend.pinst_cnt += 1
152 cc7c0f44 Christos Stavrakakis
153 cc7c0f44 Christos Stavrakakis
    backend.save()
154 cc7c0f44 Christos Stavrakakis
155 cc7c0f44 Christos Stavrakakis
156 9cf4a3c0 Christos Stavrakakis
def refresh_backends_stats(backends):
157 cc7c0f44 Christos Stavrakakis
    """ Refresh the statistics of the backends.
158 cc7c0f44 Christos Stavrakakis

159 cc7c0f44 Christos Stavrakakis
    Set db backend state to the actual state of the backend, if
160 cc7c0f44 Christos Stavrakakis
    BACKEND_REFRESH_MIN time has passed.
161 cc7c0f44 Christos Stavrakakis

162 cc7c0f44 Christos Stavrakakis
    """
163 cc7c0f44 Christos Stavrakakis
164 cc7c0f44 Christos Stavrakakis
    now = datetime.datetime.now()
165 5dd9d123 Christos Stavrakakis
    delta = datetime.timedelta(minutes=BACKEND_REFRESH_MIN)
166 9cf4a3c0 Christos Stavrakakis
    for b in backends:
167 cc7c0f44 Christos Stavrakakis
        if now > b.updated + delta:
168 9cf4a3c0 Christos Stavrakakis
            log.debug("Updating resources of backend %r. Last Updated %r",
169 9cf4a3c0 Christos Stavrakakis
                      b, b.updated)
170 1da50fe3 Christos Stavrakakis
            update_backend_resources(b)
171 5dd9d123 Christos Stavrakakis
172 5dd9d123 Christos Stavrakakis
173 5dd9d123 Christos Stavrakakis
def get_backend_for_user(userid):
174 5dd9d123 Christos Stavrakakis
    """Find fixed Backend for user based on BACKEND_PER_USER setting."""
175 5dd9d123 Christos Stavrakakis
176 5dd9d123 Christos Stavrakakis
    backend = BACKEND_PER_USER.get(userid)
177 5dd9d123 Christos Stavrakakis
178 5dd9d123 Christos Stavrakakis
    if not backend:
179 5dd9d123 Christos Stavrakakis
        return None
180 5dd9d123 Christos Stavrakakis
181 5dd9d123 Christos Stavrakakis
    try:
182 5dd9d123 Christos Stavrakakis
        try:
183 5dd9d123 Christos Stavrakakis
            backend_id = int(backend)
184 5dd9d123 Christos Stavrakakis
            return Backend.objects.get(id=backend_id)
185 5dd9d123 Christos Stavrakakis
        except ValueError:
186 5dd9d123 Christos Stavrakakis
            pass
187 5dd9d123 Christos Stavrakakis
188 5dd9d123 Christos Stavrakakis
        backend_name = str(backend)
189 5dd9d123 Christos Stavrakakis
        return Backend.objects.get(clustername=backend_name)
190 5dd9d123 Christos Stavrakakis
    except Backend.DoesNotExist:
191 5dd9d123 Christos Stavrakakis
        log.error("Invalid backend %s for user %s", backend, userid)