Statistics
| Branch: | Tag: | Revision:

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

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

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

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

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

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

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