Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (26.1 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 37ca953f Christodoulos Psaltis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 37ca953f Christodoulos Psaltis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 37ca953f Christodoulos Psaltis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 37ca953f Christodoulos Psaltis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 37ca953f Christodoulos Psaltis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 529178b1 Giorgos Verigakis
from django.conf import settings
34 207b70d5 Giorgos Verigakis
from django.db import transaction
35 1a894bfe Christos Stavrakakis
from datetime import datetime
36 207b70d5 Giorgos Verigakis
37 22ee6892 Christos Stavrakakis
from synnefo.db.models import (Backend, VirtualMachine, Network,
38 3524241a Christos Stavrakakis
                               BackendNetwork, BACKEND_STATUSES,
39 fd95834e Christos Stavrakakis
                               pooled_rapi_client, VirtualMachineDiagnostic)
40 03992c72 Christos Stavrakakis
from synnefo.logic import utils
41 cb4eee84 Christos Stavrakakis
from synnefo import quotas
42 b7d38981 Dimitris Aragiorgis
from synnefo.api.util import release_resource
43 fd95834e Christos Stavrakakis
from synnefo.util.mac2eui64 import mac2eui64
44 529178b1 Giorgos Verigakis
45 3524241a Christos Stavrakakis
from logging import getLogger
46 3524241a Christos Stavrakakis
log = getLogger(__name__)
47 9e98ba3c Giorgos Verigakis
48 529178b1 Giorgos Verigakis
49 efff6193 Giorgos Verigakis
_firewall_tags = {
50 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
51 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
52 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
53 efff6193 Giorgos Verigakis
54 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
55 efff6193 Giorgos Verigakis
56 02feca11 Vassilios Karakoidas
57 093f9c53 Vangelis Koukis
@transaction.commit_on_success
58 fd95834e Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None):
59 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
60 02feca11 Vassilios Karakoidas

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

65 02feca11 Vassilios Karakoidas
    """
66 41303ed0 Vangelis Koukis
    # See #1492, #1031, #1111 why this line has been removed
67 41303ed0 Vangelis Koukis
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
68 fd65ab41 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
69 02feca11 Vassilios Karakoidas
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
70 02feca11 Vassilios Karakoidas
71 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = jobid
72 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = status
73 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = opcode
74 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = logmsg
75 02feca11 Vassilios Karakoidas
76 02feca11 Vassilios Karakoidas
    # Notifications of success change the operating state
77 41303ed0 Vangelis Koukis
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
78 41303ed0 Vangelis Koukis
    if status == 'success' and state_for_success is not None:
79 c4ce868e Christos Stavrakakis
        vm.operstate = state_for_success
80 685b219e Vangelis Koukis
81 fd95834e Christos Stavrakakis
    # Update the NICs of the VM
82 fd95834e Christos Stavrakakis
    if status == "success" and nics is not None:
83 fd95834e Christos Stavrakakis
        _process_net_status(vm, etime, nics)
84 fd95834e Christos Stavrakakis
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 40d53b77 Christos Stavrakakis
            _process_net_status(vm, etime, nics=[])
98 e97288bc Christos Stavrakakis
            vm.deleted = True
99 e97288bc Christos Stavrakakis
            vm.operstate = state_for_success
100 e97288bc Christos Stavrakakis
            vm.backendtime = etime
101 2509ce17 Christos Stavrakakis
            # Issue and accept commission to Quotaholder
102 2509ce17 Christos Stavrakakis
            quotas.issue_and_accept_commission(vm, delete=True)
103 093f9c53 Vangelis Koukis
104 c4ce868e Christos Stavrakakis
    # Update backendtime only for jobs that have been successfully completed,
105 c4ce868e Christos Stavrakakis
    # since only these jobs update the state of the VM. Else a "race condition"
106 c4ce868e Christos Stavrakakis
    # may occur when a successful job (e.g. OP_INSTANCE_REMOVE) completes
107 c4ce868e Christos Stavrakakis
    # before an error job and messages arrive in reversed order.
108 c4ce868e Christos Stavrakakis
    if status == 'success':
109 c4ce868e Christos Stavrakakis
        vm.backendtime = etime
110 02feca11 Vassilios Karakoidas
111 02feca11 Vassilios Karakoidas
    vm.save()
112 22e52ede Vassilios Karakoidas
113 ad2d6807 Vangelis Koukis
114 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
115 c4e55622 Christos Stavrakakis
def process_net_status(vm, etime, nics):
116 fd95834e Christos Stavrakakis
    """Wrap _process_net_status inside transaction."""
117 fd95834e Christos Stavrakakis
    _process_net_status(vm, etime, nics)
118 fd95834e Christos Stavrakakis
119 fd95834e Christos Stavrakakis
120 fd95834e Christos Stavrakakis
def _process_net_status(vm, etime, nics):
121 ad2d6807 Vangelis Koukis
    """Process a net status notification from the backend
122 ad2d6807 Vangelis Koukis

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

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

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

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

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

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

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

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

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

669 1a894bfe Christos Stavrakakis
    """
670 e77a29ab Christos Stavrakakis
    nodes = get_nodes(backend, bulk=True)
671 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
672 1a894bfe Christos Stavrakakis
    res = {}
673 1a894bfe Christos Stavrakakis
    for a in attr:
674 1a894bfe Christos Stavrakakis
        res[a] = 0
675 1a894bfe Christos Stavrakakis
    for n in nodes:
676 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
677 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
678 cc92b70f Christos Stavrakakis
        can_host_vms = n['vm_capable'] and not (n['drained'] or n['offline'])
679 cc92b70f Christos Stavrakakis
        if can_host_vms and n['cnodes']:
680 1a894bfe Christos Stavrakakis
            for a in attr:
681 1a894bfe Christos Stavrakakis
                res[a] += int(n[a])
682 1a894bfe Christos Stavrakakis
    return res
683 1a894bfe Christos Stavrakakis
684 1a894bfe Christos Stavrakakis
685 1a894bfe Christos Stavrakakis
def update_resources(backend, resources=None):
686 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
687 1a894bfe Christos Stavrakakis

688 1a894bfe Christos Stavrakakis
    """
689 17852fe9 Giorgos Verigakis
690 1a894bfe Christos Stavrakakis
    if not resources:
691 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
692 41303ed0 Vangelis Koukis
693 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
694 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
695 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
696 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
697 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
698 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
699 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
700 1a894bfe Christos Stavrakakis
    backend.save()
701 1a894bfe Christos Stavrakakis
702 1a894bfe Christos Stavrakakis
703 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
704 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
705 1a894bfe Christos Stavrakakis

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

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