Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (26.3 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 fd95834e Christos Stavrakakis
                               pooled_rapi_client, VirtualMachineDiagnostic)
43 03992c72 Christos Stavrakakis
from synnefo.logic import utils
44 cb4eee84 Christos Stavrakakis
from synnefo import quotas
45 b7d38981 Dimitris Aragiorgis
from synnefo.api.util import release_resource
46 fd95834e Christos Stavrakakis
from synnefo.util.mac2eui64 import mac2eui64
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 093f9c53 Vangelis Koukis
@transaction.commit_on_success
61 fd95834e Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None):
62 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
63 02feca11 Vassilios Karakoidas

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

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

127 ad2d6807 Vangelis Koukis
    Process an incoming message from the Ganeti backend,
128 ad2d6807 Vangelis Koukis
    detailing the NIC configuration of a VM instance.
129 ad2d6807 Vangelis Koukis

130 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
131 ad2d6807 Vangelis Koukis
    """
132 37ca953f Christodoulos Psaltis
133 b578d9e7 Christos Stavrakakis
    ganeti_nics = process_ganeti_nics(nics)
134 b578d9e7 Christos Stavrakakis
    if not nics_changed(vm.nics.order_by('index'), ganeti_nics):
135 b578d9e7 Christos Stavrakakis
        log.debug("NICs for VM %s have not changed", vm)
136 b578d9e7 Christos Stavrakakis
137 fdc94944 Christos Stavrakakis
    release_instance_nics(vm)
138 77f0fa63 Christos Stavrakakis
139 b578d9e7 Christos Stavrakakis
    for nic in ganeti_nics:
140 b578d9e7 Christos Stavrakakis
        ipv4 = nic.get('ipv4', '')
141 f45a7ac4 Christos Stavrakakis
        net = nic['network']
142 b578d9e7 Christos Stavrakakis
        if ipv4:
143 b578d9e7 Christos Stavrakakis
            net.reserve_address(ipv4)
144 b578d9e7 Christos Stavrakakis
145 b578d9e7 Christos Stavrakakis
        nic['dirty'] = False
146 b578d9e7 Christos Stavrakakis
        vm.nics.create(**nic)
147 b578d9e7 Christos Stavrakakis
        # Dummy save the network, because UI uses changed-since for VMs
148 b578d9e7 Christos Stavrakakis
        # and Networks in order to show the VM NICs
149 b578d9e7 Christos Stavrakakis
        net.save()
150 b578d9e7 Christos Stavrakakis
151 b578d9e7 Christos Stavrakakis
    vm.backendtime = etime
152 b578d9e7 Christos Stavrakakis
    vm.save()
153 b578d9e7 Christos Stavrakakis
154 b578d9e7 Christos Stavrakakis
155 b578d9e7 Christos Stavrakakis
def process_ganeti_nics(ganeti_nics):
156 b578d9e7 Christos Stavrakakis
    """Process NIC dict from ganeti hooks."""
157 b578d9e7 Christos Stavrakakis
    new_nics = []
158 b578d9e7 Christos Stavrakakis
    for i, new_nic in enumerate(ganeti_nics):
159 77f0fa63 Christos Stavrakakis
        network = new_nic.get('network', '')
160 22ee6892 Christos Stavrakakis
        n = str(network)
161 77f0fa63 Christos Stavrakakis
        pk = utils.id_from_network_name(n)
162 77f0fa63 Christos Stavrakakis
163 fdc94944 Christos Stavrakakis
        net = Network.objects.get(pk=pk)
164 77f0fa63 Christos Stavrakakis
165 77f0fa63 Christos Stavrakakis
        # Get the new nic info
166 77f0fa63 Christos Stavrakakis
        mac = new_nic.get('mac', '')
167 77f0fa63 Christos Stavrakakis
        ipv4 = new_nic.get('ip', '')
168 fd95834e Christos Stavrakakis
        if net.subnet6:
169 fd95834e Christos Stavrakakis
            ipv6 = mac2eui64(mac, net.subnet6)
170 fd95834e Christos Stavrakakis
        else:
171 fd95834e Christos Stavrakakis
            ipv6 = ''
172 9afeb669 Kostas Papadimitriou
173 77f0fa63 Christos Stavrakakis
        firewall = new_nic.get('firewall', '')
174 658a825a Giorgos Verigakis
        firewall_profile = _reverse_tags.get(firewall, '')
175 658a825a Giorgos Verigakis
        if not firewall_profile and net.public:
176 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
177 9afeb669 Kostas Papadimitriou
178 b578d9e7 Christos Stavrakakis
        nic = {
179 cc92b70f Christos Stavrakakis
            'index': i,
180 cc92b70f Christos Stavrakakis
            'network': net,
181 cc92b70f Christos Stavrakakis
            'mac': mac,
182 cc92b70f Christos Stavrakakis
            'ipv4': ipv4,
183 cc92b70f Christos Stavrakakis
            'ipv6': ipv6,
184 939d71dd Christos Stavrakakis
            'firewall_profile': firewall_profile,
185 939d71dd Christos Stavrakakis
            'state': 'ACTIVE'}
186 b578d9e7 Christos Stavrakakis
187 b578d9e7 Christos Stavrakakis
        new_nics.append(nic)
188 b578d9e7 Christos Stavrakakis
    return new_nics
189 b578d9e7 Christos Stavrakakis
190 b578d9e7 Christos Stavrakakis
191 b578d9e7 Christos Stavrakakis
def nics_changed(old_nics, new_nics):
192 b578d9e7 Christos Stavrakakis
    """Return True if NICs have changed in any way."""
193 b578d9e7 Christos Stavrakakis
    if len(old_nics) != len(new_nics):
194 b578d9e7 Christos Stavrakakis
        return True
195 be4d8aed Christos Stavrakakis
    fields = ["ipv4", "ipv6", "mac", "firewall_profile", "index", "network"]
196 b578d9e7 Christos Stavrakakis
    for old_nic, new_nic in zip(old_nics, new_nics):
197 be4d8aed Christos Stavrakakis
        for field in fields:
198 be4d8aed Christos Stavrakakis
            if getattr(old_nic, field) != new_nic[field]:
199 be4d8aed Christos Stavrakakis
                return True
200 b578d9e7 Christos Stavrakakis
    return False
201 22ee6892 Christos Stavrakakis
202 22ee6892 Christos Stavrakakis
203 bd392934 Christos Stavrakakis
def release_instance_nics(vm):
204 bd392934 Christos Stavrakakis
    for nic in vm.nics.all():
205 40ef487d Christos Stavrakakis
        net = nic.network
206 fa454545 Christos Stavrakakis
        if nic.ipv4:
207 40ef487d Christos Stavrakakis
            net.release_address(nic.ipv4)
208 bd392934 Christos Stavrakakis
        nic.delete()
209 40ef487d Christos Stavrakakis
        net.save()
210 bd392934 Christos Stavrakakis
211 bd392934 Christos Stavrakakis
212 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
213 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
214 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
215 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
216 22ee6892 Christos Stavrakakis
217 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
218 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
219 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
220 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
221 22ee6892 Christos Stavrakakis
222 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
223 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
224 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
225 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
226 22ee6892 Christos Stavrakakis
227 e6f6627c Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_ADD':
228 5480daec Christos Stavrakakis
        back_network.operstate = 'ERROR'
229 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
230 22ee6892 Christos Stavrakakis
231 e97288bc Christos Stavrakakis
    if opcode == 'OP_NETWORK_REMOVE':
232 e97288bc Christos Stavrakakis
        if status == 'success' or (status == 'error' and
233 e97288bc Christos Stavrakakis
                                   back_network.operstate == 'ERROR'):
234 e97288bc Christos Stavrakakis
            back_network.operstate = state_for_success
235 e97288bc Christos Stavrakakis
            back_network.deleted = True
236 e97288bc Christos Stavrakakis
            back_network.backendtime = etime
237 22ee6892 Christos Stavrakakis
238 e97288bc Christos Stavrakakis
    if status == 'success':
239 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
240 22ee6892 Christos Stavrakakis
    back_network.save()
241 4d5d0b9c Christos Stavrakakis
    # Also you must update the state of the Network!!
242 4d5d0b9c Christos Stavrakakis
    update_network_state(back_network.network)
243 fd2bdbb2 Christos Stavrakakis
244 fd2bdbb2 Christos Stavrakakis
245 2509ce17 Christos Stavrakakis
def update_network_state(network):
246 99af08a4 Christos Stavrakakis
    """Update the state of a Network based on BackendNetwork states.
247 cb4eee84 Christos Stavrakakis

248 99af08a4 Christos Stavrakakis
    Update the state of a Network based on the operstate of the networks in the
249 99af08a4 Christos Stavrakakis
    backends that network exists.
250 99af08a4 Christos Stavrakakis

251 99af08a4 Christos Stavrakakis
    The state of the network is:
252 99af08a4 Christos Stavrakakis
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
253 99af08a4 Christos Stavrakakis
    * DELETED: If it is is 'DELETED' in all backends that have been created.
254 99af08a4 Christos Stavrakakis

255 99af08a4 Christos Stavrakakis
    This function also releases the resources (MAC prefix or Bridge) and the
256 99af08a4 Christos Stavrakakis
    quotas for the network.
257 99af08a4 Christos Stavrakakis

258 99af08a4 Christos Stavrakakis
    """
259 99af08a4 Christos Stavrakakis
    if network.deleted:
260 99af08a4 Christos Stavrakakis
        # Network has already been deleted. Just assert that state is also
261 99af08a4 Christos Stavrakakis
        # DELETED
262 99af08a4 Christos Stavrakakis
        if not network.state == "DELETED":
263 99af08a4 Christos Stavrakakis
            network.state = "DELETED"
264 99af08a4 Christos Stavrakakis
            network.save()
265 cb4eee84 Christos Stavrakakis
        return
266 cb4eee84 Christos Stavrakakis
267 99af08a4 Christos Stavrakakis
    backend_states = [s.operstate for s in network.backend_networks.all()]
268 27cda06b Christos Stavrakakis
    if not backend_states and network.action != "DESTROY":
269 99af08a4 Christos Stavrakakis
        if network.state != "ACTIVE":
270 99af08a4 Christos Stavrakakis
            network.state = "ACTIVE"
271 99af08a4 Christos Stavrakakis
            network.save()
272 99af08a4 Christos Stavrakakis
            return
273 99af08a4 Christos Stavrakakis
274 99af08a4 Christos Stavrakakis
    # Network is deleted when all BackendNetworks go to "DELETED" operstate
275 27cda06b Christos Stavrakakis
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
276 27cda06b Christos Stavrakakis
                     "DELETED")
277 99af08a4 Christos Stavrakakis
278 cb4eee84 Christos Stavrakakis
    # Release the resources on the deletion of the Network
279 99af08a4 Christos Stavrakakis
    if deleted:
280 cb4eee84 Christos Stavrakakis
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
281 cb4eee84 Christos Stavrakakis
                 network.id, network.mac_prefix, network.link)
282 cb4eee84 Christos Stavrakakis
        network.deleted = True
283 99af08a4 Christos Stavrakakis
        network.state = "DELETED"
284 b7d38981 Dimitris Aragiorgis
        if network.mac_prefix:
285 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
286 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="mac_prefix",
287 b7d38981 Dimitris Aragiorgis
                                 value=network.mac_prefix)
288 b7d38981 Dimitris Aragiorgis
        if network.link:
289 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["link"] == "pool":
290 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="bridge", value=network.link)
291 cb4eee84 Christos Stavrakakis
292 cb4eee84 Christos Stavrakakis
        # Issue commission
293 e18c1749 Christos Stavrakakis
        if network.userid:
294 2509ce17 Christos Stavrakakis
            quotas.issue_and_accept_commission(network, delete=True)
295 e18c1749 Christos Stavrakakis
        elif not network.public:
296 e18c1749 Christos Stavrakakis
            log.warning("Network %s does not have an owner!", network.id)
297 cb4eee84 Christos Stavrakakis
    network.save()
298 cb4eee84 Christos Stavrakakis
299 cb4eee84 Christos Stavrakakis
300 fd2bdbb2 Christos Stavrakakis
@transaction.commit_on_success
301 fd2bdbb2 Christos Stavrakakis
def process_network_modify(back_network, etime, jobid, opcode, status,
302 fd2bdbb2 Christos Stavrakakis
                           add_reserved_ips, remove_reserved_ips):
303 fd2bdbb2 Christos Stavrakakis
    assert (opcode == "OP_NETWORK_SET_PARAMS")
304 fd2bdbb2 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
305 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
306 fd2bdbb2 Christos Stavrakakis
307 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobid = jobid
308 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobstatus = status
309 fd2bdbb2 Christos Stavrakakis
    back_network.opcode = opcode
310 fd2bdbb2 Christos Stavrakakis
311 fd2bdbb2 Christos Stavrakakis
    if add_reserved_ips or remove_reserved_ips:
312 fd2bdbb2 Christos Stavrakakis
        net = back_network.network
313 fd2bdbb2 Christos Stavrakakis
        pool = net.get_pool()
314 fd2bdbb2 Christos Stavrakakis
        if add_reserved_ips:
315 fd2bdbb2 Christos Stavrakakis
            for ip in add_reserved_ips:
316 fd2bdbb2 Christos Stavrakakis
                pool.reserve(ip, external=True)
317 fd2bdbb2 Christos Stavrakakis
        if remove_reserved_ips:
318 fd2bdbb2 Christos Stavrakakis
            for ip in remove_reserved_ips:
319 fd2bdbb2 Christos Stavrakakis
                pool.put(ip, external=True)
320 fd2bdbb2 Christos Stavrakakis
        pool.save()
321 fd2bdbb2 Christos Stavrakakis
322 fd2bdbb2 Christos Stavrakakis
    if status == 'success':
323 fd2bdbb2 Christos Stavrakakis
        back_network.backendtime = etime
324 fd2bdbb2 Christos Stavrakakis
    back_network.save()
325 ad2d6807 Vangelis Koukis
326 c25cc9ec Vangelis Koukis
327 9068cd85 Georgios Gousios
@transaction.commit_on_success
328 0827883e Nikos Skalkotos
def process_create_progress(vm, etime, progress):
329 9068cd85 Georgios Gousios
330 0827883e Nikos Skalkotos
    percentage = int(progress)
331 9068cd85 Georgios Gousios
332 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
333 0827883e Nikos Skalkotos
    # snf-image:copy-progress tracks bytes read by image handling processes
334 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
335 af90d919 Vangelis Koukis
    if percentage < 0:
336 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
337 9068cd85 Georgios Gousios
338 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
339 7ec9558b Vangelis Koukis
#   if last_update > percentage:
340 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
341 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
342 9068cd85 Georgios Gousios
343 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
344 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
345 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
346 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
347 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
348 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
349 c25cc9ec Vangelis Koukis
    #
350 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
351 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
352 9068cd85 Georgios Gousios
353 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
354 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
355 9068cd85 Georgios Gousios
    vm.save()
356 ad2d6807 Vangelis Koukis
357 c25cc9ec Vangelis Koukis
358 7d43565f Kostas Papadimitriou
def create_instance_diagnostic(vm, message, source, level="DEBUG", etime=None,
359 cc92b70f Christos Stavrakakis
                               details=None):
360 7d43565f Kostas Papadimitriou
    """
361 7d43565f Kostas Papadimitriou
    Create virtual machine instance diagnostic entry.
362 7d43565f Kostas Papadimitriou

363 7d43565f Kostas Papadimitriou
    :param vm: VirtualMachine instance to create diagnostic for.
364 7d43565f Kostas Papadimitriou
    :param message: Diagnostic message.
365 7d43565f Kostas Papadimitriou
    :param source: Diagnostic source identifier (e.g. image-helper).
366 7d43565f Kostas Papadimitriou
    :param level: Diagnostic level (`DEBUG`, `INFO`, `WARNING`, `ERROR`).
367 7d43565f Kostas Papadimitriou
    :param etime: The time the message occured (if available).
368 7d43565f Kostas Papadimitriou
    :param details: Additional details or debug information.
369 7d43565f Kostas Papadimitriou
    """
370 7d43565f Kostas Papadimitriou
    VirtualMachineDiagnostic.objects.create_for_vm(vm, level, source=source,
371 cc92b70f Christos Stavrakakis
                                                   source_date=etime,
372 cc92b70f Christos Stavrakakis
                                                   message=message,
373 cc92b70f Christos Stavrakakis
                                                   details=details)
374 7d43565f Kostas Papadimitriou
375 7d43565f Kostas Papadimitriou
376 8528b8ac Christos Stavrakakis
def create_instance(vm, public_nic, flavor, image):
377 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
378 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
379 7f691719 Christos Stavrakakis

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

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

685 1a894bfe Christos Stavrakakis
    """
686 1a894bfe Christos Stavrakakis
    nodes = get_ganeti_nodes(backend, bulk=True)
687 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
688 1a894bfe Christos Stavrakakis
    res = {}
689 1a894bfe Christos Stavrakakis
    for a in attr:
690 1a894bfe Christos Stavrakakis
        res[a] = 0
691 1a894bfe Christos Stavrakakis
    for n in nodes:
692 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
693 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
694 cc92b70f Christos Stavrakakis
        can_host_vms = n['vm_capable'] and not (n['drained'] or n['offline'])
695 cc92b70f Christos Stavrakakis
        if can_host_vms and n['cnodes']:
696 1a894bfe Christos Stavrakakis
            for a in attr:
697 1a894bfe Christos Stavrakakis
                res[a] += int(n[a])
698 1a894bfe Christos Stavrakakis
    return res
699 1a894bfe Christos Stavrakakis
700 1a894bfe Christos Stavrakakis
701 1a894bfe Christos Stavrakakis
def update_resources(backend, resources=None):
702 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
703 1a894bfe Christos Stavrakakis

704 1a894bfe Christos Stavrakakis
    """
705 17852fe9 Giorgos Verigakis
706 1a894bfe Christos Stavrakakis
    if not resources:
707 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
708 41303ed0 Vangelis Koukis
709 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
710 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
711 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
712 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
713 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
714 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
715 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
716 1a894bfe Christos Stavrakakis
    backend.save()
717 1a894bfe Christos Stavrakakis
718 1a894bfe Christos Stavrakakis
719 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
720 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
721 1a894bfe Christos Stavrakakis

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

725 1a894bfe Christos Stavrakakis
    """
726 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
727 3524241a Christos Stavrakakis
        instances = client.GetInstances(bulk=True)
728 1a894bfe Christos Stavrakakis
    mem = 0
729 1a894bfe Christos Stavrakakis
    for i in instances:
730 1a894bfe Christos Stavrakakis
        mem += i['oper_ram']
731 1a894bfe Christos Stavrakakis
    return mem
732 b3d28af2 Christos Stavrakakis
733 b3d28af2 Christos Stavrakakis
##
734 b3d28af2 Christos Stavrakakis
## Synchronized operations for reconciliation
735 b3d28af2 Christos Stavrakakis
##
736 b3d28af2 Christos Stavrakakis
737 b3d28af2 Christos Stavrakakis
738 b3d28af2 Christos Stavrakakis
def create_network_synced(network, backend):
739 b3d28af2 Christos Stavrakakis
    result = _create_network_synced(network, backend)
740 b3d28af2 Christos Stavrakakis
    if result[0] != 'success':
741 b3d28af2 Christos Stavrakakis
        return result
742 b3d28af2 Christos Stavrakakis
    result = connect_network_synced(network, backend)
743 b3d28af2 Christos Stavrakakis
    return result
744 b3d28af2 Christos Stavrakakis
745 b3d28af2 Christos Stavrakakis
746 b3d28af2 Christos Stavrakakis
def _create_network_synced(network, backend):
747 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
748 e60b4630 Christos Stavrakakis
        job = _create_network(network, backend)
749 3524241a Christos Stavrakakis
        result = wait_for_job(client, job)
750 3524241a Christos Stavrakakis
    return result
751 b3d28af2 Christos Stavrakakis
752 b3d28af2 Christos Stavrakakis
753 b3d28af2 Christos Stavrakakis
def connect_network_synced(network, backend):
754 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
755 3524241a Christos Stavrakakis
        for group in client.GetGroups():
756 b7d38981 Dimitris Aragiorgis
            job = client.ConnectNetwork(network.backend_id, group,
757 b7d38981 Dimitris Aragiorgis
                                        network.mode, network.link)
758 3524241a Christos Stavrakakis
            result = wait_for_job(client, job)
759 3524241a Christos Stavrakakis
            if result[0] != 'success':
760 3524241a Christos Stavrakakis
                return result
761 b3d28af2 Christos Stavrakakis
762 b3d28af2 Christos Stavrakakis
    return result
763 b3d28af2 Christos Stavrakakis
764 b3d28af2 Christos Stavrakakis
765 b3d28af2 Christos Stavrakakis
def wait_for_job(client, jobid):
766 b3d28af2 Christos Stavrakakis
    result = client.WaitForJobChange(jobid, ['status', 'opresult'], None, None)
767 b3d28af2 Christos Stavrakakis
    status = result['job_info'][0]
768 b3d28af2 Christos Stavrakakis
    while status not in ['success', 'error', 'cancel']:
769 b3d28af2 Christos Stavrakakis
        result = client.WaitForJobChange(jobid, ['status', 'opresult'],
770 cc92b70f Christos Stavrakakis
                                         [result], None)
771 b3d28af2 Christos Stavrakakis
        status = result['job_info'][0]
772 b3d28af2 Christos Stavrakakis
773 b3d28af2 Christos Stavrakakis
    if status == 'success':
774 b3d28af2 Christos Stavrakakis
        return (status, None)
775 b3d28af2 Christos Stavrakakis
    else:
776 b3d28af2 Christos Stavrakakis
        error = result['job_info'][1]
777 b3d28af2 Christos Stavrakakis
        return (status, error)