Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (22.3 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 37ca953f Christodoulos Psaltis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 37ca953f Christodoulos Psaltis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 37ca953f Christodoulos Psaltis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 37ca953f Christodoulos Psaltis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 37ca953f Christodoulos Psaltis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 02feca11 Vassilios Karakoidas
34 2b1db26f Giorgos Verigakis
import json
35 2b1db26f Giorgos Verigakis
36 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 bd392934 Christos Stavrakakis
        net.release_address(nic.ipv4)
175 bd392934 Christos Stavrakakis
        nic.delete()
176 bd392934 Christos Stavrakakis
177 bd392934 Christos Stavrakakis
    return networks
178 bd392934 Christos Stavrakakis
179 bd392934 Christos Stavrakakis
180 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
181 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
182 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
183 22ee6892 Christos Stavrakakis
        return
184 22ee6892 Christos Stavrakakis
        #raise Network.InvalidBackendMsgError(opcode, status)
185 22ee6892 Christos Stavrakakis
186 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
187 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
188 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
189 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
190 22ee6892 Christos Stavrakakis
191 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
192 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
193 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
194 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
195 22ee6892 Christos Stavrakakis
        if opcode == 'OP_NETWORK_REMOVE':
196 22ee6892 Christos Stavrakakis
            back_network.deleted = True
197 22ee6892 Christos Stavrakakis
198 9c65f166 Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_CREATE':
199 22ee6892 Christos Stavrakakis
        utils.update_state(back_network, 'ERROR')
200 22ee6892 Christos Stavrakakis
201 9c65f166 Christos Stavrakakis
    if (status == 'error' and opcode == 'OP_NETWORK_REMOVE'):
202 22ee6892 Christos Stavrakakis
        back_network.deleted = True
203 22ee6892 Christos Stavrakakis
        back_network.operstate = 'DELETED'
204 22ee6892 Christos Stavrakakis
205 22ee6892 Christos Stavrakakis
    back_network.save()
206 ad2d6807 Vangelis Koukis
207 c25cc9ec Vangelis Koukis
208 9068cd85 Georgios Gousios
@transaction.commit_on_success
209 c4e55622 Christos Stavrakakis
def process_create_progress(vm, etime, rprogress, wprogress):
210 9068cd85 Georgios Gousios
211 c25cc9ec Vangelis Koukis
    # XXX: This only uses the read progress for now.
212 c25cc9ec Vangelis Koukis
    #      Explore whether it would make sense to use the value of wprogress
213 c25cc9ec Vangelis Koukis
    #      somewhere.
214 c25cc9ec Vangelis Koukis
    percentage = int(rprogress)
215 9068cd85 Georgios Gousios
216 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
217 af90d919 Vangelis Koukis
    # snf-progress-monitor tracks bytes read by image handling processes
218 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
219 af90d919 Vangelis Koukis
    if percentage < 0:
220 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
221 9068cd85 Georgios Gousios
222 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
223 7ec9558b Vangelis Koukis
#   if last_update > percentage:
224 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
225 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
226 9068cd85 Georgios Gousios
227 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
228 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
229 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
230 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
231 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
232 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
233 c25cc9ec Vangelis Koukis
    #
234 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
235 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
236 9068cd85 Georgios Gousios
237 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
238 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
239 9068cd85 Georgios Gousios
    vm.save()
240 ad2d6807 Vangelis Koukis
241 c25cc9ec Vangelis Koukis
242 22e52ede Vassilios Karakoidas
def start_action(vm, action):
243 22e52ede Vassilios Karakoidas
    """Update the state of a VM when a new action is initiated."""
244 22e52ede Vassilios Karakoidas
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
245 22e52ede Vassilios Karakoidas
        raise VirtualMachine.InvalidActionError(action)
246 22e52ede Vassilios Karakoidas
247 22e52ede Vassilios Karakoidas
    # No actions to deleted and no actions beside destroy to suspended VMs
248 22e52ede Vassilios Karakoidas
    if vm.deleted:
249 5231a38a Giorgos Verigakis
        raise VirtualMachine.DeletedError
250 37ca953f Christodoulos Psaltis
251 30f3b5e5 Vangelis Koukis
    # No actions to machines being built. They may be destroyed, however.
252 30f3b5e5 Vangelis Koukis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
253 5231a38a Giorgos Verigakis
        raise VirtualMachine.BuildingError
254 37ca953f Christodoulos Psaltis
255 dfd19c2d Vassilios Karakoidas
    vm.action = action
256 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = None
257 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = None
258 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = None
259 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = None
260 22e52ede Vassilios Karakoidas
261 f90c3d8c Vangelis Koukis
    # Update the relevant flags if the VM is being suspended or destroyed.
262 f90c3d8c Vangelis Koukis
    # Do not set the deleted flag here, see ticket #721.
263 f90c3d8c Vangelis Koukis
    #
264 f90c3d8c Vangelis Koukis
    # The deleted flag is set asynchronously, when an OP_INSTANCE_REMOVE
265 f90c3d8c Vangelis Koukis
    # completes successfully. Hence, a server may be visible for some time
266 f90c3d8c Vangelis Koukis
    # after a DELETE /servers/id returns HTTP 204.
267 f90c3d8c Vangelis Koukis
    #
268 22e52ede Vassilios Karakoidas
    if action == "DESTROY":
269 f90c3d8c Vangelis Koukis
        # vm.deleted = True
270 f90c3d8c Vangelis Koukis
        pass
271 22e52ede Vassilios Karakoidas
    elif action == "SUSPEND":
272 22e52ede Vassilios Karakoidas
        vm.suspended = True
273 22e52ede Vassilios Karakoidas
    elif action == "START":
274 22e52ede Vassilios Karakoidas
        vm.suspended = False
275 22e52ede Vassilios Karakoidas
    vm.save()
276 529178b1 Giorgos Verigakis
277 ad2d6807 Vangelis Koukis
278 967d3f83 Christos Stavrakakis
@transaction.commit_on_success
279 2b1db26f Giorgos Verigakis
def create_instance(vm, flavor, image, password, personality):
280 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
281 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
282 7f691719 Christos Stavrakakis

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

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

411 22ee6892 Christos Stavrakakis
    """
412 22ee6892 Christos Stavrakakis
    backend_jobs = _create_network(network, backends)
413 22ee6892 Christos Stavrakakis
    connect_network(network, backend_jobs)
414 22ee6892 Christos Stavrakakis
    return network
415 c25cc9ec Vangelis Koukis
416 37ca953f Christodoulos Psaltis
417 22ee6892 Christos Stavrakakis
def _create_network(network, backends=None):
418 22ee6892 Christos Stavrakakis
    """Add a network to backends.
419 22ee6892 Christos Stavrakakis
    @param network: Network object
420 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
421 64938cb0 Giorgos Verigakis

422 22ee6892 Christos Stavrakakis
    """
423 c25cc9ec Vangelis Koukis
424 22ee6892 Christos Stavrakakis
    network_type = network.public and 'public' or 'private'
425 22ee6892 Christos Stavrakakis
426 22ee6892 Christos Stavrakakis
    if not backends:
427 22ee6892 Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
428 22ee6892 Christos Stavrakakis
429 22ee6892 Christos Stavrakakis
    tags = network.backend_tag
430 22ee6892 Christos Stavrakakis
    if network.dhcp:
431 22ee6892 Christos Stavrakakis
        tags.append('nfdhcpd')
432 22ee6892 Christos Stavrakakis
    tags = ','.join(tags)
433 22ee6892 Christos Stavrakakis
434 22ee6892 Christos Stavrakakis
    backend_jobs = []
435 22ee6892 Christos Stavrakakis
    for backend in backends:
436 22ee6892 Christos Stavrakakis
        job = backend.client.CreateNetwork(
437 22ee6892 Christos Stavrakakis
                network_name=network.backend_id,
438 22ee6892 Christos Stavrakakis
                network=network.subnet,
439 22ee6892 Christos Stavrakakis
                gateway=network.gateway,
440 22ee6892 Christos Stavrakakis
                network_type=network_type,
441 22ee6892 Christos Stavrakakis
                mac_prefix=network.mac_prefix,
442 22ee6892 Christos Stavrakakis
                tags=tags)
443 22ee6892 Christos Stavrakakis
        backend_jobs.append((backend, job))
444 22ee6892 Christos Stavrakakis
445 22ee6892 Christos Stavrakakis
    return backend_jobs
446 22ee6892 Christos Stavrakakis
447 22ee6892 Christos Stavrakakis
448 22ee6892 Christos Stavrakakis
def connect_network(network, backend_jobs=None):
449 22ee6892 Christos Stavrakakis
    """Connect a network to all nodegroups.
450 22ee6892 Christos Stavrakakis

451 22ee6892 Christos Stavrakakis
    @param network: Network object
452 22ee6892 Christos Stavrakakis
    @param backend_jobs: List of tuples of the form (Backend, jobs) which are
453 22ee6892 Christos Stavrakakis
                         the backends to connect the network and the jobs on
454 22ee6892 Christos Stavrakakis
                         which the connect job depends.
455 22ee6892 Christos Stavrakakis

456 22ee6892 Christos Stavrakakis
    """
457 64938cb0 Giorgos Verigakis
458 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
459 839e2bd0 Christos Stavrakakis
        mode = 'routed'
460 839e2bd0 Christos Stavrakakis
    else:
461 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
462 c25cc9ec Vangelis Koukis
463 22ee6892 Christos Stavrakakis
    if not backend_jobs:
464 22ee6892 Christos Stavrakakis
        backend_jobs = [(backend, []) for backend in
465 22ee6892 Christos Stavrakakis
                        Backend.objects.exclude(offline=True)]
466 64938cb0 Giorgos Verigakis
467 22ee6892 Christos Stavrakakis
    for backend, job in backend_jobs:
468 22ee6892 Christos Stavrakakis
        client = backend.client
469 22ee6892 Christos Stavrakakis
        for group in client.GetGroups():
470 22ee6892 Christos Stavrakakis
            client.ConnectNetwork(network.backend_id, group, mode,
471 22ee6892 Christos Stavrakakis
                                  network.link, [job])
472 22ee6892 Christos Stavrakakis
473 22ee6892 Christos Stavrakakis
474 22ee6892 Christos Stavrakakis
def connect_network_group(backend, network, group):
475 22ee6892 Christos Stavrakakis
    """Connect a network to a specific nodegroup of a backend.
476 22ee6892 Christos Stavrakakis

477 22ee6892 Christos Stavrakakis
    """
478 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
479 839e2bd0 Christos Stavrakakis
        mode = 'routed'
480 839e2bd0 Christos Stavrakakis
    else:
481 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
482 22ee6892 Christos Stavrakakis
483 22ee6892 Christos Stavrakakis
    return backend.client.ConnectNetwork(network.backend_id, group, mode,
484 22ee6892 Christos Stavrakakis
                                         network.link)
485 22ee6892 Christos Stavrakakis
486 22ee6892 Christos Stavrakakis
487 22ee6892 Christos Stavrakakis
def delete_network(network, backends=None):
488 22ee6892 Christos Stavrakakis
    """ Disconnect and a remove a network from backends.
489 22ee6892 Christos Stavrakakis

490 22ee6892 Christos Stavrakakis
    @param network: Network object
491 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
492 22ee6892 Christos Stavrakakis

493 22ee6892 Christos Stavrakakis
    """
494 22ee6892 Christos Stavrakakis
    backend_jobs = disconnect_network(network, backends)
495 22ee6892 Christos Stavrakakis
    _delete_network(network, backend_jobs)
496 22ee6892 Christos Stavrakakis
497 22ee6892 Christos Stavrakakis
498 22ee6892 Christos Stavrakakis
def disconnect_network(network, backends=None):
499 0196d9a3 Christos Stavrakakis
    """Disconnect a network from all nodegroups.
500 22ee6892 Christos Stavrakakis

501 22ee6892 Christos Stavrakakis
    @param network: Network object
502 22ee6892 Christos Stavrakakis
    @param backends: List of Backend objects. None defaults to all.
503 22ee6892 Christos Stavrakakis

504 22ee6892 Christos Stavrakakis
    """
505 22ee6892 Christos Stavrakakis
506 22ee6892 Christos Stavrakakis
    if not backends:
507 22ee6892 Christos Stavrakakis
        backends = Backend.objects.exclude(offline=True)
508 22ee6892 Christos Stavrakakis
509 22ee6892 Christos Stavrakakis
    backend_jobs = []
510 22ee6892 Christos Stavrakakis
    for backend in backends:
511 22ee6892 Christos Stavrakakis
        client = backend.client
512 22ee6892 Christos Stavrakakis
        jobs = []
513 22ee6892 Christos Stavrakakis
        for group in client.GetGroups():
514 0196d9a3 Christos Stavrakakis
            job = client.DisconnectNetwork(network.backend_id, group)
515 0196d9a3 Christos Stavrakakis
            jobs.append(job)
516 0196d9a3 Christos Stavrakakis
        backend_jobs.append((backend, jobs))
517 22ee6892 Christos Stavrakakis
518 22ee6892 Christos Stavrakakis
    return backend_jobs
519 22ee6892 Christos Stavrakakis
520 22ee6892 Christos Stavrakakis
521 0196d9a3 Christos Stavrakakis
def disconnect_from_network(vm, nic):
522 22ee6892 Christos Stavrakakis
    """Disconnect a virtual machine from a network by removing it's nic.
523 22ee6892 Christos Stavrakakis

524 22ee6892 Christos Stavrakakis
    @param vm: VirtualMachine object
525 22ee6892 Christos Stavrakakis
    @param network: Network object
526 22ee6892 Christos Stavrakakis

527 22ee6892 Christos Stavrakakis
    """
528 c25cc9ec Vangelis Koukis
529 36f4cb29 Christos Stavrakakis
    op = [('remove', nic.index, {})]
530 36f4cb29 Christos Stavrakakis
    return vm.client.ModifyInstance(vm.backend_vm_id, nics=op,
531 36f4cb29 Christos Stavrakakis
                                   hotplug=True, dry_run=settings.TEST)
532 36f4cb29 Christos Stavrakakis
533 36f4cb29 Christos Stavrakakis
534 22ee6892 Christos Stavrakakis
def _delete_network(network, backend_jobs=None):
535 22ee6892 Christos Stavrakakis
    if not backend_jobs:
536 22ee6892 Christos Stavrakakis
        backend_jobs = [(backend, []) for backend in
537 22ee6892 Christos Stavrakakis
                Backend.objects.exclude(offline=True)]
538 22ee6892 Christos Stavrakakis
    for backend, jobs in backend_jobs:
539 22ee6892 Christos Stavrakakis
        backend.client.DeleteNetwork(network.backend_id, jobs)
540 22ee6892 Christos Stavrakakis
541 22ee6892 Christos Stavrakakis
542 77f0fa63 Christos Stavrakakis
def connect_to_network(vm, network, address):
543 22ee6892 Christos Stavrakakis
    """Connect a virtual machine to a network.
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 22ee6892 Christos Stavrakakis
550 77f0fa63 Christos Stavrakakis
    # ip = network.dhcp and 'pool' or None
551 22ee6892 Christos Stavrakakis
552 77f0fa63 Christos Stavrakakis
    nic = {'ip': address, 'network': network.backend_id}
553 22ee6892 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add',  nic)],
554 22ee6892 Christos Stavrakakis
                             hotplug=True, dry_run=settings.TEST)
555 91826390 Giorgos Verigakis
556 c25cc9ec Vangelis Koukis
557 91826390 Giorgos Verigakis
def set_firewall_profile(vm, profile):
558 26563957 Giorgos Verigakis
    try:
559 26563957 Giorgos Verigakis
        tag = _firewall_tags[profile]
560 26563957 Giorgos Verigakis
    except KeyError:
561 91826390 Giorgos Verigakis
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
562 37ca953f Christodoulos Psaltis
563 f5b4f2a3 Christos Stavrakakis
    client = vm.client
564 26563957 Giorgos Verigakis
    # Delete all firewall tags
565 efff6193 Giorgos Verigakis
    for t in _firewall_tags.values():
566 f5b4f2a3 Christos Stavrakakis
        client.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST)
567 37ca953f Christodoulos Psaltis
568 f5b4f2a3 Christos Stavrakakis
    client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
569 9afeb669 Kostas Papadimitriou
570 2da5f785 Giorgos Verigakis
    # XXX NOP ModifyInstance call to force process_net_status to run
571 2da5f785 Giorgos Verigakis
    # on the dispatcher
572 f5b4f2a3 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id,
573 5eedb0e4 Vangelis Koukis
                        os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
574 5eedb0e4 Vangelis Koukis
575 41303ed0 Vangelis Koukis
576 f5b4f2a3 Christos Stavrakakis
def get_ganeti_instances(backend=None, bulk=False):
577 1a894bfe Christos Stavrakakis
    Instances = [c.client.GetInstances(bulk=bulk)\
578 1a894bfe Christos Stavrakakis
                 for c in get_backends(backend)]
579 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Instances, [])
580 f5b4f2a3 Christos Stavrakakis
581 f5b4f2a3 Christos Stavrakakis
582 f5b4f2a3 Christos Stavrakakis
def get_ganeti_nodes(backend=None, bulk=False):
583 f5b4f2a3 Christos Stavrakakis
    Nodes = [c.client.GetNodes(bulk=bulk) for c in get_backends(backend)]
584 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Nodes, [])
585 f5b4f2a3 Christos Stavrakakis
586 f5b4f2a3 Christos Stavrakakis
587 f5b4f2a3 Christos Stavrakakis
def get_ganeti_jobs(backend=None, bulk=False):
588 f5b4f2a3 Christos Stavrakakis
    Jobs = [c.client.GetJobs(bulk=bulk) for c in get_backends(backend)]
589 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Jobs, [])
590 f5b4f2a3 Christos Stavrakakis
591 f5b4f2a3 Christos Stavrakakis
##
592 f5b4f2a3 Christos Stavrakakis
##
593 f5b4f2a3 Christos Stavrakakis
##
594 1a894bfe Christos Stavrakakis
595 1a894bfe Christos Stavrakakis
596 f5b4f2a3 Christos Stavrakakis
def get_backends(backend=None):
597 f5b4f2a3 Christos Stavrakakis
    if backend:
598 f5b4f2a3 Christos Stavrakakis
        return [backend]
599 cc7c0f44 Christos Stavrakakis
    return Backend.objects.filter(offline=False)
600 f5b4f2a3 Christos Stavrakakis
601 17852fe9 Giorgos Verigakis
602 1a894bfe Christos Stavrakakis
def get_physical_resources(backend):
603 1a894bfe Christos Stavrakakis
    """ Get the physical resources of a backend.
604 1a894bfe Christos Stavrakakis

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

607 1a894bfe Christos Stavrakakis
    """
608 1a894bfe Christos Stavrakakis
    nodes = get_ganeti_nodes(backend, bulk=True)
609 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
610 1a894bfe Christos Stavrakakis
    res = {}
611 1a894bfe Christos Stavrakakis
    for a in attr:
612 1a894bfe Christos Stavrakakis
        res[a] = 0
613 1a894bfe Christos Stavrakakis
    for n in nodes:
614 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
615 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
616 1a894bfe Christos Stavrakakis
        if n['vm_capable'] and not n['drained'] and not n['offline']\
617 1a894bfe Christos Stavrakakis
           and n['cnodes']:
618 1a894bfe Christos Stavrakakis
            for a in attr:
619 1a894bfe Christos Stavrakakis
                res[a] += int(n[a])
620 1a894bfe Christos Stavrakakis
    return res
621 1a894bfe Christos Stavrakakis
622 1a894bfe Christos Stavrakakis
623 1a894bfe Christos Stavrakakis
def update_resources(backend, resources=None):
624 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
625 1a894bfe Christos Stavrakakis

626 1a894bfe Christos Stavrakakis
    """
627 17852fe9 Giorgos Verigakis
628 1a894bfe Christos Stavrakakis
    if not resources:
629 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
630 41303ed0 Vangelis Koukis
631 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
632 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
633 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
634 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
635 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
636 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
637 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
638 1a894bfe Christos Stavrakakis
    backend.save()
639 1a894bfe Christos Stavrakakis
640 1a894bfe Christos Stavrakakis
641 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
642 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
643 1a894bfe Christos Stavrakakis

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

647 1a894bfe Christos Stavrakakis
    """
648 1a894bfe Christos Stavrakakis
    instances = backend.client.GetInstances(bulk=True)
649 1a894bfe Christos Stavrakakis
    mem = 0
650 1a894bfe Christos Stavrakakis
    for i in instances:
651 1a894bfe Christos Stavrakakis
        mem += i['oper_ram']
652 1a894bfe Christos Stavrakakis
    return mem
653 b3d28af2 Christos Stavrakakis
654 b3d28af2 Christos Stavrakakis
##
655 b3d28af2 Christos Stavrakakis
## Synchronized operations for reconciliation
656 b3d28af2 Christos Stavrakakis
##
657 b3d28af2 Christos Stavrakakis
658 b3d28af2 Christos Stavrakakis
659 b3d28af2 Christos Stavrakakis
def create_network_synced(network, backend):
660 b3d28af2 Christos Stavrakakis
    result = _create_network_synced(network, backend)
661 b3d28af2 Christos Stavrakakis
    if result[0] != 'success':
662 b3d28af2 Christos Stavrakakis
        return result
663 b3d28af2 Christos Stavrakakis
    result = connect_network_synced(network, backend)
664 b3d28af2 Christos Stavrakakis
    return result
665 b3d28af2 Christos Stavrakakis
666 b3d28af2 Christos Stavrakakis
667 b3d28af2 Christos Stavrakakis
def _create_network_synced(network, backend):
668 b3d28af2 Christos Stavrakakis
    client = backend.client
669 b3d28af2 Christos Stavrakakis
    job = client.CreateNetwork(network.backend_id, network.subnet)
670 b3d28af2 Christos Stavrakakis
    return wait_for_job(client, job)
671 b3d28af2 Christos Stavrakakis
672 b3d28af2 Christos Stavrakakis
673 b3d28af2 Christos Stavrakakis
def connect_network_synced(network, backend):
674 839e2bd0 Christos Stavrakakis
    if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'):
675 839e2bd0 Christos Stavrakakis
        mode = 'routed'
676 839e2bd0 Christos Stavrakakis
    else:
677 839e2bd0 Christos Stavrakakis
        mode = 'bridged'
678 b3d28af2 Christos Stavrakakis
    client = backend.client
679 b3d28af2 Christos Stavrakakis
680 b3d28af2 Christos Stavrakakis
    for group in client.GetGroups():
681 b3d28af2 Christos Stavrakakis
        job = client.ConnectNetwork(network.backend_id, group, mode,
682 b3d28af2 Christos Stavrakakis
                                    network.link)
683 b3d28af2 Christos Stavrakakis
        result = wait_for_job(client, job)
684 b3d28af2 Christos Stavrakakis
        if result[0] != 'success':
685 b3d28af2 Christos Stavrakakis
            return result
686 b3d28af2 Christos Stavrakakis
687 b3d28af2 Christos Stavrakakis
    return result
688 b3d28af2 Christos Stavrakakis
689 b3d28af2 Christos Stavrakakis
690 b3d28af2 Christos Stavrakakis
def wait_for_job(client, jobid):
691 b3d28af2 Christos Stavrakakis
    result = client.WaitForJobChange(jobid, ['status', 'opresult'], None, None)
692 b3d28af2 Christos Stavrakakis
    status = result['job_info'][0]
693 b3d28af2 Christos Stavrakakis
    while status not in ['success', 'error', 'cancel']:
694 b3d28af2 Christos Stavrakakis
        result = client.WaitForJobChange(jobid, ['status', 'opresult'],
695 b3d28af2 Christos Stavrakakis
                                        [result], None)
696 b3d28af2 Christos Stavrakakis
        status = result['job_info'][0]
697 b3d28af2 Christos Stavrakakis
698 b3d28af2 Christos Stavrakakis
    if status == 'success':
699 b3d28af2 Christos Stavrakakis
        return (status, None)
700 b3d28af2 Christos Stavrakakis
    else:
701 b3d28af2 Christos Stavrakakis
        error = result['job_info'][1]
702 b3d28af2 Christos Stavrakakis
        return (status, error)