Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (23.2 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 2035039b Giorgos Verigakis
from logging import getLogger
37 529178b1 Giorgos Verigakis
from django.conf import settings
38 207b70d5 Giorgos Verigakis
from django.db import transaction
39 1a894bfe Christos Stavrakakis
from datetime import datetime
40 207b70d5 Giorgos Verigakis
41 22ee6892 Christos Stavrakakis
from synnefo.db.models import (Backend, VirtualMachine, Network,
42 22ee6892 Christos Stavrakakis
                               BackendNetwork, BACKEND_STATUSES)
43 864bed43 Christos Stavrakakis
from synnefo.logic import utils, ippool
44 8a4a931d Christos Stavrakakis
from synnefo.api.faults import OverLimit
45 529178b1 Giorgos Verigakis
from synnefo.util.rapi import GanetiRapiClient
46 529178b1 Giorgos Verigakis
47 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.logic')
48 9e98ba3c Giorgos Verigakis
49 529178b1 Giorgos Verigakis
50 efff6193 Giorgos Verigakis
_firewall_tags = {
51 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
52 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
53 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
54 efff6193 Giorgos Verigakis
55 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
56 efff6193 Giorgos Verigakis
57 02feca11 Vassilios Karakoidas
58 924d8085 Christos Stavrakakis
def create_client(hostname, port=5080, username=None, password=None):
59 1a894bfe Christos Stavrakakis
    return GanetiRapiClient(hostname, port, username, password)
60 924d8085 Christos Stavrakakis
61 22ee6892 Christos Stavrakakis
62 093f9c53 Vangelis Koukis
@transaction.commit_on_success
63 c4e55622 Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg):
64 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
65 02feca11 Vassilios Karakoidas

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

70 02feca11 Vassilios Karakoidas
    """
71 41303ed0 Vangelis Koukis
    # See #1492, #1031, #1111 why this line has been removed
72 41303ed0 Vangelis Koukis
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
73 fd65ab41 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
74 02feca11 Vassilios Karakoidas
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
75 02feca11 Vassilios Karakoidas
76 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = jobid
77 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = status
78 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = opcode
79 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = logmsg
80 02feca11 Vassilios Karakoidas
81 02feca11 Vassilios Karakoidas
    # Notifications of success change the operating state
82 41303ed0 Vangelis Koukis
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
83 41303ed0 Vangelis Koukis
    if status == 'success' and state_for_success is not None:
84 41303ed0 Vangelis Koukis
        utils.update_state(vm, state_for_success)
85 41303ed0 Vangelis Koukis
        # Set the deleted flag explicitly, cater for admin-initiated removals
86 685b219e Vangelis Koukis
        if opcode == 'OP_INSTANCE_REMOVE':
87 bd392934 Christos Stavrakakis
            release_instance_nics(vm)
88 685b219e Vangelis Koukis
            vm.deleted = True
89 9c21a2e2 Christos Stavrakakis
            vm.nics.all().delete()
90 685b219e Vangelis Koukis
91 91954b45 Christos Stavrakakis
    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
92 91954b45 Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_INSTANCE_CREATE':
93 234f8b07 Vangelis Koukis
        utils.update_state(vm, 'ERROR')
94 093f9c53 Vangelis Koukis
95 093f9c53 Vangelis Koukis
    # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
96 093f9c53 Vangelis Koukis
    # when no instance exists at the Ganeti backend.
97 093f9c53 Vangelis Koukis
    # See ticket #799 for all the details.
98 093f9c53 Vangelis Koukis
    #
99 788a54be Christos Stavrakakis
    if (status == 'error' and opcode == 'OP_INSTANCE_REMOVE'):
100 093f9c53 Vangelis Koukis
        vm.deleted = True
101 9c21a2e2 Christos Stavrakakis
        vm.nics.all().delete()
102 093f9c53 Vangelis Koukis
103 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
104 02feca11 Vassilios Karakoidas
    # Any other notification of failure leaves the operating state unchanged
105 02feca11 Vassilios Karakoidas
106 02feca11 Vassilios Karakoidas
    vm.save()
107 22e52ede Vassilios Karakoidas
108 ad2d6807 Vangelis Koukis
109 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
110 c4e55622 Christos Stavrakakis
def process_net_status(vm, etime, nics):
111 ad2d6807 Vangelis Koukis
    """Process a net status notification from the backend
112 ad2d6807 Vangelis Koukis

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

116 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
117 ad2d6807 Vangelis Koukis
    """
118 37ca953f Christodoulos Psaltis
119 bd392934 Christos Stavrakakis
    # Release the ips of the old nics. Get back the networks as multiple
120 bd392934 Christos Stavrakakis
    # changes in the same network, must happen in the same Network object,
121 bd392934 Christos Stavrakakis
    # because transaction will be commited only on exit of the function.
122 bd392934 Christos Stavrakakis
    networks = release_instance_nics(vm)
123 77f0fa63 Christos Stavrakakis
124 bd392934 Christos Stavrakakis
    new_nics = enumerate(nics)
125 77f0fa63 Christos Stavrakakis
    for i, new_nic in new_nics:
126 77f0fa63 Christos Stavrakakis
        network = new_nic.get('network', '')
127 22ee6892 Christos Stavrakakis
        n = str(network)
128 77f0fa63 Christos Stavrakakis
        pk = utils.id_from_network_name(n)
129 77f0fa63 Christos Stavrakakis
130 77f0fa63 Christos Stavrakakis
        # Get the cached Network or get it from DB
131 77f0fa63 Christos Stavrakakis
        if pk in networks:
132 77f0fa63 Christos Stavrakakis
            net = networks[pk]
133 64938cb0 Giorgos Verigakis
        else:
134 864bed43 Christos Stavrakakis
            net = Network.objects.select_for_update().get(pk=pk)
135 77f0fa63 Christos Stavrakakis
136 77f0fa63 Christos Stavrakakis
        # Get the new nic info
137 77f0fa63 Christos Stavrakakis
        mac = new_nic.get('mac', '')
138 77f0fa63 Christos Stavrakakis
        ipv4 = new_nic.get('ip', '')
139 77f0fa63 Christos Stavrakakis
        ipv6 = new_nic.get('ipv6', '')
140 9afeb669 Kostas Papadimitriou
141 77f0fa63 Christos Stavrakakis
        firewall = new_nic.get('firewall', '')
142 658a825a Giorgos Verigakis
        firewall_profile = _reverse_tags.get(firewall, '')
143 658a825a Giorgos Verigakis
        if not firewall_profile and net.public:
144 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
145 9afeb669 Kostas Papadimitriou
146 77f0fa63 Christos Stavrakakis
        if ipv4:
147 77f0fa63 Christos Stavrakakis
            net.reserve_address(ipv4)
148 77f0fa63 Christos Stavrakakis
149 64938cb0 Giorgos Verigakis
        vm.nics.create(
150 64938cb0 Giorgos Verigakis
            network=net,
151 64938cb0 Giorgos Verigakis
            index=i,
152 77f0fa63 Christos Stavrakakis
            mac=mac,
153 77f0fa63 Christos Stavrakakis
            ipv4=ipv4,
154 77f0fa63 Christos Stavrakakis
            ipv6=ipv6,
155 0196d9a3 Christos Stavrakakis
            firewall_profile=firewall_profile,
156 0196d9a3 Christos Stavrakakis
            dirty=False)
157 9afeb669 Kostas Papadimitriou
158 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
159 ad2d6807 Vangelis Koukis
    vm.save()
160 22ee6892 Christos Stavrakakis
161 22ee6892 Christos Stavrakakis
162 bd392934 Christos Stavrakakis
def release_instance_nics(vm):
163 bd392934 Christos Stavrakakis
    networks = {}
164 bd392934 Christos Stavrakakis
165 bd392934 Christos Stavrakakis
    for nic in vm.nics.all():
166 bd392934 Christos Stavrakakis
        pk = nic.network.pk
167 bd392934 Christos Stavrakakis
        # Get the cached Network or get it from DB
168 bd392934 Christos Stavrakakis
        if pk in networks:
169 bd392934 Christos Stavrakakis
            net = networks[pk]
170 bd392934 Christos Stavrakakis
        else:
171 bd392934 Christos Stavrakakis
            # Get the network object in exclusive mode in order
172 bd392934 Christos Stavrakakis
            # to guarantee consistency of the address pool
173 bd392934 Christos Stavrakakis
            net = Network.objects.select_for_update().get(pk=pk)
174 2b36eda5 Christos Stavrakakis
        if nic.ipv4:
175 2b36eda5 Christos Stavrakakis
            net.release_address(nic.ipv4)
176 bd392934 Christos Stavrakakis
        nic.delete()
177 bd392934 Christos Stavrakakis
178 bd392934 Christos Stavrakakis
    return networks
179 bd392934 Christos Stavrakakis
180 bd392934 Christos Stavrakakis
181 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
182 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
183 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
184 22ee6892 Christos Stavrakakis
        return
185 22ee6892 Christos Stavrakakis
        #raise Network.InvalidBackendMsgError(opcode, status)
186 22ee6892 Christos Stavrakakis
187 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
188 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
189 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
190 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
191 22ee6892 Christos Stavrakakis
192 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
193 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
194 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
195 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
196 22ee6892 Christos Stavrakakis
        if opcode == 'OP_NETWORK_REMOVE':
197 22ee6892 Christos Stavrakakis
            back_network.deleted = True
198 22ee6892 Christos Stavrakakis
199 9c65f166 Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_CREATE':
200 22ee6892 Christos Stavrakakis
        utils.update_state(back_network, 'ERROR')
201 22ee6892 Christos Stavrakakis
202 9c65f166 Christos Stavrakakis
    if (status == 'error' and opcode == 'OP_NETWORK_REMOVE'):
203 22ee6892 Christos Stavrakakis
        back_network.deleted = True
204 22ee6892 Christos Stavrakakis
        back_network.operstate = 'DELETED'
205 22ee6892 Christos Stavrakakis
206 22ee6892 Christos Stavrakakis
    back_network.save()
207 ad2d6807 Vangelis Koukis
208 c25cc9ec Vangelis Koukis
209 9068cd85 Georgios Gousios
@transaction.commit_on_success
210 0827883e Nikos Skalkotos
def process_create_progress(vm, etime, progress):
211 9068cd85 Georgios Gousios
212 0827883e Nikos Skalkotos
    percentage = int(progress)
213 9068cd85 Georgios Gousios
214 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
215 0827883e Nikos Skalkotos
    # snf-image:copy-progress tracks bytes read by image handling processes
216 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
217 af90d919 Vangelis Koukis
    if percentage < 0:
218 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
219 9068cd85 Georgios Gousios
220 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
221 7ec9558b Vangelis Koukis
#   if last_update > percentage:
222 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
223 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
224 9068cd85 Georgios Gousios
225 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
226 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
227 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
228 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
229 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
230 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
231 c25cc9ec Vangelis Koukis
    #
232 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
233 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
234 9068cd85 Georgios Gousios
235 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
236 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
237 9068cd85 Georgios Gousios
    vm.save()
238 ad2d6807 Vangelis Koukis
239 c25cc9ec Vangelis Koukis
240 22e52ede Vassilios Karakoidas
def start_action(vm, action):
241 22e52ede Vassilios Karakoidas
    """Update the state of a VM when a new action is initiated."""
242 22e52ede Vassilios Karakoidas
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
243 22e52ede Vassilios Karakoidas
        raise VirtualMachine.InvalidActionError(action)
244 22e52ede Vassilios Karakoidas
245 22e52ede Vassilios Karakoidas
    # No actions to deleted and no actions beside destroy to suspended VMs
246 22e52ede Vassilios Karakoidas
    if vm.deleted:
247 5231a38a Giorgos Verigakis
        raise VirtualMachine.DeletedError
248 37ca953f Christodoulos Psaltis
249 30f3b5e5 Vangelis Koukis
    # No actions to machines being built. They may be destroyed, however.
250 30f3b5e5 Vangelis Koukis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
251 5231a38a Giorgos Verigakis
        raise VirtualMachine.BuildingError
252 37ca953f Christodoulos Psaltis
253 dfd19c2d Vassilios Karakoidas
    vm.action = action
254 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = None
255 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = None
256 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = None
257 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = None
258 22e52ede Vassilios Karakoidas
259 f90c3d8c Vangelis Koukis
    # Update the relevant flags if the VM is being suspended or destroyed.
260 f90c3d8c Vangelis Koukis
    # Do not set the deleted flag here, see ticket #721.
261 f90c3d8c Vangelis Koukis
    #
262 f90c3d8c Vangelis Koukis
    # The deleted flag is set asynchronously, when an OP_INSTANCE_REMOVE
263 f90c3d8c Vangelis Koukis
    # completes successfully. Hence, a server may be visible for some time
264 f90c3d8c Vangelis Koukis
    # after a DELETE /servers/id returns HTTP 204.
265 f90c3d8c Vangelis Koukis
    #
266 22e52ede Vassilios Karakoidas
    if action == "DESTROY":
267 f90c3d8c Vangelis Koukis
        # vm.deleted = True
268 f90c3d8c Vangelis Koukis
        pass
269 22e52ede Vassilios Karakoidas
    elif action == "SUSPEND":
270 22e52ede Vassilios Karakoidas
        vm.suspended = True
271 22e52ede Vassilios Karakoidas
    elif action == "START":
272 22e52ede Vassilios Karakoidas
        vm.suspended = False
273 22e52ede Vassilios Karakoidas
    vm.save()
274 529178b1 Giorgos Verigakis
275 ad2d6807 Vangelis Koukis
276 967d3f83 Christos Stavrakakis
@transaction.commit_on_success
277 2b1db26f Giorgos Verigakis
def create_instance(vm, flavor, image, password, personality):
278 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
279 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
280 7f691719 Christos Stavrakakis

281 3a9b3cde Giorgos Verigakis
        metadata value should be a dictionary.
282 3a9b3cde Giorgos Verigakis
    """
283 864bed43 Christos Stavrakakis
284 ad297723 Christos Stavrakakis
    if settings.PUBLIC_ROUTED_USE_POOL:
285 ad297723 Christos Stavrakakis
        # Get the Network object in exclusive mode in order to
286 ad297723 Christos Stavrakakis
        # safely (isolated) reserve an IP address
287 aeb523a4 Christos Stavrakakis
        try:
288 aeb523a4 Christos Stavrakakis
            network = Network.objects.select_for_update().get(public=True)
289 aeb523a4 Christos Stavrakakis
        except Network.DoesNotExist:
290 aeb523a4 Christos Stavrakakis
            raise Exception('No public network available')
291 ad297723 Christos Stavrakakis
        pool = ippool.IPPool(network)
292 ad297723 Christos Stavrakakis
        try:
293 ad297723 Christos Stavrakakis
            address = pool.get_free_address()
294 ad297723 Christos Stavrakakis
        except ippool.IPPool.IPPoolExhausted:
295 ad297723 Christos Stavrakakis
            raise OverLimit("Can not allocate IP for new machine."
296 ad297723 Christos Stavrakakis
                            " Public network is full.")
297 ad297723 Christos Stavrakakis
        pool.save()
298 ad297723 Christos Stavrakakis
        nic = {'ip': address, 'network': settings.GANETI_PUBLIC_NETWORK}
299 ad297723 Christos Stavrakakis
    else:
300 ad297723 Christos Stavrakakis
        nic = {'ip': 'pool', 'network': settings.GANETI_PUBLIC_NETWORK}
301 61868190 Vangelis Koukis
302 61868190 Vangelis Koukis
    if settings.IGNORE_FLAVOR_DISK_SIZES:
303 3a9b3cde Giorgos Verigakis
        if image['backend_id'].find("windows") >= 0:
304 61868190 Vangelis Koukis
            sz = 14000
305 61868190 Vangelis Koukis
        else:
306 61868190 Vangelis Koukis
            sz = 4000
307 cf0e4232 Vangelis Koukis
    else:
308 61868190 Vangelis Koukis
        sz = flavor.disk * 1024
309 37ca953f Christodoulos Psaltis
310 1c382247 Vangelis Koukis
    # Handle arguments to CreateInstance() as a dictionary,
311 1c382247 Vangelis Koukis
    # initialize it based on a deployment-specific value.
312 1c382247 Vangelis Koukis
    # This enables the administrator to override deployment-specific
313 c25cc9ec Vangelis Koukis
    # arguments, such as the disk template to use, name of os provider
314 1c382247 Vangelis Koukis
    # and hypervisor-specific parameters at will (see Synnefo #785, #835).
315 1c382247 Vangelis Koukis
    #
316 1c382247 Vangelis Koukis
    kw = settings.GANETI_CREATEINSTANCE_KWARGS
317 1c382247 Vangelis Koukis
    kw['mode'] = 'create'
318 924d8085 Christos Stavrakakis
    kw['name'] = vm.backend_vm_id
319 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
320 296682fe Kostas Papadimitriou
321 296682fe Kostas Papadimitriou
    # Identify if provider parameter should be set in disk options.
322 296682fe Kostas Papadimitriou
    # Current implementation support providers only fo ext template.
323 296682fe Kostas Papadimitriou
    # To select specific provider for an ext template, template name
324 296682fe Kostas Papadimitriou
    # should be formated as `ext_<provider_name>`.
325 296682fe Kostas Papadimitriou
    provider = None
326 296682fe Kostas Papadimitriou
    disk_template = flavor.disk_template
327 296682fe Kostas Papadimitriou
    if flavor.disk_template.startswith("ext"):
328 296682fe Kostas Papadimitriou
        disk_template, provider = flavor.disk_template.split("_", 1)
329 296682fe Kostas Papadimitriou
330 296682fe Kostas Papadimitriou
    kw['disk_template'] = disk_template
331 1c382247 Vangelis Koukis
    kw['disks'] = [{"size": sz}]
332 296682fe Kostas Papadimitriou
    if provider:
333 296682fe Kostas Papadimitriou
        kw['disks'][0]['provider'] = provider
334 296682fe Kostas Papadimitriou
335 296682fe Kostas Papadimitriou
336 1c382247 Vangelis Koukis
    kw['nics'] = [nic]
337 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
338 1c382247 Vangelis Koukis
    # kw['os'] = settings.GANETI_OS_PROVIDER
339 1c382247 Vangelis Koukis
    kw['ip_check'] = False
340 1c382247 Vangelis Koukis
    kw['name_check'] = False
341 1c382247 Vangelis Koukis
    # Do not specific a node explicitly, have
342 1c382247 Vangelis Koukis
    # Ganeti use an iallocator instead
343 1c382247 Vangelis Koukis
    #
344 1c382247 Vangelis Koukis
    # kw['pnode']=rapi.GetNodes()[0]
345 1c382247 Vangelis Koukis
    kw['dry_run'] = settings.TEST
346 41303ed0 Vangelis Koukis
347 2b1db26f Giorgos Verigakis
    kw['beparams'] = {
348 2b1db26f Giorgos Verigakis
        'auto_balance': True,
349 2b1db26f Giorgos Verigakis
        'vcpus': flavor.cpu,
350 2b1db26f Giorgos Verigakis
        'memory': flavor.ram}
351 41303ed0 Vangelis Koukis
352 e3b5be49 Giorgos Verigakis
    kw['osparams'] = {
353 3a9b3cde Giorgos Verigakis
        'img_id': image['backend_id'],
354 e3b5be49 Giorgos Verigakis
        'img_passwd': password,
355 3a9b3cde Giorgos Verigakis
        'img_format': image['format']}
356 2b1db26f Giorgos Verigakis
    if personality:
357 e3b5be49 Giorgos Verigakis
        kw['osparams']['img_personality'] = json.dumps(personality)
358 d1eaa651 Christos Stavrakakis
359 3a9b3cde Giorgos Verigakis
    kw['osparams']['img_properties'] = json.dumps(image['metadata'])
360 d1eaa651 Christos Stavrakakis
361 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
362 1c382247 Vangelis Koukis
    # kw['hvparams'] = dict(serial_console=False)
363 1c382247 Vangelis Koukis
364 f5b4f2a3 Christos Stavrakakis
    return vm.client.CreateInstance(**kw)
365 f533f224 Vangelis Koukis
366 529178b1 Giorgos Verigakis
367 529178b1 Giorgos Verigakis
def delete_instance(vm):
368 529178b1 Giorgos Verigakis
    start_action(vm, 'DESTROY')
369 f5b4f2a3 Christos Stavrakakis
    vm.client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
370 529178b1 Giorgos Verigakis
371 ad2d6807 Vangelis Koukis
372 529178b1 Giorgos Verigakis
def reboot_instance(vm, reboot_type):
373 529178b1 Giorgos Verigakis
    assert reboot_type in ('soft', 'hard')
374 0827883e Nikos Skalkotos
    vm.client.RebootInstance(vm.backend_vm_id, reboot_type,
375 0827883e Nikos Skalkotos
                             dry_run=settings.TEST)
376 924d8085 Christos Stavrakakis
    log.info('Rebooting instance %s', vm.backend_vm_id)
377 529178b1 Giorgos Verigakis
378 ad2d6807 Vangelis Koukis
379 529178b1 Giorgos Verigakis
def startup_instance(vm):
380 529178b1 Giorgos Verigakis
    start_action(vm, 'START')
381 f5b4f2a3 Christos Stavrakakis
    vm.client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
382 529178b1 Giorgos Verigakis
383 ad2d6807 Vangelis Koukis
384 529178b1 Giorgos Verigakis
def shutdown_instance(vm):
385 529178b1 Giorgos Verigakis
    start_action(vm, 'STOP')
386 f5b4f2a3 Christos Stavrakakis
    vm.client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
387 529178b1 Giorgos Verigakis
388 ad2d6807 Vangelis Koukis
389 529178b1 Giorgos Verigakis
def get_instance_console(vm):
390 71099804 Vangelis Koukis
    # RAPI GetInstanceConsole() returns endpoints to the vnc_bind_address,
391 71099804 Vangelis Koukis
    # which is a cluster-wide setting, either 0.0.0.0 or 127.0.0.1, and pretty
392 71099804 Vangelis Koukis
    # useless (see #783).
393 71099804 Vangelis Koukis
    #
394 71099804 Vangelis Koukis
    # Until this is fixed on the Ganeti side, construct a console info reply
395 71099804 Vangelis Koukis
    # directly.
396 9afeb669 Kostas Papadimitriou
    #
397 71099804 Vangelis Koukis
    # WARNING: This assumes that VNC runs on port network_port on
398 71099804 Vangelis Koukis
    #          the instance's primary node, and is probably
399 71099804 Vangelis Koukis
    #          hypervisor-specific.
400 71099804 Vangelis Koukis
    #
401 71099804 Vangelis Koukis
    console = {}
402 71099804 Vangelis Koukis
    console['kind'] = 'vnc'
403 f5b4f2a3 Christos Stavrakakis
    i = vm.client.GetInstance(vm.backend_vm_id)
404 71099804 Vangelis Koukis
    if i['hvparams']['serial_console']:
405 71099804 Vangelis Koukis
        raise Exception("hv parameter serial_console cannot be true")
406 71099804 Vangelis Koukis
    console['host'] = i['pnode']
407 71099804 Vangelis Koukis
    console['port'] = i['network_port']
408 9afeb669 Kostas Papadimitriou
409 71099804 Vangelis Koukis
    return console
410 924d8085 Christos Stavrakakis
    # return rapi.GetInstanceConsole(vm.backend_vm_id)
411 64938cb0 Giorgos Verigakis
412 c25cc9ec Vangelis Koukis
413 604b2bf8 Georgios Gousios
def request_status_update(vm):
414 f5b4f2a3 Christos Stavrakakis
    return vm.client.GetInstanceInfo(vm.backend_vm_id)
415 604b2bf8 Georgios Gousios
416 604b2bf8 Georgios Gousios
417 604b2bf8 Georgios Gousios
def update_status(vm, status):
418 db7a3230 Vangelis Koukis
    utils.update_state(vm, status)
419 f533f224 Vangelis Koukis
420 c25cc9ec Vangelis Koukis
421 22ee6892 Christos Stavrakakis
def create_network(network, backends=None):
422 22ee6892 Christos Stavrakakis
    """ Add and connect a network to backends.
423 37ca953f Christodoulos Psaltis

424 22ee6892 Christos Stavrakakis
    @param network: Network object
425 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
426 64938cb0 Giorgos Verigakis

427 22ee6892 Christos Stavrakakis
    """
428 22ee6892 Christos Stavrakakis
    backend_jobs = _create_network(network, backends)
429 22ee6892 Christos Stavrakakis
    connect_network(network, backend_jobs)
430 22ee6892 Christos Stavrakakis
    return network
431 c25cc9ec Vangelis Koukis
432 37ca953f Christodoulos Psaltis
433 22ee6892 Christos Stavrakakis
def _create_network(network, backends=None):
434 22ee6892 Christos Stavrakakis
    """Add a network to backends.
435 22ee6892 Christos Stavrakakis
    @param network: Network object
436 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
437 64938cb0 Giorgos Verigakis

438 22ee6892 Christos Stavrakakis
    """
439 c25cc9ec Vangelis Koukis
440 22ee6892 Christos Stavrakakis
    network_type = network.public and 'public' or 'private'
441 22ee6892 Christos Stavrakakis
    if not backends:
442 22ee6892 Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
443 22ee6892 Christos Stavrakakis
444 22ee6892 Christos Stavrakakis
    tags = network.backend_tag
445 22ee6892 Christos Stavrakakis
    if network.dhcp:
446 22ee6892 Christos Stavrakakis
        tags.append('nfdhcpd')
447 22ee6892 Christos Stavrakakis
    tags = ','.join(tags)
448 22ee6892 Christos Stavrakakis
449 22ee6892 Christos Stavrakakis
    backend_jobs = []
450 22ee6892 Christos Stavrakakis
    for backend in backends:
451 3165f027 Christos Stavrakakis
        try:
452 3165f027 Christos Stavrakakis
            backend_network = BackendNetwork.objects.get(network=network,
453 3165f027 Christos Stavrakakis
                                                         backend=backend)
454 3165f027 Christos Stavrakakis
        except BackendNetwork.DoesNotExist:
455 3165f027 Christos Stavrakakis
            raise Exception("BackendNetwork for network '%s' in backend '%s'"\
456 3165f027 Christos Stavrakakis
                            " does not exist" % (network.id, backend.id))
457 22ee6892 Christos Stavrakakis
        job = backend.client.CreateNetwork(
458 22ee6892 Christos Stavrakakis
                network_name=network.backend_id,
459 22ee6892 Christos Stavrakakis
                network=network.subnet,
460 22ee6892 Christos Stavrakakis
                gateway=network.gateway,
461 22ee6892 Christos Stavrakakis
                network_type=network_type,
462 3165f027 Christos Stavrakakis
                mac_prefix=backend_network.mac_prefix,
463 22ee6892 Christos Stavrakakis
                tags=tags)
464 22ee6892 Christos Stavrakakis
        backend_jobs.append((backend, job))
465 22ee6892 Christos Stavrakakis
466 22ee6892 Christos Stavrakakis
    return backend_jobs
467 22ee6892 Christos Stavrakakis
468 22ee6892 Christos Stavrakakis
469 22ee6892 Christos Stavrakakis
def connect_network(network, backend_jobs=None):
470 22ee6892 Christos Stavrakakis
    """Connect a network to all nodegroups.
471 22ee6892 Christos Stavrakakis

472 22ee6892 Christos Stavrakakis
    @param network: Network object
473 22ee6892 Christos Stavrakakis
    @param backend_jobs: List of tuples of the form (Backend, jobs) which are
474 22ee6892 Christos Stavrakakis
                         the backends to connect the network and the jobs on
475 22ee6892 Christos Stavrakakis
                         which the connect job depends.
476 22ee6892 Christos Stavrakakis

477 22ee6892 Christos Stavrakakis
    """
478 64938cb0 Giorgos Verigakis
479 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
480 839e2bd0 Christos Stavrakakis
        mode = 'routed'
481 839e2bd0 Christos Stavrakakis
    else:
482 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
483 c25cc9ec Vangelis Koukis
484 22ee6892 Christos Stavrakakis
    if not backend_jobs:
485 22ee6892 Christos Stavrakakis
        backend_jobs = [(backend, []) for backend in
486 22ee6892 Christos Stavrakakis
                        Backend.objects.exclude(offline=True)]
487 64938cb0 Giorgos Verigakis
488 22ee6892 Christos Stavrakakis
    for backend, job in backend_jobs:
489 22ee6892 Christos Stavrakakis
        client = backend.client
490 22ee6892 Christos Stavrakakis
        for group in client.GetGroups():
491 22ee6892 Christos Stavrakakis
            client.ConnectNetwork(network.backend_id, group, mode,
492 22ee6892 Christos Stavrakakis
                                  network.link, [job])
493 22ee6892 Christos Stavrakakis
494 22ee6892 Christos Stavrakakis
495 22ee6892 Christos Stavrakakis
def connect_network_group(backend, network, group):
496 22ee6892 Christos Stavrakakis
    """Connect a network to a specific nodegroup of a backend.
497 22ee6892 Christos Stavrakakis

498 22ee6892 Christos Stavrakakis
    """
499 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
500 839e2bd0 Christos Stavrakakis
        mode = 'routed'
501 839e2bd0 Christos Stavrakakis
    else:
502 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
503 22ee6892 Christos Stavrakakis
504 22ee6892 Christos Stavrakakis
    return backend.client.ConnectNetwork(network.backend_id, group, mode,
505 22ee6892 Christos Stavrakakis
                                         network.link)
506 22ee6892 Christos Stavrakakis
507 22ee6892 Christos Stavrakakis
508 22ee6892 Christos Stavrakakis
def delete_network(network, backends=None):
509 22ee6892 Christos Stavrakakis
    """ Disconnect and a remove a network from backends.
510 22ee6892 Christos Stavrakakis

511 22ee6892 Christos Stavrakakis
    @param network: Network object
512 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
513 22ee6892 Christos Stavrakakis

514 22ee6892 Christos Stavrakakis
    """
515 22ee6892 Christos Stavrakakis
    backend_jobs = disconnect_network(network, backends)
516 22ee6892 Christos Stavrakakis
    _delete_network(network, backend_jobs)
517 22ee6892 Christos Stavrakakis
518 22ee6892 Christos Stavrakakis
519 22ee6892 Christos Stavrakakis
def disconnect_network(network, backends=None):
520 0196d9a3 Christos Stavrakakis
    """Disconnect a network from all nodegroups.
521 22ee6892 Christos Stavrakakis

522 22ee6892 Christos Stavrakakis
    @param network: Network object
523 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
524 22ee6892 Christos Stavrakakis

525 22ee6892 Christos Stavrakakis
    """
526 22ee6892 Christos Stavrakakis
527 22ee6892 Christos Stavrakakis
    if not backends:
528 22ee6892 Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
529 22ee6892 Christos Stavrakakis
530 22ee6892 Christos Stavrakakis
    backend_jobs = []
531 22ee6892 Christos Stavrakakis
    for backend in backends:
532 22ee6892 Christos Stavrakakis
        client = backend.client
533 22ee6892 Christos Stavrakakis
        jobs = []
534 22ee6892 Christos Stavrakakis
        for group in client.GetGroups():
535 0196d9a3 Christos Stavrakakis
            job = client.DisconnectNetwork(network.backend_id, group)
536 0196d9a3 Christos Stavrakakis
            jobs.append(job)
537 0196d9a3 Christos Stavrakakis
        backend_jobs.append((backend, jobs))
538 22ee6892 Christos Stavrakakis
539 22ee6892 Christos Stavrakakis
    return backend_jobs
540 22ee6892 Christos Stavrakakis
541 22ee6892 Christos Stavrakakis
542 0196d9a3 Christos Stavrakakis
def disconnect_from_network(vm, nic):
543 22ee6892 Christos Stavrakakis
    """Disconnect a virtual machine from a network by removing it's nic.
544 22ee6892 Christos Stavrakakis

545 22ee6892 Christos Stavrakakis
    @param vm: VirtualMachine object
546 22ee6892 Christos Stavrakakis
    @param network: Network object
547 22ee6892 Christos Stavrakakis

548 22ee6892 Christos Stavrakakis
    """
549 c25cc9ec Vangelis Koukis
550 36f4cb29 Christos Stavrakakis
    op = [('remove', nic.index, {})]
551 36f4cb29 Christos Stavrakakis
    return vm.client.ModifyInstance(vm.backend_vm_id, nics=op,
552 16ddd1fe Christos Stavrakakis
                                    hotplug=settings.GANETI_USE_HOTPLUG,
553 16ddd1fe Christos Stavrakakis
                                    dry_run=settings.TEST)
554 36f4cb29 Christos Stavrakakis
555 36f4cb29 Christos Stavrakakis
556 22ee6892 Christos Stavrakakis
def _delete_network(network, backend_jobs=None):
557 22ee6892 Christos Stavrakakis
    if not backend_jobs:
558 22ee6892 Christos Stavrakakis
        backend_jobs = [(backend, []) for backend in
559 22ee6892 Christos Stavrakakis
                Backend.objects.exclude(offline=True)]
560 22ee6892 Christos Stavrakakis
    for backend, jobs in backend_jobs:
561 22ee6892 Christos Stavrakakis
        backend.client.DeleteNetwork(network.backend_id, jobs)
562 22ee6892 Christos Stavrakakis
563 22ee6892 Christos Stavrakakis
564 77f0fa63 Christos Stavrakakis
def connect_to_network(vm, network, address):
565 22ee6892 Christos Stavrakakis
    """Connect a virtual machine to a network.
566 22ee6892 Christos Stavrakakis

567 22ee6892 Christos Stavrakakis
    @param vm: VirtualMachine object
568 22ee6892 Christos Stavrakakis
    @param network: Network object
569 22ee6892 Christos Stavrakakis

570 22ee6892 Christos Stavrakakis
    """
571 22ee6892 Christos Stavrakakis
572 77f0fa63 Christos Stavrakakis
    # ip = network.dhcp and 'pool' or None
573 22ee6892 Christos Stavrakakis
574 77f0fa63 Christos Stavrakakis
    nic = {'ip': address, 'network': network.backend_id}
575 22ee6892 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add',  nic)],
576 16ddd1fe Christos Stavrakakis
                             hotplug=settings.GANETI_USE_HOTPLUG,
577 16ddd1fe Christos Stavrakakis
                             dry_run=settings.TEST)
578 91826390 Giorgos Verigakis
579 c25cc9ec Vangelis Koukis
580 91826390 Giorgos Verigakis
def set_firewall_profile(vm, profile):
581 26563957 Giorgos Verigakis
    try:
582 26563957 Giorgos Verigakis
        tag = _firewall_tags[profile]
583 26563957 Giorgos Verigakis
    except KeyError:
584 91826390 Giorgos Verigakis
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
585 37ca953f Christodoulos Psaltis
586 f5b4f2a3 Christos Stavrakakis
    client = vm.client
587 26563957 Giorgos Verigakis
    # Delete all firewall tags
588 efff6193 Giorgos Verigakis
    for t in _firewall_tags.values():
589 f5b4f2a3 Christos Stavrakakis
        client.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST)
590 37ca953f Christodoulos Psaltis
591 f5b4f2a3 Christos Stavrakakis
    client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
592 9afeb669 Kostas Papadimitriou
593 2da5f785 Giorgos Verigakis
    # XXX NOP ModifyInstance call to force process_net_status to run
594 2da5f785 Giorgos Verigakis
    # on the dispatcher
595 f5b4f2a3 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id,
596 5eedb0e4 Vangelis Koukis
                        os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
597 5eedb0e4 Vangelis Koukis
598 41303ed0 Vangelis Koukis
599 f5b4f2a3 Christos Stavrakakis
def get_ganeti_instances(backend=None, bulk=False):
600 1a894bfe Christos Stavrakakis
    Instances = [c.client.GetInstances(bulk=bulk)\
601 1a894bfe Christos Stavrakakis
                 for c in get_backends(backend)]
602 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Instances, [])
603 f5b4f2a3 Christos Stavrakakis
604 f5b4f2a3 Christos Stavrakakis
605 f5b4f2a3 Christos Stavrakakis
def get_ganeti_nodes(backend=None, bulk=False):
606 f5b4f2a3 Christos Stavrakakis
    Nodes = [c.client.GetNodes(bulk=bulk) for c in get_backends(backend)]
607 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Nodes, [])
608 f5b4f2a3 Christos Stavrakakis
609 f5b4f2a3 Christos Stavrakakis
610 f5b4f2a3 Christos Stavrakakis
def get_ganeti_jobs(backend=None, bulk=False):
611 f5b4f2a3 Christos Stavrakakis
    Jobs = [c.client.GetJobs(bulk=bulk) for c in get_backends(backend)]
612 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Jobs, [])
613 f5b4f2a3 Christos Stavrakakis
614 f5b4f2a3 Christos Stavrakakis
##
615 f5b4f2a3 Christos Stavrakakis
##
616 f5b4f2a3 Christos Stavrakakis
##
617 1a894bfe Christos Stavrakakis
618 1a894bfe Christos Stavrakakis
619 f5b4f2a3 Christos Stavrakakis
def get_backends(backend=None):
620 f5b4f2a3 Christos Stavrakakis
    if backend:
621 f5b4f2a3 Christos Stavrakakis
        return [backend]
622 cc7c0f44 Christos Stavrakakis
    return Backend.objects.filter(offline=False)
623 f5b4f2a3 Christos Stavrakakis
624 17852fe9 Giorgos Verigakis
625 1a894bfe Christos Stavrakakis
def get_physical_resources(backend):
626 1a894bfe Christos Stavrakakis
    """ Get the physical resources of a backend.
627 1a894bfe Christos Stavrakakis

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

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

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

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

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