Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (25.5 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 4d5d0b9c Christos Stavrakakis
                               pooled_rapi_client, BridgePoolTable,
43 4d5d0b9c Christos Stavrakakis
                               MacPrefixPoolTable, VirtualMachineDiagnostic)
44 03992c72 Christos Stavrakakis
from synnefo.logic import utils
45 cb4eee84 Christos Stavrakakis
from synnefo import quotas
46 b7d38981 Dimitris Aragiorgis
from synnefo.api.util import release_resource
47 529178b1 Giorgos Verigakis
48 3524241a Christos Stavrakakis
from logging import getLogger
49 3524241a Christos Stavrakakis
log = getLogger(__name__)
50 9e98ba3c Giorgos Verigakis
51 529178b1 Giorgos Verigakis
52 efff6193 Giorgos Verigakis
_firewall_tags = {
53 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
54 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
55 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
56 efff6193 Giorgos Verigakis
57 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
58 efff6193 Giorgos Verigakis
59 02feca11 Vassilios Karakoidas
60 cb4eee84 Christos Stavrakakis
@quotas.uses_commission
61 093f9c53 Vangelis Koukis
@transaction.commit_on_success
62 cb4eee84 Christos Stavrakakis
def process_op_status(serials, vm, etime, jobid, opcode, status, logmsg):
63 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
64 02feca11 Vassilios Karakoidas

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

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

124 ad2d6807 Vangelis Koukis
    Process an incoming message from the Ganeti backend,
125 ad2d6807 Vangelis Koukis
    detailing the NIC configuration of a VM instance.
126 ad2d6807 Vangelis Koukis

127 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
128 ad2d6807 Vangelis Koukis
    """
129 37ca953f Christodoulos Psaltis
130 b578d9e7 Christos Stavrakakis
    ganeti_nics = process_ganeti_nics(nics)
131 b578d9e7 Christos Stavrakakis
    if not nics_changed(vm.nics.order_by('index'), ganeti_nics):
132 b578d9e7 Christos Stavrakakis
        log.debug("NICs for VM %s have not changed", vm)
133 b578d9e7 Christos Stavrakakis
134 fdc94944 Christos Stavrakakis
    release_instance_nics(vm)
135 77f0fa63 Christos Stavrakakis
136 b578d9e7 Christos Stavrakakis
    for nic in ganeti_nics:
137 b578d9e7 Christos Stavrakakis
        ipv4 = nic.get('ipv4', '')
138 f45a7ac4 Christos Stavrakakis
        net = nic['network']
139 b578d9e7 Christos Stavrakakis
        if ipv4:
140 b578d9e7 Christos Stavrakakis
            net.reserve_address(ipv4)
141 b578d9e7 Christos Stavrakakis
142 b578d9e7 Christos Stavrakakis
        nic['dirty'] = False
143 b578d9e7 Christos Stavrakakis
        vm.nics.create(**nic)
144 b578d9e7 Christos Stavrakakis
        # Dummy save the network, because UI uses changed-since for VMs
145 b578d9e7 Christos Stavrakakis
        # and Networks in order to show the VM NICs
146 b578d9e7 Christos Stavrakakis
        net.save()
147 b578d9e7 Christos Stavrakakis
148 b578d9e7 Christos Stavrakakis
    vm.backendtime = etime
149 b578d9e7 Christos Stavrakakis
    vm.save()
150 b578d9e7 Christos Stavrakakis
151 b578d9e7 Christos Stavrakakis
152 b578d9e7 Christos Stavrakakis
def process_ganeti_nics(ganeti_nics):
153 b578d9e7 Christos Stavrakakis
    """Process NIC dict from ganeti hooks."""
154 b578d9e7 Christos Stavrakakis
    new_nics = []
155 b578d9e7 Christos Stavrakakis
    for i, new_nic in enumerate(ganeti_nics):
156 77f0fa63 Christos Stavrakakis
        network = new_nic.get('network', '')
157 22ee6892 Christos Stavrakakis
        n = str(network)
158 77f0fa63 Christos Stavrakakis
        pk = utils.id_from_network_name(n)
159 77f0fa63 Christos Stavrakakis
160 fdc94944 Christos Stavrakakis
        net = Network.objects.get(pk=pk)
161 77f0fa63 Christos Stavrakakis
162 77f0fa63 Christos Stavrakakis
        # Get the new nic info
163 77f0fa63 Christos Stavrakakis
        mac = new_nic.get('mac', '')
164 77f0fa63 Christos Stavrakakis
        ipv4 = new_nic.get('ip', '')
165 77f0fa63 Christos Stavrakakis
        ipv6 = new_nic.get('ipv6', '')
166 9afeb669 Kostas Papadimitriou
167 77f0fa63 Christos Stavrakakis
        firewall = new_nic.get('firewall', '')
168 658a825a Giorgos Verigakis
        firewall_profile = _reverse_tags.get(firewall, '')
169 658a825a Giorgos Verigakis
        if not firewall_profile and net.public:
170 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
171 9afeb669 Kostas Papadimitriou
172 b578d9e7 Christos Stavrakakis
        nic = {
173 cc92b70f Christos Stavrakakis
            'index': i,
174 cc92b70f Christos Stavrakakis
            'network': net,
175 cc92b70f Christos Stavrakakis
            'mac': mac,
176 cc92b70f Christos Stavrakakis
            'ipv4': ipv4,
177 cc92b70f Christos Stavrakakis
            'ipv6': ipv6,
178 939d71dd Christos Stavrakakis
            'firewall_profile': firewall_profile,
179 939d71dd Christos Stavrakakis
            'state': 'ACTIVE'}
180 b578d9e7 Christos Stavrakakis
181 b578d9e7 Christos Stavrakakis
        new_nics.append(nic)
182 b578d9e7 Christos Stavrakakis
    return new_nics
183 b578d9e7 Christos Stavrakakis
184 b578d9e7 Christos Stavrakakis
185 b578d9e7 Christos Stavrakakis
def nics_changed(old_nics, new_nics):
186 b578d9e7 Christos Stavrakakis
    """Return True if NICs have changed in any way."""
187 b578d9e7 Christos Stavrakakis
    if len(old_nics) != len(new_nics):
188 b578d9e7 Christos Stavrakakis
        return True
189 b578d9e7 Christos Stavrakakis
    for old_nic, new_nic in zip(old_nics, new_nics):
190 cc92b70f Christos Stavrakakis
        if not (old_nic.ipv4 == new_nic['ipv4'] and
191 cc92b70f Christos Stavrakakis
                old_nic.ipv6 == new_nic['ipv6'] and
192 cc92b70f Christos Stavrakakis
                old_nic.mac == new_nic['mac'] and
193 cc92b70f Christos Stavrakakis
                old_nic.firewall_profile == new_nic['firewall_profile'] and
194 cc92b70f Christos Stavrakakis
                old_nic.index == new_nic['index'] and
195 b578d9e7 Christos Stavrakakis
                old_nic.network == new_nic['network']):
196 b578d9e7 Christos Stavrakakis
            return True
197 b578d9e7 Christos Stavrakakis
    return False
198 22ee6892 Christos Stavrakakis
199 22ee6892 Christos Stavrakakis
200 bd392934 Christos Stavrakakis
def release_instance_nics(vm):
201 bd392934 Christos Stavrakakis
    for nic in vm.nics.all():
202 40ef487d Christos Stavrakakis
        net = nic.network
203 fa454545 Christos Stavrakakis
        if nic.ipv4:
204 40ef487d Christos Stavrakakis
            net.release_address(nic.ipv4)
205 bd392934 Christos Stavrakakis
        nic.delete()
206 40ef487d Christos Stavrakakis
        net.save()
207 bd392934 Christos Stavrakakis
208 bd392934 Christos Stavrakakis
209 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
210 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
211 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
212 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
213 22ee6892 Christos Stavrakakis
214 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
215 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
216 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
217 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
218 22ee6892 Christos Stavrakakis
219 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
220 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
221 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
222 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
223 22ee6892 Christos Stavrakakis
224 e6f6627c Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_ADD':
225 5480daec Christos Stavrakakis
        back_network.operstate = 'ERROR'
226 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
227 22ee6892 Christos Stavrakakis
228 e97288bc Christos Stavrakakis
    if opcode == 'OP_NETWORK_REMOVE':
229 e97288bc Christos Stavrakakis
        if status == 'success' or (status == 'error' and
230 e97288bc Christos Stavrakakis
                                   back_network.operstate == 'ERROR'):
231 e97288bc Christos Stavrakakis
            back_network.operstate = state_for_success
232 e97288bc Christos Stavrakakis
            back_network.deleted = True
233 e97288bc Christos Stavrakakis
            back_network.backendtime = etime
234 22ee6892 Christos Stavrakakis
235 e97288bc Christos Stavrakakis
    if status == 'success':
236 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
237 22ee6892 Christos Stavrakakis
    back_network.save()
238 4d5d0b9c Christos Stavrakakis
    # Also you must update the state of the Network!!
239 4d5d0b9c Christos Stavrakakis
    update_network_state(back_network.network)
240 fd2bdbb2 Christos Stavrakakis
241 fd2bdbb2 Christos Stavrakakis
242 cb4eee84 Christos Stavrakakis
@quotas.uses_commission
243 cb4eee84 Christos Stavrakakis
def update_network_state(serials, network):
244 cb4eee84 Christos Stavrakakis
    old_state = network.state
245 cb4eee84 Christos Stavrakakis
246 3f77e63d Christos Stavrakakis
    backend_states = [s.operstate for s in
247 cc92b70f Christos Stavrakakis
                      network.backend_networks.filter(backend__offline=False)]
248 cb4eee84 Christos Stavrakakis
    if not backend_states:
249 cb4eee84 Christos Stavrakakis
        network.state = 'PENDING'
250 cb4eee84 Christos Stavrakakis
        network.save()
251 cb4eee84 Christos Stavrakakis
        return
252 cb4eee84 Christos Stavrakakis
253 cb4eee84 Christos Stavrakakis
    all_equal = len(set(backend_states)) <= 1
254 cb4eee84 Christos Stavrakakis
    network.state = all_equal and backend_states[0] or 'PENDING'
255 cb4eee84 Christos Stavrakakis
    # Release the resources on the deletion of the Network
256 cb4eee84 Christos Stavrakakis
    if old_state != 'DELETED' and network.state == 'DELETED':
257 cb4eee84 Christos Stavrakakis
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
258 cb4eee84 Christos Stavrakakis
                 network.id, network.mac_prefix, network.link)
259 cb4eee84 Christos Stavrakakis
        network.deleted = True
260 b7d38981 Dimitris Aragiorgis
        if network.mac_prefix:
261 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
262 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="mac_prefix",
263 b7d38981 Dimitris Aragiorgis
                                 value=network.mac_prefix)
264 b7d38981 Dimitris Aragiorgis
        if network.link:
265 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["link"] == "pool":
266 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="bridge", value=network.link)
267 cb4eee84 Christos Stavrakakis
268 cb4eee84 Christos Stavrakakis
        # Issue commission
269 e18c1749 Christos Stavrakakis
        if network.userid:
270 e18c1749 Christos Stavrakakis
            serial = quotas.issue_network_commission(network.userid,
271 e18c1749 Christos Stavrakakis
                                                     delete=True)
272 e18c1749 Christos Stavrakakis
            serials.append(serial)
273 e18c1749 Christos Stavrakakis
            network.serial = serial
274 e18c1749 Christos Stavrakakis
            serial.accepted = True
275 e18c1749 Christos Stavrakakis
            serial.save()
276 e18c1749 Christos Stavrakakis
        elif not network.public:
277 e18c1749 Christos Stavrakakis
            log.warning("Network %s does not have an owner!", network.id)
278 cb4eee84 Christos Stavrakakis
    network.save()
279 cb4eee84 Christos Stavrakakis
280 cb4eee84 Christos Stavrakakis
281 fd2bdbb2 Christos Stavrakakis
@transaction.commit_on_success
282 fd2bdbb2 Christos Stavrakakis
def process_network_modify(back_network, etime, jobid, opcode, status,
283 fd2bdbb2 Christos Stavrakakis
                           add_reserved_ips, remove_reserved_ips):
284 fd2bdbb2 Christos Stavrakakis
    assert (opcode == "OP_NETWORK_SET_PARAMS")
285 fd2bdbb2 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
286 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
287 fd2bdbb2 Christos Stavrakakis
288 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobid = jobid
289 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobstatus = status
290 fd2bdbb2 Christos Stavrakakis
    back_network.opcode = opcode
291 fd2bdbb2 Christos Stavrakakis
292 fd2bdbb2 Christos Stavrakakis
    if add_reserved_ips or remove_reserved_ips:
293 fd2bdbb2 Christos Stavrakakis
        net = back_network.network
294 fd2bdbb2 Christos Stavrakakis
        pool = net.get_pool()
295 fd2bdbb2 Christos Stavrakakis
        if add_reserved_ips:
296 fd2bdbb2 Christos Stavrakakis
            for ip in add_reserved_ips:
297 fd2bdbb2 Christos Stavrakakis
                pool.reserve(ip, external=True)
298 fd2bdbb2 Christos Stavrakakis
        if remove_reserved_ips:
299 fd2bdbb2 Christos Stavrakakis
            for ip in remove_reserved_ips:
300 fd2bdbb2 Christos Stavrakakis
                pool.put(ip, external=True)
301 fd2bdbb2 Christos Stavrakakis
        pool.save()
302 fd2bdbb2 Christos Stavrakakis
303 fd2bdbb2 Christos Stavrakakis
    if status == 'success':
304 fd2bdbb2 Christos Stavrakakis
        back_network.backendtime = etime
305 fd2bdbb2 Christos Stavrakakis
    back_network.save()
306 ad2d6807 Vangelis Koukis
307 c25cc9ec Vangelis Koukis
308 9068cd85 Georgios Gousios
@transaction.commit_on_success
309 0827883e Nikos Skalkotos
def process_create_progress(vm, etime, progress):
310 9068cd85 Georgios Gousios
311 0827883e Nikos Skalkotos
    percentage = int(progress)
312 9068cd85 Georgios Gousios
313 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
314 0827883e Nikos Skalkotos
    # snf-image:copy-progress tracks bytes read by image handling processes
315 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
316 af90d919 Vangelis Koukis
    if percentage < 0:
317 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
318 9068cd85 Georgios Gousios
319 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
320 7ec9558b Vangelis Koukis
#   if last_update > percentage:
321 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
322 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
323 9068cd85 Georgios Gousios
324 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
325 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
326 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
327 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
328 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
329 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
330 c25cc9ec Vangelis Koukis
    #
331 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
332 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
333 9068cd85 Georgios Gousios
334 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
335 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
336 9068cd85 Georgios Gousios
    vm.save()
337 ad2d6807 Vangelis Koukis
338 c25cc9ec Vangelis Koukis
339 7d43565f Kostas Papadimitriou
def create_instance_diagnostic(vm, message, source, level="DEBUG", etime=None,
340 cc92b70f Christos Stavrakakis
                               details=None):
341 7d43565f Kostas Papadimitriou
    """
342 7d43565f Kostas Papadimitriou
    Create virtual machine instance diagnostic entry.
343 7d43565f Kostas Papadimitriou

344 7d43565f Kostas Papadimitriou
    :param vm: VirtualMachine instance to create diagnostic for.
345 7d43565f Kostas Papadimitriou
    :param message: Diagnostic message.
346 7d43565f Kostas Papadimitriou
    :param source: Diagnostic source identifier (e.g. image-helper).
347 7d43565f Kostas Papadimitriou
    :param level: Diagnostic level (`DEBUG`, `INFO`, `WARNING`, `ERROR`).
348 7d43565f Kostas Papadimitriou
    :param etime: The time the message occured (if available).
349 7d43565f Kostas Papadimitriou
    :param details: Additional details or debug information.
350 7d43565f Kostas Papadimitriou
    """
351 7d43565f Kostas Papadimitriou
    VirtualMachineDiagnostic.objects.create_for_vm(vm, level, source=source,
352 cc92b70f Christos Stavrakakis
                                                   source_date=etime,
353 cc92b70f Christos Stavrakakis
                                                   message=message,
354 cc92b70f Christos Stavrakakis
                                                   details=details)
355 7d43565f Kostas Papadimitriou
356 7d43565f Kostas Papadimitriou
357 8528b8ac Christos Stavrakakis
def create_instance(vm, public_nic, flavor, image):
358 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
359 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
360 7f691719 Christos Stavrakakis

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

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

659 1a894bfe Christos Stavrakakis
    """
660 1a894bfe Christos Stavrakakis
    nodes = get_ganeti_nodes(backend, bulk=True)
661 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
662 1a894bfe Christos Stavrakakis
    res = {}
663 1a894bfe Christos Stavrakakis
    for a in attr:
664 1a894bfe Christos Stavrakakis
        res[a] = 0
665 1a894bfe Christos Stavrakakis
    for n in nodes:
666 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
667 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
668 cc92b70f Christos Stavrakakis
        can_host_vms = n['vm_capable'] and not (n['drained'] or n['offline'])
669 cc92b70f Christos Stavrakakis
        if can_host_vms and n['cnodes']:
670 1a894bfe Christos Stavrakakis
            for a in attr:
671 1a894bfe Christos Stavrakakis
                res[a] += int(n[a])
672 1a894bfe Christos Stavrakakis
    return res
673 1a894bfe Christos Stavrakakis
674 1a894bfe Christos Stavrakakis
675 1a894bfe Christos Stavrakakis
def update_resources(backend, resources=None):
676 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
677 1a894bfe Christos Stavrakakis

678 1a894bfe Christos Stavrakakis
    """
679 17852fe9 Giorgos Verigakis
680 1a894bfe Christos Stavrakakis
    if not resources:
681 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
682 41303ed0 Vangelis Koukis
683 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
684 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
685 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
686 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
687 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
688 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
689 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
690 1a894bfe Christos Stavrakakis
    backend.save()
691 1a894bfe Christos Stavrakakis
692 1a894bfe Christos Stavrakakis
693 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
694 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
695 1a894bfe Christos Stavrakakis

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

699 1a894bfe Christos Stavrakakis
    """
700 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
701 3524241a Christos Stavrakakis
        instances = client.GetInstances(bulk=True)
702 1a894bfe Christos Stavrakakis
    mem = 0
703 1a894bfe Christos Stavrakakis
    for i in instances:
704 1a894bfe Christos Stavrakakis
        mem += i['oper_ram']
705 1a894bfe Christos Stavrakakis
    return mem
706 b3d28af2 Christos Stavrakakis
707 b3d28af2 Christos Stavrakakis
##
708 b3d28af2 Christos Stavrakakis
## Synchronized operations for reconciliation
709 b3d28af2 Christos Stavrakakis
##
710 b3d28af2 Christos Stavrakakis
711 b3d28af2 Christos Stavrakakis
712 b3d28af2 Christos Stavrakakis
def create_network_synced(network, backend):
713 b3d28af2 Christos Stavrakakis
    result = _create_network_synced(network, backend)
714 b3d28af2 Christos Stavrakakis
    if result[0] != 'success':
715 b3d28af2 Christos Stavrakakis
        return result
716 b3d28af2 Christos Stavrakakis
    result = connect_network_synced(network, backend)
717 b3d28af2 Christos Stavrakakis
    return result
718 b3d28af2 Christos Stavrakakis
719 b3d28af2 Christos Stavrakakis
720 b3d28af2 Christos Stavrakakis
def _create_network_synced(network, backend):
721 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
722 e60b4630 Christos Stavrakakis
        job = _create_network(network, backend)
723 3524241a Christos Stavrakakis
        result = wait_for_job(client, job)
724 3524241a Christos Stavrakakis
    return result
725 b3d28af2 Christos Stavrakakis
726 b3d28af2 Christos Stavrakakis
727 b3d28af2 Christos Stavrakakis
def connect_network_synced(network, backend):
728 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
729 3524241a Christos Stavrakakis
        for group in client.GetGroups():
730 b7d38981 Dimitris Aragiorgis
            job = client.ConnectNetwork(network.backend_id, group,
731 b7d38981 Dimitris Aragiorgis
                                        network.mode, network.link)
732 3524241a Christos Stavrakakis
            result = wait_for_job(client, job)
733 3524241a Christos Stavrakakis
            if result[0] != 'success':
734 3524241a Christos Stavrakakis
                return result
735 b3d28af2 Christos Stavrakakis
736 b3d28af2 Christos Stavrakakis
    return result
737 b3d28af2 Christos Stavrakakis
738 b3d28af2 Christos Stavrakakis
739 b3d28af2 Christos Stavrakakis
def wait_for_job(client, jobid):
740 b3d28af2 Christos Stavrakakis
    result = client.WaitForJobChange(jobid, ['status', 'opresult'], None, None)
741 b3d28af2 Christos Stavrakakis
    status = result['job_info'][0]
742 b3d28af2 Christos Stavrakakis
    while status not in ['success', 'error', 'cancel']:
743 b3d28af2 Christos Stavrakakis
        result = client.WaitForJobChange(jobid, ['status', 'opresult'],
744 cc92b70f Christos Stavrakakis
                                         [result], None)
745 b3d28af2 Christos Stavrakakis
        status = result['job_info'][0]
746 b3d28af2 Christos Stavrakakis
747 b3d28af2 Christos Stavrakakis
    if status == 'success':
748 b3d28af2 Christos Stavrakakis
        return (status, None)
749 b3d28af2 Christos Stavrakakis
    else:
750 b3d28af2 Christos Stavrakakis
        error = result['job_info'][1]
751 b3d28af2 Christos Stavrakakis
        return (status, error)