Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / backend.py @ b578d9e7

History | View | Annotate | Download (24.1 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 37ca953f 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 37ca953f 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 37ca953f 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 37ca953f 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 37ca953f 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 02feca11 Vassilios Karakoidas
34 2b1db26f Giorgos Verigakis
import json
35 2b1db26f Giorgos Verigakis
36 529178b1 Giorgos Verigakis
from django.conf import settings
37 207b70d5 Giorgos Verigakis
from django.db import transaction
38 1a894bfe Christos Stavrakakis
from datetime import datetime
39 207b70d5 Giorgos Verigakis
40 22ee6892 Christos Stavrakakis
from synnefo.db.models import (Backend, VirtualMachine, Network,
41 3524241a Christos Stavrakakis
                               BackendNetwork, BACKEND_STATUSES,
42 b16db49b Kostas Papadimitriou
                               pooled_rapi_client, VirtualMachineDiagnostic)
43 03992c72 Christos Stavrakakis
from synnefo.logic import utils
44 529178b1 Giorgos Verigakis
45 3524241a Christos Stavrakakis
from logging import getLogger
46 3524241a Christos Stavrakakis
log = getLogger(__name__)
47 9e98ba3c Giorgos Verigakis
48 529178b1 Giorgos Verigakis
49 efff6193 Giorgos Verigakis
_firewall_tags = {
50 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
51 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
52 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
53 efff6193 Giorgos Verigakis
54 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
55 efff6193 Giorgos Verigakis
56 02feca11 Vassilios Karakoidas
57 093f9c53 Vangelis Koukis
@transaction.commit_on_success
58 c4e55622 Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg):
59 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
60 02feca11 Vassilios Karakoidas

61 02feca11 Vassilios Karakoidas
    Process an incoming message from the backend (currently Ganeti).
62 02feca11 Vassilios Karakoidas
    Job notifications with a terminating status (sucess, error, or canceled),
63 02feca11 Vassilios Karakoidas
    also update the operating state of the VM.
64 02feca11 Vassilios Karakoidas

65 02feca11 Vassilios Karakoidas
    """
66 41303ed0 Vangelis Koukis
    # See #1492, #1031, #1111 why this line has been removed
67 41303ed0 Vangelis Koukis
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
68 fd65ab41 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
69 02feca11 Vassilios Karakoidas
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
70 02feca11 Vassilios Karakoidas
71 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = jobid
72 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = status
73 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = opcode
74 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = logmsg
75 02feca11 Vassilios Karakoidas
76 02feca11 Vassilios Karakoidas
    # Notifications of success change the operating state
77 41303ed0 Vangelis Koukis
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
78 41303ed0 Vangelis Koukis
    if status == 'success' and state_for_success is not None:
79 c4ce868e Christos Stavrakakis
        vm.operstate = state_for_success
80 685b219e Vangelis Koukis
81 7d43565f Kostas Papadimitriou
82 91954b45 Christos Stavrakakis
    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
83 91954b45 Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_INSTANCE_CREATE':
84 c4ce868e Christos Stavrakakis
        vm.operstate = 'ERROR'
85 c4ce868e Christos Stavrakakis
        vm.backendtime = etime
86 093f9c53 Vangelis Koukis
87 e97288bc Christos Stavrakakis
    if opcode == 'OP_INSTANCE_REMOVE':
88 e97288bc Christos Stavrakakis
        # Set the deleted flag explicitly, cater for admin-initiated removals
89 e97288bc Christos Stavrakakis
        # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
90 e97288bc Christos Stavrakakis
        # when no instance exists at the Ganeti backend.
91 e97288bc Christos Stavrakakis
        # See ticket #799 for all the details.
92 e97288bc Christos Stavrakakis
        #
93 e97288bc Christos Stavrakakis
        if status == 'success' or (status == 'error' and
94 e97288bc Christos Stavrakakis
                                   vm.operstate == 'ERROR'):
95 e97288bc Christos Stavrakakis
            release_instance_nics(vm)
96 e97288bc Christos Stavrakakis
            vm.nics.all().delete()
97 e97288bc Christos Stavrakakis
            vm.deleted = True
98 e97288bc Christos Stavrakakis
            vm.operstate = state_for_success
99 e97288bc Christos Stavrakakis
            vm.backendtime = etime
100 093f9c53 Vangelis Koukis
101 c4ce868e Christos Stavrakakis
    # Update backendtime only for jobs that have been successfully completed,
102 c4ce868e Christos Stavrakakis
    # since only these jobs update the state of the VM. Else a "race condition"
103 c4ce868e Christos Stavrakakis
    # may occur when a successful job (e.g. OP_INSTANCE_REMOVE) completes
104 c4ce868e Christos Stavrakakis
    # before an error job and messages arrive in reversed order.
105 c4ce868e Christos Stavrakakis
    if status == 'success':
106 c4ce868e Christos Stavrakakis
        vm.backendtime = etime
107 02feca11 Vassilios Karakoidas
108 02feca11 Vassilios Karakoidas
    vm.save()
109 22e52ede Vassilios Karakoidas
110 ad2d6807 Vangelis Koukis
111 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
112 c4e55622 Christos Stavrakakis
def process_net_status(vm, etime, nics):
113 ad2d6807 Vangelis Koukis
    """Process a net status notification from the backend
114 ad2d6807 Vangelis Koukis

115 ad2d6807 Vangelis Koukis
    Process an incoming message from the Ganeti backend,
116 ad2d6807 Vangelis Koukis
    detailing the NIC configuration of a VM instance.
117 ad2d6807 Vangelis Koukis

118 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
119 ad2d6807 Vangelis Koukis
    """
120 37ca953f Christodoulos Psaltis
121 b578d9e7 Christos Stavrakakis
    ganeti_nics = process_ganeti_nics(nics)
122 b578d9e7 Christos Stavrakakis
    if not nics_changed(vm.nics.order_by('index'), ganeti_nics):
123 b578d9e7 Christos Stavrakakis
        log.debug("NICs for VM %s have not changed", vm)
124 b578d9e7 Christos Stavrakakis
125 fdc94944 Christos Stavrakakis
    release_instance_nics(vm)
126 77f0fa63 Christos Stavrakakis
127 b578d9e7 Christos Stavrakakis
    for nic in ganeti_nics:
128 b578d9e7 Christos Stavrakakis
        ipv4 = nic.get('ipv4', '')
129 b578d9e7 Christos Stavrakakis
        if ipv4:
130 b578d9e7 Christos Stavrakakis
            net = nic['network']
131 b578d9e7 Christos Stavrakakis
            net.reserve_address(ipv4)
132 b578d9e7 Christos Stavrakakis
133 b578d9e7 Christos Stavrakakis
        nic['dirty'] = False
134 b578d9e7 Christos Stavrakakis
        vm.nics.create(**nic)
135 b578d9e7 Christos Stavrakakis
        # Dummy save the network, because UI uses changed-since for VMs
136 b578d9e7 Christos Stavrakakis
        # and Networks in order to show the VM NICs
137 b578d9e7 Christos Stavrakakis
        net.save()
138 b578d9e7 Christos Stavrakakis
139 b578d9e7 Christos Stavrakakis
    vm.backendtime = etime
140 b578d9e7 Christos Stavrakakis
    vm.save()
141 b578d9e7 Christos Stavrakakis
142 b578d9e7 Christos Stavrakakis
143 b578d9e7 Christos Stavrakakis
def process_ganeti_nics(ganeti_nics):
144 b578d9e7 Christos Stavrakakis
    """Process NIC dict from ganeti hooks."""
145 b578d9e7 Christos Stavrakakis
    new_nics = []
146 b578d9e7 Christos Stavrakakis
    for i, new_nic in enumerate(ganeti_nics):
147 77f0fa63 Christos Stavrakakis
        network = new_nic.get('network', '')
148 22ee6892 Christos Stavrakakis
        n = str(network)
149 77f0fa63 Christos Stavrakakis
        pk = utils.id_from_network_name(n)
150 77f0fa63 Christos Stavrakakis
151 fdc94944 Christos Stavrakakis
        net = Network.objects.get(pk=pk)
152 77f0fa63 Christos Stavrakakis
153 77f0fa63 Christos Stavrakakis
        # Get the new nic info
154 77f0fa63 Christos Stavrakakis
        mac = new_nic.get('mac', '')
155 77f0fa63 Christos Stavrakakis
        ipv4 = new_nic.get('ip', '')
156 77f0fa63 Christos Stavrakakis
        ipv6 = new_nic.get('ipv6', '')
157 9afeb669 Kostas Papadimitriou
158 77f0fa63 Christos Stavrakakis
        firewall = new_nic.get('firewall', '')
159 658a825a Giorgos Verigakis
        firewall_profile = _reverse_tags.get(firewall, '')
160 658a825a Giorgos Verigakis
        if not firewall_profile and net.public:
161 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
162 9afeb669 Kostas Papadimitriou
163 b578d9e7 Christos Stavrakakis
        nic = {
164 b578d9e7 Christos Stavrakakis
               'index': i,
165 b578d9e7 Christos Stavrakakis
               'network': net,
166 b578d9e7 Christos Stavrakakis
               'mac': mac,
167 b578d9e7 Christos Stavrakakis
               'ipv4': ipv4,
168 b578d9e7 Christos Stavrakakis
               'ipv6': ipv6,
169 b578d9e7 Christos Stavrakakis
               'firewall_profile': firewall_profile}
170 b578d9e7 Christos Stavrakakis
171 b578d9e7 Christos Stavrakakis
        new_nics.append(nic)
172 b578d9e7 Christos Stavrakakis
    return new_nics
173 b578d9e7 Christos Stavrakakis
174 b578d9e7 Christos Stavrakakis
175 b578d9e7 Christos Stavrakakis
def nics_changed(old_nics, new_nics):
176 b578d9e7 Christos Stavrakakis
    """Return True if NICs have changed in any way."""
177 b578d9e7 Christos Stavrakakis
    if len(old_nics) != len(new_nics):
178 b578d9e7 Christos Stavrakakis
        return True
179 b578d9e7 Christos Stavrakakis
    for old_nic, new_nic in zip(old_nics, new_nics):
180 b578d9e7 Christos Stavrakakis
        if not (old_nic.ipv4 == new_nic['ipv4'] and\
181 b578d9e7 Christos Stavrakakis
                old_nic.ipv6 == new_nic['ipv6'] and\
182 b578d9e7 Christos Stavrakakis
                old_nic.mac == new_nic['mac'] and\
183 b578d9e7 Christos Stavrakakis
                old_nic.firewall_profile == new_nic['firewall_profile'] and\
184 b578d9e7 Christos Stavrakakis
                old_nic.index == new_nic['index'] and\
185 b578d9e7 Christos Stavrakakis
                old_nic.network == new_nic['network']):
186 b578d9e7 Christos Stavrakakis
            return True
187 b578d9e7 Christos Stavrakakis
    return False
188 22ee6892 Christos Stavrakakis
189 22ee6892 Christos Stavrakakis
190 bd392934 Christos Stavrakakis
def release_instance_nics(vm):
191 bd392934 Christos Stavrakakis
    for nic in vm.nics.all():
192 40ef487d Christos Stavrakakis
        net = nic.network
193 fa454545 Christos Stavrakakis
        if nic.ipv4:
194 40ef487d Christos Stavrakakis
            net.release_address(nic.ipv4)
195 bd392934 Christos Stavrakakis
        nic.delete()
196 40ef487d Christos Stavrakakis
        net.save()
197 bd392934 Christos Stavrakakis
198 bd392934 Christos Stavrakakis
199 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
200 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
201 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
202 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
203 22ee6892 Christos Stavrakakis
204 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
205 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
206 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
207 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
208 22ee6892 Christos Stavrakakis
209 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
210 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
211 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
212 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
213 22ee6892 Christos Stavrakakis
214 9c65f166 Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_CREATE':
215 22ee6892 Christos Stavrakakis
        utils.update_state(back_network, 'ERROR')
216 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
217 22ee6892 Christos Stavrakakis
218 e97288bc Christos Stavrakakis
    if opcode == 'OP_NETWORK_REMOVE':
219 e97288bc Christos Stavrakakis
        if status == 'success' or (status == 'error' and
220 e97288bc Christos Stavrakakis
                                   back_network.operstate == 'ERROR'):
221 e97288bc Christos Stavrakakis
            back_network.operstate = state_for_success
222 e97288bc Christos Stavrakakis
            back_network.deleted = True
223 e97288bc Christos Stavrakakis
            back_network.backendtime = etime
224 22ee6892 Christos Stavrakakis
225 e97288bc Christos Stavrakakis
    if status == 'success':
226 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
227 22ee6892 Christos Stavrakakis
    back_network.save()
228 fd2bdbb2 Christos Stavrakakis
229 fd2bdbb2 Christos Stavrakakis
230 fd2bdbb2 Christos Stavrakakis
@transaction.commit_on_success
231 fd2bdbb2 Christos Stavrakakis
def process_network_modify(back_network, etime, jobid, opcode, status,
232 fd2bdbb2 Christos Stavrakakis
                           add_reserved_ips, remove_reserved_ips):
233 fd2bdbb2 Christos Stavrakakis
    assert (opcode == "OP_NETWORK_SET_PARAMS")
234 fd2bdbb2 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
235 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
236 fd2bdbb2 Christos Stavrakakis
237 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobid = jobid
238 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobstatus = status
239 fd2bdbb2 Christos Stavrakakis
    back_network.opcode = opcode
240 fd2bdbb2 Christos Stavrakakis
241 fd2bdbb2 Christos Stavrakakis
    if add_reserved_ips or remove_reserved_ips:
242 fd2bdbb2 Christos Stavrakakis
        net = back_network.network
243 fd2bdbb2 Christos Stavrakakis
        pool = net.get_pool()
244 fd2bdbb2 Christos Stavrakakis
        if add_reserved_ips:
245 fd2bdbb2 Christos Stavrakakis
            for ip in add_reserved_ips:
246 fd2bdbb2 Christos Stavrakakis
                pool.reserve(ip, external=True)
247 fd2bdbb2 Christos Stavrakakis
        if remove_reserved_ips:
248 fd2bdbb2 Christos Stavrakakis
            for ip in remove_reserved_ips:
249 fd2bdbb2 Christos Stavrakakis
                pool.put(ip, external=True)
250 fd2bdbb2 Christos Stavrakakis
        pool.save()
251 fd2bdbb2 Christos Stavrakakis
252 fd2bdbb2 Christos Stavrakakis
    if status == 'success':
253 fd2bdbb2 Christos Stavrakakis
        back_network.backendtime = etime
254 fd2bdbb2 Christos Stavrakakis
    back_network.save()
255 ad2d6807 Vangelis Koukis
256 c25cc9ec Vangelis Koukis
257 9068cd85 Georgios Gousios
@transaction.commit_on_success
258 0827883e Nikos Skalkotos
def process_create_progress(vm, etime, progress):
259 9068cd85 Georgios Gousios
260 0827883e Nikos Skalkotos
    percentage = int(progress)
261 9068cd85 Georgios Gousios
262 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
263 0827883e Nikos Skalkotos
    # snf-image:copy-progress tracks bytes read by image handling processes
264 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
265 af90d919 Vangelis Koukis
    if percentage < 0:
266 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
267 9068cd85 Georgios Gousios
268 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
269 7ec9558b Vangelis Koukis
#   if last_update > percentage:
270 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
271 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
272 9068cd85 Georgios Gousios
273 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
274 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
275 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
276 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
277 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
278 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
279 c25cc9ec Vangelis Koukis
    #
280 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
281 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
282 9068cd85 Georgios Gousios
283 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
284 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
285 9068cd85 Georgios Gousios
    vm.save()
286 ad2d6807 Vangelis Koukis
287 c25cc9ec Vangelis Koukis
288 7d43565f Kostas Papadimitriou
def create_instance_diagnostic(vm, message, source, level="DEBUG", etime=None,
289 7d43565f Kostas Papadimitriou
    details=None):
290 7d43565f Kostas Papadimitriou
    """
291 7d43565f Kostas Papadimitriou
    Create virtual machine instance diagnostic entry.
292 7d43565f Kostas Papadimitriou

293 7d43565f Kostas Papadimitriou
    :param vm: VirtualMachine instance to create diagnostic for.
294 7d43565f Kostas Papadimitriou
    :param message: Diagnostic message.
295 7d43565f Kostas Papadimitriou
    :param source: Diagnostic source identifier (e.g. image-helper).
296 7d43565f Kostas Papadimitriou
    :param level: Diagnostic level (`DEBUG`, `INFO`, `WARNING`, `ERROR`).
297 7d43565f Kostas Papadimitriou
    :param etime: The time the message occured (if available).
298 7d43565f Kostas Papadimitriou
    :param details: Additional details or debug information.
299 7d43565f Kostas Papadimitriou
    """
300 7d43565f Kostas Papadimitriou
    VirtualMachineDiagnostic.objects.create_for_vm(vm, level, source=source,
301 7d43565f Kostas Papadimitriou
            source_date=etime, message=message, details=details)
302 7d43565f Kostas Papadimitriou
303 7d43565f Kostas Papadimitriou
304 adc46059 Christos Stavrakakis
def create_instance(vm, public_nic, flavor, image, password, personality):
305 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
306 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
307 7f691719 Christos Stavrakakis

308 3a9b3cde Giorgos Verigakis
        metadata value should be a dictionary.
309 3a9b3cde Giorgos Verigakis
    """
310 864bed43 Christos Stavrakakis
311 61868190 Vangelis Koukis
    if settings.IGNORE_FLAVOR_DISK_SIZES:
312 3a9b3cde Giorgos Verigakis
        if image['backend_id'].find("windows") >= 0:
313 61868190 Vangelis Koukis
            sz = 14000
314 61868190 Vangelis Koukis
        else:
315 61868190 Vangelis Koukis
            sz = 4000
316 cf0e4232 Vangelis Koukis
    else:
317 61868190 Vangelis Koukis
        sz = flavor.disk * 1024
318 37ca953f Christodoulos Psaltis
319 1c382247 Vangelis Koukis
    # Handle arguments to CreateInstance() as a dictionary,
320 1c382247 Vangelis Koukis
    # initialize it based on a deployment-specific value.
321 1c382247 Vangelis Koukis
    # This enables the administrator to override deployment-specific
322 c25cc9ec Vangelis Koukis
    # arguments, such as the disk template to use, name of os provider
323 1c382247 Vangelis Koukis
    # and hypervisor-specific parameters at will (see Synnefo #785, #835).
324 1c382247 Vangelis Koukis
    #
325 1c382247 Vangelis Koukis
    kw = settings.GANETI_CREATEINSTANCE_KWARGS
326 1c382247 Vangelis Koukis
    kw['mode'] = 'create'
327 924d8085 Christos Stavrakakis
    kw['name'] = vm.backend_vm_id
328 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
329 296682fe Kostas Papadimitriou
330 296682fe Kostas Papadimitriou
    # Identify if provider parameter should be set in disk options.
331 296682fe Kostas Papadimitriou
    # Current implementation support providers only fo ext template.
332 296682fe Kostas Papadimitriou
    # To select specific provider for an ext template, template name
333 296682fe Kostas Papadimitriou
    # should be formated as `ext_<provider_name>`.
334 296682fe Kostas Papadimitriou
    provider = None
335 296682fe Kostas Papadimitriou
    disk_template = flavor.disk_template
336 296682fe Kostas Papadimitriou
    if flavor.disk_template.startswith("ext"):
337 296682fe Kostas Papadimitriou
        disk_template, provider = flavor.disk_template.split("_", 1)
338 296682fe Kostas Papadimitriou
339 296682fe Kostas Papadimitriou
    kw['disk_template'] = disk_template
340 1c382247 Vangelis Koukis
    kw['disks'] = [{"size": sz}]
341 296682fe Kostas Papadimitriou
    if provider:
342 296682fe Kostas Papadimitriou
        kw['disks'][0]['provider'] = provider
343 296682fe Kostas Papadimitriou
344 27d6d48d Stratos Psomadakis
        if provider == 'vlmc':
345 27d6d48d Stratos Psomadakis
            kw['disks'][0]['origin'] = image['backend_id']
346 296682fe Kostas Papadimitriou
347 adc46059 Christos Stavrakakis
    kw['nics'] = [public_nic]
348 341c818e Dimitris Aragiorgis
    if settings.GANETI_USE_HOTPLUG:
349 341c818e Dimitris Aragiorgis
        kw['hotplug'] = True
350 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
351 1c382247 Vangelis Koukis
    # kw['os'] = settings.GANETI_OS_PROVIDER
352 1c382247 Vangelis Koukis
    kw['ip_check'] = False
353 1c382247 Vangelis Koukis
    kw['name_check'] = False
354 1c382247 Vangelis Koukis
    # Do not specific a node explicitly, have
355 1c382247 Vangelis Koukis
    # Ganeti use an iallocator instead
356 1c382247 Vangelis Koukis
    #
357 f8d1eaf4 Kostas Papadimitriou
    #kw['pnode'] = rapi.GetNodes()[0]
358 1c382247 Vangelis Koukis
    kw['dry_run'] = settings.TEST
359 41303ed0 Vangelis Koukis
360 2b1db26f Giorgos Verigakis
    kw['beparams'] = {
361 2b1db26f Giorgos Verigakis
        'auto_balance': True,
362 2b1db26f Giorgos Verigakis
        'vcpus': flavor.cpu,
363 2b1db26f Giorgos Verigakis
        'memory': flavor.ram}
364 41303ed0 Vangelis Koukis
365 e3b5be49 Giorgos Verigakis
    kw['osparams'] = {
366 3a9b3cde Giorgos Verigakis
        'img_id': image['backend_id'],
367 e3b5be49 Giorgos Verigakis
        'img_passwd': password,
368 3a9b3cde Giorgos Verigakis
        'img_format': image['format']}
369 2b1db26f Giorgos Verigakis
    if personality:
370 e3b5be49 Giorgos Verigakis
        kw['osparams']['img_personality'] = json.dumps(personality)
371 d1eaa651 Christos Stavrakakis
372 27d6d48d Stratos Psomadakis
    if provider != None and provider == 'vlmc':
373 27d6d48d Stratos Psomadakis
        kw['osparams']['img_id'] = 'null'
374 27d6d48d Stratos Psomadakis
375 3a9b3cde Giorgos Verigakis
    kw['osparams']['img_properties'] = json.dumps(image['metadata'])
376 d1eaa651 Christos Stavrakakis
377 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
378 1c382247 Vangelis Koukis
    # kw['hvparams'] = dict(serial_console=False)
379 6afeb85d Christos Stavrakakis
    log.debug("Creating instance %s", utils.hide_pass(kw))
380 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
381 3524241a Christos Stavrakakis
        return client.CreateInstance(**kw)
382 f533f224 Vangelis Koukis
383 529178b1 Giorgos Verigakis
384 529178b1 Giorgos Verigakis
def delete_instance(vm):
385 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
386 3524241a Christos Stavrakakis
        return client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
387 529178b1 Giorgos Verigakis
388 ad2d6807 Vangelis Koukis
389 529178b1 Giorgos Verigakis
def reboot_instance(vm, reboot_type):
390 529178b1 Giorgos Verigakis
    assert reboot_type in ('soft', 'hard')
391 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
392 bf5c82dc Christos Stavrakakis
        return client.RebootInstance(vm.backend_vm_id, reboot_type,
393 bf5c82dc Christos Stavrakakis
                                     dry_run=settings.TEST)
394 529178b1 Giorgos Verigakis
395 ad2d6807 Vangelis Koukis
396 529178b1 Giorgos Verigakis
def startup_instance(vm):
397 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
398 3524241a Christos Stavrakakis
        return client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
399 529178b1 Giorgos Verigakis
400 ad2d6807 Vangelis Koukis
401 529178b1 Giorgos Verigakis
def shutdown_instance(vm):
402 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
403 3524241a Christos Stavrakakis
        return client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
404 529178b1 Giorgos Verigakis
405 ad2d6807 Vangelis Koukis
406 529178b1 Giorgos Verigakis
def get_instance_console(vm):
407 71099804 Vangelis Koukis
    # RAPI GetInstanceConsole() returns endpoints to the vnc_bind_address,
408 71099804 Vangelis Koukis
    # which is a cluster-wide setting, either 0.0.0.0 or 127.0.0.1, and pretty
409 71099804 Vangelis Koukis
    # useless (see #783).
410 71099804 Vangelis Koukis
    #
411 71099804 Vangelis Koukis
    # Until this is fixed on the Ganeti side, construct a console info reply
412 71099804 Vangelis Koukis
    # directly.
413 9afeb669 Kostas Papadimitriou
    #
414 71099804 Vangelis Koukis
    # WARNING: This assumes that VNC runs on port network_port on
415 71099804 Vangelis Koukis
    #          the instance's primary node, and is probably
416 71099804 Vangelis Koukis
    #          hypervisor-specific.
417 71099804 Vangelis Koukis
    #
418 bf5c82dc Christos Stavrakakis
    log.debug("Getting console for vm %s", vm)
419 bf5c82dc Christos Stavrakakis
420 71099804 Vangelis Koukis
    console = {}
421 71099804 Vangelis Koukis
    console['kind'] = 'vnc'
422 3524241a Christos Stavrakakis
423 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
424 3524241a Christos Stavrakakis
        i = client.GetInstance(vm.backend_vm_id)
425 3524241a Christos Stavrakakis
426 71099804 Vangelis Koukis
    if i['hvparams']['serial_console']:
427 71099804 Vangelis Koukis
        raise Exception("hv parameter serial_console cannot be true")
428 71099804 Vangelis Koukis
    console['host'] = i['pnode']
429 71099804 Vangelis Koukis
    console['port'] = i['network_port']
430 9afeb669 Kostas Papadimitriou
431 71099804 Vangelis Koukis
    return console
432 604b2bf8 Georgios Gousios
433 604b2bf8 Georgios Gousios
434 3524241a Christos Stavrakakis
def get_instance_info(vm):
435 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
436 3524241a Christos Stavrakakis
        return client.GetInstanceInfo(vm.backend_vm_id)
437 f533f224 Vangelis Koukis
438 c25cc9ec Vangelis Koukis
439 3524241a Christos Stavrakakis
def create_network(network, backends=None, connect=True):
440 3524241a Christos Stavrakakis
    """Create and connect a network."""
441 3524241a Christos Stavrakakis
    if not backends:
442 3524241a Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
443 64938cb0 Giorgos Verigakis
444 bf5c82dc Christos Stavrakakis
    log.debug("Creating network %s in backends %s", network, backends)
445 c25cc9ec Vangelis Koukis
446 3524241a Christos Stavrakakis
    for backend in backends:
447 3524241a Christos Stavrakakis
        create_jobID = _create_network(network, backend)
448 3524241a Christos Stavrakakis
        if connect:
449 3524241a Christos Stavrakakis
            connect_network(network, backend, create_jobID)
450 37ca953f Christodoulos Psaltis
451 64938cb0 Giorgos Verigakis
452 3524241a Christos Stavrakakis
def _create_network(network, backend):
453 3524241a Christos Stavrakakis
    """Create a network."""
454 c25cc9ec Vangelis Koukis
455 22ee6892 Christos Stavrakakis
    network_type = network.public and 'public' or 'private'
456 22ee6892 Christos Stavrakakis
457 22ee6892 Christos Stavrakakis
    tags = network.backend_tag
458 22ee6892 Christos Stavrakakis
    if network.dhcp:
459 22ee6892 Christos Stavrakakis
        tags.append('nfdhcpd')
460 2d762302 Dimitris Aragiorgis
461 2d762302 Dimitris Aragiorgis
    if network.public:
462 2d762302 Dimitris Aragiorgis
        conflicts_check = True
463 2d762302 Dimitris Aragiorgis
    else:
464 2d762302 Dimitris Aragiorgis
        conflicts_check = False
465 22ee6892 Christos Stavrakakis
466 3524241a Christos Stavrakakis
    try:
467 3524241a Christos Stavrakakis
        bn = BackendNetwork.objects.get(network=network, backend=backend)
468 3524241a Christos Stavrakakis
        mac_prefix = bn.mac_prefix
469 3524241a Christos Stavrakakis
    except BackendNetwork.DoesNotExist:
470 3524241a Christos Stavrakakis
        raise Exception("BackendNetwork for network '%s' in backend '%s'"\
471 3524241a Christos Stavrakakis
                        " does not exist" % (network.id, backend.id))
472 3524241a Christos Stavrakakis
473 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
474 3524241a Christos Stavrakakis
        return client.CreateNetwork(network_name=network.backend_id,
475 3524241a Christos Stavrakakis
                                    network=network.subnet,
476 6cc3a31c Christos Stavrakakis
                                    network6=network.subnet6,
477 3524241a Christos Stavrakakis
                                    gateway=network.gateway,
478 6cc3a31c Christos Stavrakakis
                                    gateway6=network.gateway6,
479 3524241a Christos Stavrakakis
                                    network_type=network_type,
480 3524241a Christos Stavrakakis
                                    mac_prefix=mac_prefix,
481 2d762302 Dimitris Aragiorgis
                                    conflicts_check=conflicts_check,
482 3524241a Christos Stavrakakis
                                    tags=tags)
483 3524241a Christos Stavrakakis
484 3524241a Christos Stavrakakis
485 3524241a Christos Stavrakakis
def connect_network(network, backend, depend_job=None, group=None):
486 3524241a Christos Stavrakakis
    """Connect a network to nodegroups."""
487 bf5c82dc Christos Stavrakakis
    log.debug("Connecting network %s to backend %s", network, backend)
488 bf5c82dc Christos Stavrakakis
489 3524241a Christos Stavrakakis
    mode = "routed" if "ROUTED" in network.type else "bridged"
490 3524241a Christos Stavrakakis
491 2d762302 Dimitris Aragiorgis
    if network.public:
492 2d762302 Dimitris Aragiorgis
        conflicts_check = True
493 2d762302 Dimitris Aragiorgis
    else:
494 2d762302 Dimitris Aragiorgis
        conflicts_check = False
495 2d762302 Dimitris Aragiorgis
496 122c4019 Christos Stavrakakis
    depend_jobs = [depend_job] if depend_job else []
497 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
498 3524241a Christos Stavrakakis
        if group:
499 22ee6892 Christos Stavrakakis
            client.ConnectNetwork(network.backend_id, group, mode,
500 2d762302 Dimitris Aragiorgis
                                  network.link, conflicts_check, depend_jobs)
501 3524241a Christos Stavrakakis
        else:
502 3524241a Christos Stavrakakis
            for group in client.GetGroups():
503 3524241a Christos Stavrakakis
                client.ConnectNetwork(network.backend_id, group, mode,
504 2d762302 Dimitris Aragiorgis
                                      network.link, conflicts_check,
505 2d762302 Dimitris Aragiorgis
                                      depend_jobs)
506 22ee6892 Christos Stavrakakis
507 22ee6892 Christos Stavrakakis
508 3524241a Christos Stavrakakis
def delete_network(network, backends=None, disconnect=True):
509 22ee6892 Christos Stavrakakis
    if not backends:
510 22ee6892 Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
511 22ee6892 Christos Stavrakakis
512 bf5c82dc Christos Stavrakakis
    log.debug("Deleting network %s from backends %s", network, backends)
513 bf5c82dc Christos Stavrakakis
514 22ee6892 Christos Stavrakakis
    for backend in backends:
515 3524241a Christos Stavrakakis
        disconnect_jobIDs = []
516 3524241a Christos Stavrakakis
        if disconnect:
517 3524241a Christos Stavrakakis
            disconnect_jobIDs = disconnect_network(network, backend)
518 3524241a Christos Stavrakakis
        _delete_network(network, backend, disconnect_jobIDs)
519 22ee6892 Christos Stavrakakis
520 22ee6892 Christos Stavrakakis
521 3524241a Christos Stavrakakis
def _delete_network(network, backend, depend_jobs=[]):
522 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
523 3524241a Christos Stavrakakis
        return client.DeleteNetwork(network.backend_id, depend_jobs)
524 22ee6892 Christos Stavrakakis
525 22ee6892 Christos Stavrakakis
526 3524241a Christos Stavrakakis
def disconnect_network(network, backend, group=None):
527 bf5c82dc Christos Stavrakakis
    log.debug("Disconnecting network %s to backend %s", network, backend)
528 22ee6892 Christos Stavrakakis
529 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
530 3524241a Christos Stavrakakis
        if group:
531 3524241a Christos Stavrakakis
            return [client.DisconnectNetwork(network.backend_id, group)]
532 3524241a Christos Stavrakakis
        else:
533 3524241a Christos Stavrakakis
            jobs = []
534 3524241a Christos Stavrakakis
            for group in client.GetGroups():
535 3524241a Christos Stavrakakis
                job = client.DisconnectNetwork(network.backend_id, group)
536 3524241a Christos Stavrakakis
                jobs.append(job)
537 3524241a Christos Stavrakakis
            return jobs
538 36f4cb29 Christos Stavrakakis
539 36f4cb29 Christos Stavrakakis
540 87920bc3 Christos Stavrakakis
def connect_to_network(vm, network, address=None):
541 3524241a Christos Stavrakakis
    nic = {'ip': address, 'network': network.backend_id}
542 22ee6892 Christos Stavrakakis
543 bf5c82dc Christos Stavrakakis
    log.debug("Connecting vm %s to network %s(%s)", vm, network, address)
544 22ee6892 Christos Stavrakakis
545 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
546 3524241a Christos Stavrakakis
        return client.ModifyInstance(vm.backend_vm_id, nics=[('add',  nic)],
547 3524241a Christos Stavrakakis
                                     hotplug=settings.GANETI_USE_HOTPLUG,
548 3524241a Christos Stavrakakis
                                     dry_run=settings.TEST)
549 22ee6892 Christos Stavrakakis
550 22ee6892 Christos Stavrakakis
551 3524241a Christos Stavrakakis
def disconnect_from_network(vm, nic):
552 3524241a Christos Stavrakakis
    op = [('remove', nic.index, {})]
553 22ee6892 Christos Stavrakakis
554 bf5c82dc Christos Stavrakakis
    log.debug("Removing nic of VM %s, with index %s", vm, str(nic.index))
555 22ee6892 Christos Stavrakakis
556 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
557 3524241a Christos Stavrakakis
        return client.ModifyInstance(vm.backend_vm_id, nics=op,
558 3524241a Christos Stavrakakis
                                     hotplug=settings.GANETI_USE_HOTPLUG,
559 3524241a Christos Stavrakakis
                                     dry_run=settings.TEST)
560 91826390 Giorgos Verigakis
561 c25cc9ec Vangelis Koukis
562 91826390 Giorgos Verigakis
def set_firewall_profile(vm, profile):
563 26563957 Giorgos Verigakis
    try:
564 26563957 Giorgos Verigakis
        tag = _firewall_tags[profile]
565 26563957 Giorgos Verigakis
    except KeyError:
566 91826390 Giorgos Verigakis
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
567 37ca953f Christodoulos Psaltis
568 bf5c82dc Christos Stavrakakis
    log.debug("Setting tag of VM %s to %s", vm, profile)
569 bf5c82dc Christos Stavrakakis
570 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
571 3524241a Christos Stavrakakis
        # Delete all firewall tags
572 3524241a Christos Stavrakakis
        for t in _firewall_tags.values():
573 3524241a Christos Stavrakakis
            client.DeleteInstanceTags(vm.backend_vm_id, [t],
574 3524241a Christos Stavrakakis
                                      dry_run=settings.TEST)
575 37ca953f Christodoulos Psaltis
576 3524241a Christos Stavrakakis
        client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
577 9afeb669 Kostas Papadimitriou
578 3524241a Christos Stavrakakis
        # XXX NOP ModifyInstance call to force process_net_status to run
579 3524241a Christos Stavrakakis
        # on the dispatcher
580 3524241a Christos Stavrakakis
        client.ModifyInstance(vm.backend_vm_id,
581 3524241a Christos Stavrakakis
                         os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
582 5eedb0e4 Vangelis Koukis
583 41303ed0 Vangelis Koukis
584 f5b4f2a3 Christos Stavrakakis
def get_ganeti_instances(backend=None, bulk=False):
585 3524241a Christos Stavrakakis
    instances = []
586 3524241a Christos Stavrakakis
    for backend in get_backends(backend):
587 3524241a Christos Stavrakakis
        with pooled_rapi_client(backend) as client:
588 3524241a Christos Stavrakakis
            instances.append(client.GetInstances(bulk=bulk))
589 3524241a Christos Stavrakakis
590 3524241a Christos Stavrakakis
    return reduce(list.__add__, instances, [])
591 f5b4f2a3 Christos Stavrakakis
592 f5b4f2a3 Christos Stavrakakis
593 f5b4f2a3 Christos Stavrakakis
def get_ganeti_nodes(backend=None, bulk=False):
594 3524241a Christos Stavrakakis
    nodes = []
595 3524241a Christos Stavrakakis
    for backend in get_backends(backend):
596 3524241a Christos Stavrakakis
        with pooled_rapi_client(backend) as client:
597 3524241a Christos Stavrakakis
            nodes.append(client.GetNodes(bulk=bulk))
598 3524241a Christos Stavrakakis
599 3524241a Christos Stavrakakis
    return reduce(list.__add__, nodes, [])
600 f5b4f2a3 Christos Stavrakakis
601 f5b4f2a3 Christos Stavrakakis
602 f5b4f2a3 Christos Stavrakakis
def get_ganeti_jobs(backend=None, bulk=False):
603 3524241a Christos Stavrakakis
    jobs = []
604 3524241a Christos Stavrakakis
    for backend in get_backends(backend):
605 3524241a Christos Stavrakakis
        with pooled_rapi_client(backend) as client:
606 3524241a Christos Stavrakakis
            jobs.append(client.GetJobs(bulk=bulk))
607 3524241a Christos Stavrakakis
    return reduce(list.__add__, jobs, [])
608 f5b4f2a3 Christos Stavrakakis
609 f5b4f2a3 Christos Stavrakakis
##
610 f5b4f2a3 Christos Stavrakakis
##
611 f5b4f2a3 Christos Stavrakakis
##
612 1a894bfe Christos Stavrakakis
613 1a894bfe Christos Stavrakakis
614 f5b4f2a3 Christos Stavrakakis
def get_backends(backend=None):
615 f5b4f2a3 Christos Stavrakakis
    if backend:
616 f5b4f2a3 Christos Stavrakakis
        return [backend]
617 cc7c0f44 Christos Stavrakakis
    return Backend.objects.filter(offline=False)
618 f5b4f2a3 Christos Stavrakakis
619 17852fe9 Giorgos Verigakis
620 1a894bfe Christos Stavrakakis
def get_physical_resources(backend):
621 1a894bfe Christos Stavrakakis
    """ Get the physical resources of a backend.
622 1a894bfe Christos Stavrakakis

623 1a894bfe Christos Stavrakakis
    Get the resources of a backend as reported by the backend (not the db).
624 41303ed0 Vangelis Koukis

625 1a894bfe Christos Stavrakakis
    """
626 1a894bfe Christos Stavrakakis
    nodes = get_ganeti_nodes(backend, bulk=True)
627 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
628 1a894bfe Christos Stavrakakis
    res = {}
629 1a894bfe Christos Stavrakakis
    for a in attr:
630 1a894bfe Christos Stavrakakis
        res[a] = 0
631 1a894bfe Christos Stavrakakis
    for n in nodes:
632 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
633 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
634 1a894bfe Christos Stavrakakis
        if n['vm_capable'] and not n['drained'] and not n['offline']\
635 1a894bfe Christos Stavrakakis
           and n['cnodes']:
636 1a894bfe Christos Stavrakakis
            for a in attr:
637 1a894bfe Christos Stavrakakis
                res[a] += int(n[a])
638 1a894bfe Christos Stavrakakis
    return res
639 1a894bfe Christos Stavrakakis
640 1a894bfe Christos Stavrakakis
641 1a894bfe Christos Stavrakakis
def update_resources(backend, resources=None):
642 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
643 1a894bfe Christos Stavrakakis

644 1a894bfe Christos Stavrakakis
    """
645 17852fe9 Giorgos Verigakis
646 1a894bfe Christos Stavrakakis
    if not resources:
647 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
648 41303ed0 Vangelis Koukis
649 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
650 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
651 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
652 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
653 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
654 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
655 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
656 1a894bfe Christos Stavrakakis
    backend.save()
657 1a894bfe Christos Stavrakakis
658 1a894bfe Christos Stavrakakis
659 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
660 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
661 1a894bfe Christos Stavrakakis

662 1a894bfe Christos Stavrakakis
    Get the used memory of a backend. Note: This is different for
663 1a894bfe Christos Stavrakakis
    the real memory used, due to kvm's memory de-duplication.
664 1a894bfe Christos Stavrakakis

665 1a894bfe Christos Stavrakakis
    """
666 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
667 3524241a Christos Stavrakakis
        instances = client.GetInstances(bulk=True)
668 1a894bfe Christos Stavrakakis
    mem = 0
669 1a894bfe Christos Stavrakakis
    for i in instances:
670 1a894bfe Christos Stavrakakis
        mem += i['oper_ram']
671 1a894bfe Christos Stavrakakis
    return mem
672 b3d28af2 Christos Stavrakakis
673 b3d28af2 Christos Stavrakakis
##
674 b3d28af2 Christos Stavrakakis
## Synchronized operations for reconciliation
675 b3d28af2 Christos Stavrakakis
##
676 b3d28af2 Christos Stavrakakis
677 b3d28af2 Christos Stavrakakis
678 b3d28af2 Christos Stavrakakis
def create_network_synced(network, backend):
679 b3d28af2 Christos Stavrakakis
    result = _create_network_synced(network, backend)
680 b3d28af2 Christos Stavrakakis
    if result[0] != 'success':
681 b3d28af2 Christos Stavrakakis
        return result
682 b3d28af2 Christos Stavrakakis
    result = connect_network_synced(network, backend)
683 b3d28af2 Christos Stavrakakis
    return result
684 b3d28af2 Christos Stavrakakis
685 b3d28af2 Christos Stavrakakis
686 b3d28af2 Christos Stavrakakis
def _create_network_synced(network, backend):
687 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
688 e60b4630 Christos Stavrakakis
        job = _create_network(network, backend)
689 3524241a Christos Stavrakakis
        result = wait_for_job(client, job)
690 3524241a Christos Stavrakakis
    return result
691 b3d28af2 Christos Stavrakakis
692 b3d28af2 Christos Stavrakakis
693 b3d28af2 Christos Stavrakakis
def connect_network_synced(network, backend):
694 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
695 839e2bd0 Christos Stavrakakis
        mode = 'routed'
696 839e2bd0 Christos Stavrakakis
    else:
697 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
698 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
699 3524241a Christos Stavrakakis
        for group in client.GetGroups():
700 3524241a Christos Stavrakakis
            job = client.ConnectNetwork(network.backend_id, group, mode,
701 3524241a Christos Stavrakakis
                                        network.link)
702 3524241a Christos Stavrakakis
            result = wait_for_job(client, job)
703 3524241a Christos Stavrakakis
            if result[0] != 'success':
704 3524241a Christos Stavrakakis
                return result
705 b3d28af2 Christos Stavrakakis
706 b3d28af2 Christos Stavrakakis
    return result
707 b3d28af2 Christos Stavrakakis
708 b3d28af2 Christos Stavrakakis
709 b3d28af2 Christos Stavrakakis
def wait_for_job(client, jobid):
710 b3d28af2 Christos Stavrakakis
    result = client.WaitForJobChange(jobid, ['status', 'opresult'], None, None)
711 b3d28af2 Christos Stavrakakis
    status = result['job_info'][0]
712 b3d28af2 Christos Stavrakakis
    while status not in ['success', 'error', 'cancel']:
713 b3d28af2 Christos Stavrakakis
        result = client.WaitForJobChange(jobid, ['status', 'opresult'],
714 b3d28af2 Christos Stavrakakis
                                        [result], None)
715 b3d28af2 Christos Stavrakakis
        status = result['job_info'][0]
716 b3d28af2 Christos Stavrakakis
717 b3d28af2 Christos Stavrakakis
    if status == 'success':
718 b3d28af2 Christos Stavrakakis
        return (status, None)
719 b3d28af2 Christos Stavrakakis
    else:
720 b3d28af2 Christos Stavrakakis
        error = result['job_info'][1]
721 b3d28af2 Christos Stavrakakis
        return (status, error)