Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / backend_allocator.py @ 18cb3999

History | View | Annotate | Download (5.9 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 710b1c43 Christos Stavrakakis
from django.conf import settings
35 cc7c0f44 Christos Stavrakakis
from synnefo.db.models import Backend
36 710b1c43 Christos Stavrakakis
from synnefo.logic import backend as backend_mod
37 cc7c0f44 Christos Stavrakakis
38 47d1d754 Christos Stavrakakis
log = logging.getLogger(__name__)
39 47d1d754 Christos Stavrakakis
40 cc7c0f44 Christos Stavrakakis
41 cc7c0f44 Christos Stavrakakis
class BackendAllocator():
42 cc7c0f44 Christos Stavrakakis
    """Wrapper class for instance allocation.
43 cc7c0f44 Christos Stavrakakis

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

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

56 adc46059 Christos Stavrakakis
        """
57 5dd9d123 Christos Stavrakakis
58 5dd9d123 Christos Stavrakakis
        backend = None
59 5dd9d123 Christos Stavrakakis
        backend = get_backend_for_user(userid)
60 5dd9d123 Christos Stavrakakis
        if backend:
61 5dd9d123 Christos Stavrakakis
            return backend
62 5dd9d123 Christos Stavrakakis
63 cc7c0f44 Christos Stavrakakis
        # Get the size of the vm
64 cc7c0f44 Christos Stavrakakis
        disk = flavor_disk(flavor)
65 cc7c0f44 Christos Stavrakakis
        ram = flavor.ram
66 cc7c0f44 Christos Stavrakakis
        cpu = flavor.cpu
67 cc7c0f44 Christos Stavrakakis
        vm = {'ram': ram, 'disk': disk, 'cpu': cpu}
68 cc7c0f44 Christos Stavrakakis
69 47d1d754 Christos Stavrakakis
        log.debug("Allocating VM: %r", vm)
70 47d1d754 Christos Stavrakakis
71 cc7c0f44 Christos Stavrakakis
        # Get available backends
72 f15bf3d9 Christos Stavrakakis
        available_backends = get_available_backends(flavor)
73 cc7c0f44 Christos Stavrakakis
74 cc7c0f44 Christos Stavrakakis
        if not available_backends:
75 cc7c0f44 Christos Stavrakakis
            return None
76 cc7c0f44 Christos Stavrakakis
77 cc7c0f44 Christos Stavrakakis
        # Find the best backend to host the vm, based on the allocation
78 cc7c0f44 Christos Stavrakakis
        # strategy
79 7fede91e Christos Stavrakakis
        backend = self.strategy_mod.allocate(available_backends, vm)
80 cc7c0f44 Christos Stavrakakis
81 47d1d754 Christos Stavrakakis
        log.info("Allocated VM %r, in backend %s", vm, backend)
82 47d1d754 Christos Stavrakakis
83 cc7c0f44 Christos Stavrakakis
        # Reduce the free resources of the selected backend by the size of
84 cc7c0f44 Christos Stavrakakis
        # the vm
85 cc7c0f44 Christos Stavrakakis
        reduce_backend_resources(backend, vm)
86 cc7c0f44 Christos Stavrakakis
87 cc7c0f44 Christos Stavrakakis
        return backend
88 cc7c0f44 Christos Stavrakakis
89 cc7c0f44 Christos Stavrakakis
90 f15bf3d9 Christos Stavrakakis
def get_available_backends(flavor):
91 f15bf3d9 Christos Stavrakakis
    """Get the list of available backends that can host a new VM of a flavor.
92 f15bf3d9 Christos Stavrakakis

93 f15bf3d9 Christos Stavrakakis
    The list contains the backends that are online and that have enabled
94 f15bf3d9 Christos Stavrakakis
    the disk_template of the new VM.
95 f15bf3d9 Christos Stavrakakis

96 f15bf3d9 Christos Stavrakakis
    Also, if the new VM will be automatically connected to a public network,
97 f15bf3d9 Christos Stavrakakis
    the backends that do not have an available public IPv4 address are
98 f15bf3d9 Christos Stavrakakis
    excluded.
99 cc7c0f44 Christos Stavrakakis

100 cc7c0f44 Christos Stavrakakis
    """
101 5d1f6b84 Christos Stavrakakis
    disk_template = flavor.disk_template
102 5d1f6b84 Christos Stavrakakis
    # Ganeti knows only the 'ext' disk template, but the flavors disk template
103 5d1f6b84 Christos Stavrakakis
    # includes the provider.
104 5d1f6b84 Christos Stavrakakis
    if disk_template.startswith("ext_"):
105 5d1f6b84 Christos Stavrakakis
        disk_template = "ext"
106 5d1f6b84 Christos Stavrakakis
107 996ddb98 Christos Stavrakakis
    backends = Backend.objects.select_for_update().filter(offline=False,
108 996ddb98 Christos Stavrakakis
                                                          drained=False)
109 c9e99213 Christos Stavrakakis
    # Update the disk_templates if there are empty.
110 c9e99213 Christos Stavrakakis
    [backend_mod.update_backend_disk_templates(b)
111 c9e99213 Christos Stavrakakis
     for b in backends if not b.disk_templates]
112 996ddb98 Christos Stavrakakis
    backends = filter(lambda b: disk_template in b.disk_templates,
113 996ddb98 Christos Stavrakakis
                      list(backends))
114 c9e99213 Christos Stavrakakis
115 c9e99213 Christos Stavrakakis
    # Update the backend stats if it is needed
116 c9e99213 Christos Stavrakakis
    refresh_backends_stats(backends)
117 c9e99213 Christos Stavrakakis
118 8f2aa316 Christos Stavrakakis
    return backends
119 f96f60fd Christos Stavrakakis
120 f96f60fd Christos Stavrakakis
121 cc7c0f44 Christos Stavrakakis
def flavor_disk(flavor):
122 cc7c0f44 Christos Stavrakakis
    """ Get flavor's 'real' disk size
123 cc7c0f44 Christos Stavrakakis

124 cc7c0f44 Christos Stavrakakis
    """
125 cc7c0f44 Christos Stavrakakis
    if flavor.disk_template == 'drbd':
126 cc7c0f44 Christos Stavrakakis
        return flavor.disk * 1024 * 2
127 cc7c0f44 Christos Stavrakakis
    else:
128 cc7c0f44 Christos Stavrakakis
        return flavor.disk * 1024
129 cc7c0f44 Christos Stavrakakis
130 cc7c0f44 Christos Stavrakakis
131 cc7c0f44 Christos Stavrakakis
def reduce_backend_resources(backend, vm):
132 cc7c0f44 Christos Stavrakakis
    """ Conservatively update the resources of a backend.
133 cc7c0f44 Christos Stavrakakis

134 cc7c0f44 Christos Stavrakakis
    Reduce the free resources of the backend by the size of the of the vm that
135 cc7c0f44 Christos Stavrakakis
    will host. This is an underestimation of the backend capabilities.
136 cc7c0f44 Christos Stavrakakis

137 cc7c0f44 Christos Stavrakakis
    """
138 cc7c0f44 Christos Stavrakakis
139 cc7c0f44 Christos Stavrakakis
    new_mfree = backend.mfree - vm['ram']
140 cc7c0f44 Christos Stavrakakis
    new_dfree = backend.dfree - vm['disk']
141 cc7c0f44 Christos Stavrakakis
    backend.mfree = 0 if new_mfree < 0 else new_mfree
142 cc7c0f44 Christos Stavrakakis
    backend.dfree = 0 if new_dfree < 0 else new_dfree
143 cc7c0f44 Christos Stavrakakis
    backend.pinst_cnt += 1
144 cc7c0f44 Christos Stavrakakis
145 cc7c0f44 Christos Stavrakakis
    backend.save()
146 cc7c0f44 Christos Stavrakakis
147 cc7c0f44 Christos Stavrakakis
148 9cf4a3c0 Christos Stavrakakis
def refresh_backends_stats(backends):
149 cc7c0f44 Christos Stavrakakis
    """ Refresh the statistics of the backends.
150 cc7c0f44 Christos Stavrakakis

151 cc7c0f44 Christos Stavrakakis
    Set db backend state to the actual state of the backend, if
152 cc7c0f44 Christos Stavrakakis
    BACKEND_REFRESH_MIN time has passed.
153 cc7c0f44 Christos Stavrakakis

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