Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (36.6 kB)

1 41a7fae7 Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 37ca953f Christodoulos Psaltis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 37ca953f Christodoulos Psaltis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 37ca953f Christodoulos Psaltis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 37ca953f Christodoulos Psaltis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 37ca953f Christodoulos Psaltis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 529178b1 Giorgos Verigakis
from django.conf import settings
34 207b70d5 Giorgos Verigakis
from django.db import transaction
35 a1baa42b Christos Stavrakakis
from datetime import datetime, timedelta
36 207b70d5 Giorgos Verigakis
37 22ee6892 Christos Stavrakakis
from synnefo.db.models import (Backend, VirtualMachine, Network,
38 3524241a Christos Stavrakakis
                               BackendNetwork, BACKEND_STATUSES,
39 ca4d59e3 Christos Stavrakakis
                               pooled_rapi_client, VirtualMachineDiagnostic,
40 3278725f Christos Stavrakakis
                               Flavor)
41 03992c72 Christos Stavrakakis
from synnefo.logic import utils
42 cb4eee84 Christos Stavrakakis
from synnefo import quotas
43 3278725f Christos Stavrakakis
from synnefo.api.util import release_resource, allocate_ip
44 fd95834e Christos Stavrakakis
from synnefo.util.mac2eui64 import mac2eui64
45 198d91c3 Christos Stavrakakis
from synnefo.logic.rapi import GanetiApiError
46 529178b1 Giorgos Verigakis
47 3524241a Christos Stavrakakis
from logging import getLogger
48 3524241a Christos Stavrakakis
log = getLogger(__name__)
49 9e98ba3c Giorgos Verigakis
50 529178b1 Giorgos Verigakis
51 efff6193 Giorgos Verigakis
_firewall_tags = {
52 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
53 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
54 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
55 efff6193 Giorgos Verigakis
56 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
57 efff6193 Giorgos Verigakis
58 d7ff7f5a Christos Stavrakakis
# Timeout in seconds for building NICs. After this period the NICs considered
59 d7ff7f5a Christos Stavrakakis
# stale and removed from DB.
60 0d069390 Christos Stavrakakis
BUILDING_NIC_TIMEOUT = timedelta(seconds=180)
61 02feca11 Vassilios Karakoidas
62 3278725f Christos Stavrakakis
SIMPLE_NIC_FIELDS = ["state", "mac", "network", "firewall_profile", "index"]
63 3278725f Christos Stavrakakis
COMPLEX_NIC_FIELDS = ["ipv4_address", "ipv6_address"]
64 3278725f Christos Stavrakakis
NIC_FIELDS = SIMPLE_NIC_FIELDS + COMPLEX_NIC_FIELDS
65 0d069390 Christos Stavrakakis
UNKNOWN_NIC_PREFIX = "unknown-"
66 a1baa42b Christos Stavrakakis
67 a1baa42b Christos Stavrakakis
68 41a7fae7 Christos Stavrakakis
def handle_vm_quotas(vm, job_id, job_opcode, job_status, job_fields):
69 41a7fae7 Christos Stavrakakis
    """Handle quotas for updated VirtualMachine.
70 41a7fae7 Christos Stavrakakis

71 41a7fae7 Christos Stavrakakis
    Update quotas for the updated VirtualMachine based on the job that run on
72 41a7fae7 Christos Stavrakakis
    the Ganeti backend. If a commission has been already issued for this job,
73 41a7fae7 Christos Stavrakakis
    then this commission is just accepted or rejected based on the job status.
74 41a7fae7 Christos Stavrakakis
    Otherwise, a new commission for the given change is issued, that is also in
75 41a7fae7 Christos Stavrakakis
    force and auto-accept mode. In this case, previous commissions are
76 41a7fae7 Christos Stavrakakis
    rejected, since they reflect a previous state of the VM.
77 41a7fae7 Christos Stavrakakis

78 41a7fae7 Christos Stavrakakis
    """
79 41a7fae7 Christos Stavrakakis
    if job_status not in ["success", "error", "canceled"]:
80 88fd91af Christos Stavrakakis
        return vm
81 41a7fae7 Christos Stavrakakis
82 41a7fae7 Christos Stavrakakis
    # Check successful completion of a job will trigger any quotable change in
83 41a7fae7 Christos Stavrakakis
    # the VM state.
84 41a7fae7 Christos Stavrakakis
    action = utils.get_action_from_opcode(job_opcode, job_fields)
85 88fd91af Christos Stavrakakis
    if action == "BUILD":
86 88fd91af Christos Stavrakakis
        # Quotas for new VMs are automatically accepted by the API
87 88fd91af Christos Stavrakakis
        return vm
88 41a7fae7 Christos Stavrakakis
    commission_info = quotas.get_commission_info(vm, action=action,
89 41a7fae7 Christos Stavrakakis
                                                 action_fields=job_fields)
90 41a7fae7 Christos Stavrakakis
91 41a7fae7 Christos Stavrakakis
    if vm.task_job_id == job_id and vm.serial is not None:
92 41a7fae7 Christos Stavrakakis
        # Commission for this change has already been issued. So just
93 562bf712 Christos Stavrakakis
        # accept/reject it. Special case is OP_INSTANCE_CREATE, which even
94 562bf712 Christos Stavrakakis
        # if fails, must be accepted, as the user must manually remove the
95 562bf712 Christos Stavrakakis
        # failed server
96 41a7fae7 Christos Stavrakakis
        serial = vm.serial
97 88fd91af Christos Stavrakakis
        if job_status == "success":
98 41a7fae7 Christos Stavrakakis
            quotas.accept_serial(serial)
99 41a7fae7 Christos Stavrakakis
        elif job_status in ["error", "canceled"]:
100 41a7fae7 Christos Stavrakakis
            log.debug("Job %s failed. Rejecting related serial %s", job_id,
101 41a7fae7 Christos Stavrakakis
                      serial)
102 41a7fae7 Christos Stavrakakis
            quotas.reject_serial(serial)
103 41a7fae7 Christos Stavrakakis
        vm.serial = None
104 41a7fae7 Christos Stavrakakis
    elif job_status == "success" and commission_info is not None:
105 41a7fae7 Christos Stavrakakis
        log.debug("Expected job was %s. Processing job %s. Commission for"
106 41a7fae7 Christos Stavrakakis
                  " this job: %s", vm.task_job_id, job_id, commission_info)
107 41a7fae7 Christos Stavrakakis
        # Commission for this change has not been issued, or the issued
108 41a7fae7 Christos Stavrakakis
        # commission was unaware of the current change. Reject all previous
109 41a7fae7 Christos Stavrakakis
        # commissions and create a new one in forced mode!
110 9122ffab Christos Stavrakakis
        commission_name = ("client: dispatcher, resource: %s, ganeti_job: %s"
111 9122ffab Christos Stavrakakis
                           % (vm, job_id))
112 5c8076b6 Christos Stavrakakis
        quotas.handle_resource_commission(vm, action,
113 5c8076b6 Christos Stavrakakis
                                          commission_info=commission_info,
114 5c8076b6 Christos Stavrakakis
                                          commission_name=commission_name,
115 5c8076b6 Christos Stavrakakis
                                          force=True,
116 5c8076b6 Christos Stavrakakis
                                          auto_accept=True)
117 5c8076b6 Christos Stavrakakis
        log.debug("Issued new commission: %s", vm.serial)
118 41a7fae7 Christos Stavrakakis
119 41a7fae7 Christos Stavrakakis
    return vm
120 41a7fae7 Christos Stavrakakis
121 41a7fae7 Christos Stavrakakis
122 093f9c53 Vangelis Koukis
@transaction.commit_on_success
123 ca4d59e3 Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None,
124 e6fbada1 Christos Stavrakakis
                      job_fields=None):
125 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
126 02feca11 Vassilios Karakoidas

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

131 02feca11 Vassilios Karakoidas
    """
132 41303ed0 Vangelis Koukis
    # See #1492, #1031, #1111 why this line has been removed
133 41303ed0 Vangelis Koukis
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
134 fd65ab41 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
135 02feca11 Vassilios Karakoidas
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
136 02feca11 Vassilios Karakoidas
137 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = jobid
138 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = status
139 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = opcode
140 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = logmsg
141 02feca11 Vassilios Karakoidas
142 41a7fae7 Christos Stavrakakis
    if status in ["queued", "waiting", "running"]:
143 41a7fae7 Christos Stavrakakis
        vm.save()
144 41a7fae7 Christos Stavrakakis
        return
145 41a7fae7 Christos Stavrakakis
146 e6fbada1 Christos Stavrakakis
    if job_fields is None:
147 e6fbada1 Christos Stavrakakis
        job_fields = {}
148 41a7fae7 Christos Stavrakakis
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode)
149 32a0b855 Giorgos Korfiatis
150 02feca11 Vassilios Karakoidas
    # Notifications of success change the operating state
151 41a7fae7 Christos Stavrakakis
    if status == "success":
152 41a7fae7 Christos Stavrakakis
        if state_for_success is not None:
153 41a7fae7 Christos Stavrakakis
            vm.operstate = state_for_success
154 e6fbada1 Christos Stavrakakis
        beparams = job_fields.get("beparams", None)
155 41a7fae7 Christos Stavrakakis
        if beparams:
156 41a7fae7 Christos Stavrakakis
            # Change the flavor of the VM
157 ca4d59e3 Christos Stavrakakis
            _process_resize(vm, beparams)
158 41a7fae7 Christos Stavrakakis
        # Update backendtime only for jobs that have been successfully
159 41a7fae7 Christos Stavrakakis
        # completed, since only these jobs update the state of the VM. Else a
160 41a7fae7 Christos Stavrakakis
        # "race condition" may occur when a successful job (e.g.
161 41a7fae7 Christos Stavrakakis
        # OP_INSTANCE_REMOVE) completes before an error job and messages arrive
162 41a7fae7 Christos Stavrakakis
        # in reversed order.
163 41a7fae7 Christos Stavrakakis
        vm.backendtime = etime
164 ca4d59e3 Christos Stavrakakis
165 90858bda Christos Stavrakakis
    if status in ["success", "error", "canceled"] and nics is not None:
166 90858bda Christos Stavrakakis
        # Update the NICs of the VM
167 90858bda Christos Stavrakakis
        _process_net_status(vm, etime, nics)
168 90858bda Christos Stavrakakis
169 91954b45 Christos Stavrakakis
    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
170 cb4eee84 Christos Stavrakakis
    if opcode == 'OP_INSTANCE_CREATE' and status in ('canceled', 'error'):
171 c4ce868e Christos Stavrakakis
        vm.operstate = 'ERROR'
172 c4ce868e Christos Stavrakakis
        vm.backendtime = etime
173 96feddae Christos Stavrakakis
        # Update state of associated NICs
174 96feddae Christos Stavrakakis
        vm.nics.all().update(state="ERROR")
175 cb4eee84 Christos Stavrakakis
    elif opcode == 'OP_INSTANCE_REMOVE':
176 e97288bc Christos Stavrakakis
        # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
177 e97288bc Christos Stavrakakis
        # when no instance exists at the Ganeti backend.
178 e97288bc Christos Stavrakakis
        # See ticket #799 for all the details.
179 ed2064f8 Christos Stavrakakis
        if status == 'success' or (status == 'error' and
180 198d91c3 Christos Stavrakakis
                                   not vm_exists_in_backend(vm)):
181 a1baa42b Christos Stavrakakis
            # VM has been deleted
182 a1baa42b Christos Stavrakakis
            for nic in vm.nics.all():
183 a1baa42b Christos Stavrakakis
                # Release the IP
184 3278725f Christos Stavrakakis
                remove_nic_ips(nic)
185 a1baa42b Christos Stavrakakis
                # And delete the NIC.
186 a1baa42b Christos Stavrakakis
                nic.delete()
187 e97288bc Christos Stavrakakis
            vm.deleted = True
188 e97288bc Christos Stavrakakis
            vm.operstate = state_for_success
189 e97288bc Christos Stavrakakis
            vm.backendtime = etime
190 41a7fae7 Christos Stavrakakis
            status = "success"
191 41a7fae7 Christos Stavrakakis
192 41a7fae7 Christos Stavrakakis
    if status in ["success", "error", "canceled"]:
193 41a7fae7 Christos Stavrakakis
        # Job is finalized: Handle quotas/commissioning
194 41a7fae7 Christos Stavrakakis
        vm = handle_vm_quotas(vm, job_id=jobid, job_opcode=opcode,
195 3c52a9df Christos Stavrakakis
                              job_status=status, job_fields=job_fields)
196 41a7fae7 Christos Stavrakakis
        # and clear task fields
197 41a7fae7 Christos Stavrakakis
        if vm.task_job_id == jobid:
198 41a7fae7 Christos Stavrakakis
            vm.task = None
199 41a7fae7 Christos Stavrakakis
            vm.task_job_id = None
200 02feca11 Vassilios Karakoidas
201 02feca11 Vassilios Karakoidas
    vm.save()
202 22e52ede Vassilios Karakoidas
203 ad2d6807 Vangelis Koukis
204 ca4d59e3 Christos Stavrakakis
def _process_resize(vm, beparams):
205 ca4d59e3 Christos Stavrakakis
    """Change flavor of a VirtualMachine based on new beparams."""
206 ca4d59e3 Christos Stavrakakis
    old_flavor = vm.flavor
207 41a7fae7 Christos Stavrakakis
    vcpus = beparams.get("vcpus", old_flavor.cpu)
208 41a7fae7 Christos Stavrakakis
    ram = beparams.get("maxmem", old_flavor.ram)
209 41a7fae7 Christos Stavrakakis
    if vcpus == old_flavor.cpu and ram == old_flavor.ram:
210 ca4d59e3 Christos Stavrakakis
        return
211 ca4d59e3 Christos Stavrakakis
    try:
212 ca4d59e3 Christos Stavrakakis
        new_flavor = Flavor.objects.get(cpu=vcpus, ram=ram,
213 ca4d59e3 Christos Stavrakakis
                                        disk=old_flavor.disk,
214 ca4d59e3 Christos Stavrakakis
                                        disk_template=old_flavor.disk_template)
215 ca4d59e3 Christos Stavrakakis
    except Flavor.DoesNotExist:
216 ca4d59e3 Christos Stavrakakis
        raise Exception("Can not find flavor for VM")
217 ca4d59e3 Christos Stavrakakis
    vm.flavor = new_flavor
218 ca4d59e3 Christos Stavrakakis
    vm.save()
219 ca4d59e3 Christos Stavrakakis
220 ca4d59e3 Christos Stavrakakis
221 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
222 c4e55622 Christos Stavrakakis
def process_net_status(vm, etime, nics):
223 fd95834e Christos Stavrakakis
    """Wrap _process_net_status inside transaction."""
224 fd95834e Christos Stavrakakis
    _process_net_status(vm, etime, nics)
225 fd95834e Christos Stavrakakis
226 fd95834e Christos Stavrakakis
227 fd95834e Christos Stavrakakis
def _process_net_status(vm, etime, nics):
228 ad2d6807 Vangelis Koukis
    """Process a net status notification from the backend
229 ad2d6807 Vangelis Koukis

230 ad2d6807 Vangelis Koukis
    Process an incoming message from the Ganeti backend,
231 ad2d6807 Vangelis Koukis
    detailing the NIC configuration of a VM instance.
232 ad2d6807 Vangelis Koukis

233 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
234 37ca953f Christodoulos Psaltis

235 a1baa42b Christos Stavrakakis
    """
236 b578d9e7 Christos Stavrakakis
    ganeti_nics = process_ganeti_nics(nics)
237 3278725f Christos Stavrakakis
    db_nics = dict([(nic.id, nic)
238 3278725f Christos Stavrakakis
                    for nic in vm.nics.prefetch_related("ips__subnet")])
239 40d53b77 Christos Stavrakakis
240 40d53b77 Christos Stavrakakis
    # Get X-Lock on backend before getting X-Lock on network IP pools, to
241 40d53b77 Christos Stavrakakis
    # guarantee that no deadlock will occur with Backend allocator.
242 40d53b77 Christos Stavrakakis
    Backend.objects.select_for_update().get(id=vm.backend_id)
243 b578d9e7 Christos Stavrakakis
244 a1baa42b Christos Stavrakakis
    for nic_name in set(db_nics.keys()) | set(ganeti_nics.keys()):
245 a1baa42b Christos Stavrakakis
        db_nic = db_nics.get(nic_name)
246 a1baa42b Christos Stavrakakis
        ganeti_nic = ganeti_nics.get(nic_name)
247 a1baa42b Christos Stavrakakis
        if ganeti_nic is None:
248 a1baa42b Christos Stavrakakis
            # NIC exists in DB but not in Ganeti. If the NIC is in 'building'
249 a1baa42b Christos Stavrakakis
            # state for more than 5 minutes, then we remove the NIC.
250 a1baa42b Christos Stavrakakis
            # TODO: This is dangerous as the job may be stack in the queue, and
251 a1baa42b Christos Stavrakakis
            # releasing the IP may lead to duplicate IP use.
252 3a6be177 Christos Stavrakakis
            if db_nic.state != "BUILD" or\
253 3a6be177 Christos Stavrakakis
                (db_nic.state == "BUILD" and
254 0d069390 Christos Stavrakakis
                 etime > db_nic.created + BUILDING_NIC_TIMEOUT):
255 3278725f Christos Stavrakakis
                remove_nic_ips(db_nic)
256 0d069390 Christos Stavrakakis
                db_nic.delete()
257 a1baa42b Christos Stavrakakis
            else:
258 0d069390 Christos Stavrakakis
                log.warning("Ignoring recent building NIC: %s", db_nic)
259 a1baa42b Christos Stavrakakis
        elif db_nic is None:
260 3278725f Christos Stavrakakis
            msg = ("NIC/%s of VM %s does not exist in DB! Cannot automatically"
261 3278725f Christos Stavrakakis
                   " fix this issue!" % (nic_name, vm))
262 3278725f Christos Stavrakakis
            log.error(msg)
263 3278725f Christos Stavrakakis
            continue
264 a1baa42b Christos Stavrakakis
        elif not nics_are_equal(db_nic, ganeti_nic):
265 3278725f Christos Stavrakakis
            for f in SIMPLE_NIC_FIELDS:
266 3278725f Christos Stavrakakis
                # Update the NIC in DB with the values from Ganeti NIC
267 3278725f Christos Stavrakakis
                setattr(db_nic, f, ganeti_nic[f])
268 3278725f Christos Stavrakakis
                db_nic.save()
269 a1baa42b Christos Stavrakakis
            # Special case where the IPv4 address has changed, because you
270 a1baa42b Christos Stavrakakis
            # need to release the old IPv4 address and reserve the new one
271 8764d304 Christos Stavrakakis
            ipv4_address = ganeti_nic["ipv4_address"]
272 8764d304 Christos Stavrakakis
            if db_nic.ipv4_address != ipv4_address:
273 3278725f Christos Stavrakakis
                remove_nic_ips(db_nic)
274 8764d304 Christos Stavrakakis
                if ipv4_address:
275 8764d304 Christos Stavrakakis
                    network = ganeti_nic["network"]
276 3278725f Christos Stavrakakis
                    ipaddress = allocate_ip(network, vm.userid,
277 3278725f Christos Stavrakakis
                                            address=ipv4_address)
278 8764d304 Christos Stavrakakis
                    ipaddress.nic = nic
279 8764d304 Christos Stavrakakis
                    ipaddress.save()
280 8764d304 Christos Stavrakakis
281 b578d9e7 Christos Stavrakakis
    vm.backendtime = etime
282 b578d9e7 Christos Stavrakakis
    vm.save()
283 b578d9e7 Christos Stavrakakis
284 b578d9e7 Christos Stavrakakis
285 a1baa42b Christos Stavrakakis
def nics_are_equal(db_nic, gnt_nic):
286 a1baa42b Christos Stavrakakis
    for field in NIC_FIELDS:
287 a1baa42b Christos Stavrakakis
        if getattr(db_nic, field) != gnt_nic[field]:
288 a1baa42b Christos Stavrakakis
            return False
289 a1baa42b Christos Stavrakakis
    return True
290 a1baa42b Christos Stavrakakis
291 a1baa42b Christos Stavrakakis
292 b578d9e7 Christos Stavrakakis
def process_ganeti_nics(ganeti_nics):
293 a1baa42b Christos Stavrakakis
    """Process NIC dict from ganeti"""
294 b578d9e7 Christos Stavrakakis
    new_nics = []
295 a1baa42b Christos Stavrakakis
    for index, gnic in enumerate(ganeti_nics):
296 a1baa42b Christos Stavrakakis
        nic_name = gnic.get("name", None)
297 a1baa42b Christos Stavrakakis
        if nic_name is not None:
298 a1baa42b Christos Stavrakakis
            nic_id = utils.id_from_nic_name(nic_name)
299 a1baa42b Christos Stavrakakis
        else:
300 a1baa42b Christos Stavrakakis
            # Put as default value the index. If it is an unknown NIC to
301 a1baa42b Christos Stavrakakis
            # synnefo it will be created automaticaly.
302 0d069390 Christos Stavrakakis
            nic_id = UNKNOWN_NIC_PREFIX + str(index)
303 a1baa42b Christos Stavrakakis
        network_name = gnic.get('network', '')
304 a1baa42b Christos Stavrakakis
        network_id = utils.id_from_network_name(network_name)
305 a1baa42b Christos Stavrakakis
        network = Network.objects.get(id=network_id)
306 77f0fa63 Christos Stavrakakis
307 77f0fa63 Christos Stavrakakis
        # Get the new nic info
308 a1baa42b Christos Stavrakakis
        mac = gnic.get('mac')
309 a1baa42b Christos Stavrakakis
        ipv4 = gnic.get('ip')
310 8764d304 Christos Stavrakakis
        subnet6 = network.subnet6
311 8764d304 Christos Stavrakakis
        ipv6 = mac2eui64(mac, subnet6) if subnet6 else None
312 8d325d4b Christos Stavrakakis
313 a1baa42b Christos Stavrakakis
        firewall = gnic.get('firewall')
314 8d325d4b Christos Stavrakakis
        firewall_profile = _reverse_tags.get(firewall)
315 a1baa42b Christos Stavrakakis
        if not firewall_profile and network.public:
316 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
317 9afeb669 Kostas Papadimitriou
318 a1baa42b Christos Stavrakakis
        nic_info = {
319 a1baa42b Christos Stavrakakis
            'index': index,
320 a1baa42b Christos Stavrakakis
            'network': network,
321 cc92b70f Christos Stavrakakis
            'mac': mac,
322 8764d304 Christos Stavrakakis
            'ipv4_address': ipv4,
323 8764d304 Christos Stavrakakis
            'ipv6_address': ipv6,
324 939d71dd Christos Stavrakakis
            'firewall_profile': firewall_profile,
325 939d71dd Christos Stavrakakis
            'state': 'ACTIVE'}
326 b578d9e7 Christos Stavrakakis
327 a1baa42b Christos Stavrakakis
        new_nics.append((nic_id, nic_info))
328 a1baa42b Christos Stavrakakis
    return dict(new_nics)
329 a1baa42b Christos Stavrakakis
330 a1baa42b Christos Stavrakakis
331 3278725f Christos Stavrakakis
def remove_nic_ips(nic):
332 3278725f Christos Stavrakakis
    """Remove IP addresses associated with a NetworkInterface.
333 a1baa42b Christos Stavrakakis

334 3278725f Christos Stavrakakis
    Remove all IP addresses that are associated with the NetworkInterface
335 3278725f Christos Stavrakakis
    object, by returning them to the pool and deleting the IPAddress object. If
336 3278725f Christos Stavrakakis
    the IP is a floating IP, then it is just disassociated from the NIC.
337 a1baa42b Christos Stavrakakis

338 a1baa42b Christos Stavrakakis
    """
339 a1baa42b Christos Stavrakakis
340 8764d304 Christos Stavrakakis
    for ip in nic.ips.all():
341 3278725f Christos Stavrakakis
        if ip.ipversion == 4:
342 8764d304 Christos Stavrakakis
            if ip.floating_ip:
343 8764d304 Christos Stavrakakis
                ip.nic = None
344 8764d304 Christos Stavrakakis
                ip.save()
345 8764d304 Christos Stavrakakis
            else:
346 3278725f Christos Stavrakakis
                ip.release_address()
347 3278725f Christos Stavrakakis
        if not ip.floating_ip:
348 8764d304 Christos Stavrakakis
            ip.delete()
349 bd392934 Christos Stavrakakis
350 bd392934 Christos Stavrakakis
351 22ee6892 Christos Stavrakakis
@transaction.commit_on_success
352 22ee6892 Christos Stavrakakis
def process_network_status(back_network, etime, jobid, opcode, status, logmsg):
353 22ee6892 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
354 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
355 22ee6892 Christos Stavrakakis
356 22ee6892 Christos Stavrakakis
    back_network.backendjobid = jobid
357 22ee6892 Christos Stavrakakis
    back_network.backendjobstatus = status
358 22ee6892 Christos Stavrakakis
    back_network.backendopcode = opcode
359 22ee6892 Christos Stavrakakis
    back_network.backendlogmsg = logmsg
360 22ee6892 Christos Stavrakakis
361 05146623 Christos Stavrakakis
    network = back_network.network
362 05146623 Christos Stavrakakis
363 22ee6892 Christos Stavrakakis
    # Notifications of success change the operating state
364 22ee6892 Christos Stavrakakis
    state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None)
365 22ee6892 Christos Stavrakakis
    if status == 'success' and state_for_success is not None:
366 22ee6892 Christos Stavrakakis
        back_network.operstate = state_for_success
367 22ee6892 Christos Stavrakakis
368 e6f6627c Christos Stavrakakis
    if status in ('canceled', 'error') and opcode == 'OP_NETWORK_ADD':
369 5480daec Christos Stavrakakis
        back_network.operstate = 'ERROR'
370 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
371 22ee6892 Christos Stavrakakis
372 e97288bc Christos Stavrakakis
    if opcode == 'OP_NETWORK_REMOVE':
373 198d91c3 Christos Stavrakakis
        network_is_deleted = (status == "success")
374 198d91c3 Christos Stavrakakis
        if network_is_deleted or (status == "error" and not
375 198d91c3 Christos Stavrakakis
                                  network_exists_in_backend(back_network)):
376 e97288bc Christos Stavrakakis
            back_network.operstate = state_for_success
377 e97288bc Christos Stavrakakis
            back_network.deleted = True
378 e97288bc Christos Stavrakakis
            back_network.backendtime = etime
379 22ee6892 Christos Stavrakakis
380 e97288bc Christos Stavrakakis
    if status == 'success':
381 e97288bc Christos Stavrakakis
        back_network.backendtime = etime
382 22ee6892 Christos Stavrakakis
    back_network.save()
383 4d5d0b9c Christos Stavrakakis
    # Also you must update the state of the Network!!
384 05146623 Christos Stavrakakis
    update_network_state(network)
385 fd2bdbb2 Christos Stavrakakis
386 fd2bdbb2 Christos Stavrakakis
387 2509ce17 Christos Stavrakakis
def update_network_state(network):
388 99af08a4 Christos Stavrakakis
    """Update the state of a Network based on BackendNetwork states.
389 cb4eee84 Christos Stavrakakis

390 99af08a4 Christos Stavrakakis
    Update the state of a Network based on the operstate of the networks in the
391 99af08a4 Christos Stavrakakis
    backends that network exists.
392 99af08a4 Christos Stavrakakis

393 99af08a4 Christos Stavrakakis
    The state of the network is:
394 99af08a4 Christos Stavrakakis
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
395 99af08a4 Christos Stavrakakis
    * DELETED: If it is is 'DELETED' in all backends that have been created.
396 99af08a4 Christos Stavrakakis

397 99af08a4 Christos Stavrakakis
    This function also releases the resources (MAC prefix or Bridge) and the
398 99af08a4 Christos Stavrakakis
    quotas for the network.
399 99af08a4 Christos Stavrakakis

400 99af08a4 Christos Stavrakakis
    """
401 99af08a4 Christos Stavrakakis
    if network.deleted:
402 99af08a4 Christos Stavrakakis
        # Network has already been deleted. Just assert that state is also
403 99af08a4 Christos Stavrakakis
        # DELETED
404 99af08a4 Christos Stavrakakis
        if not network.state == "DELETED":
405 99af08a4 Christos Stavrakakis
            network.state = "DELETED"
406 99af08a4 Christos Stavrakakis
            network.save()
407 cb4eee84 Christos Stavrakakis
        return
408 cb4eee84 Christos Stavrakakis
409 99af08a4 Christos Stavrakakis
    backend_states = [s.operstate for s in network.backend_networks.all()]
410 27cda06b Christos Stavrakakis
    if not backend_states and network.action != "DESTROY":
411 99af08a4 Christos Stavrakakis
        if network.state != "ACTIVE":
412 99af08a4 Christos Stavrakakis
            network.state = "ACTIVE"
413 99af08a4 Christos Stavrakakis
            network.save()
414 99af08a4 Christos Stavrakakis
            return
415 99af08a4 Christos Stavrakakis
416 99af08a4 Christos Stavrakakis
    # Network is deleted when all BackendNetworks go to "DELETED" operstate
417 27cda06b Christos Stavrakakis
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
418 27cda06b Christos Stavrakakis
                     "DELETED")
419 99af08a4 Christos Stavrakakis
420 cb4eee84 Christos Stavrakakis
    # Release the resources on the deletion of the Network
421 99af08a4 Christos Stavrakakis
    if deleted:
422 cb4eee84 Christos Stavrakakis
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
423 cb4eee84 Christos Stavrakakis
                 network.id, network.mac_prefix, network.link)
424 cb4eee84 Christos Stavrakakis
        network.deleted = True
425 99af08a4 Christos Stavrakakis
        network.state = "DELETED"
426 b7d38981 Dimitris Aragiorgis
        if network.mac_prefix:
427 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
428 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="mac_prefix",
429 b7d38981 Dimitris Aragiorgis
                                 value=network.mac_prefix)
430 b7d38981 Dimitris Aragiorgis
        if network.link:
431 b7d38981 Dimitris Aragiorgis
            if network.FLAVORS[network.flavor]["link"] == "pool":
432 b7d38981 Dimitris Aragiorgis
                release_resource(res_type="bridge", value=network.link)
433 cb4eee84 Christos Stavrakakis
434 cb4eee84 Christos Stavrakakis
        # Issue commission
435 e18c1749 Christos Stavrakakis
        if network.userid:
436 2509ce17 Christos Stavrakakis
            quotas.issue_and_accept_commission(network, delete=True)
437 32a0b855 Giorgos Korfiatis
            # the above has already saved the object and committed;
438 32a0b855 Giorgos Korfiatis
            # a second save would override others' changes, since the
439 32a0b855 Giorgos Korfiatis
            # object is now unlocked
440 32a0b855 Giorgos Korfiatis
            return
441 e18c1749 Christos Stavrakakis
        elif not network.public:
442 e18c1749 Christos Stavrakakis
            log.warning("Network %s does not have an owner!", network.id)
443 a96e84cf Christos Stavrakakis
444 a96e84cf Christos Stavrakakis
        # TODO!!!!!
445 a96e84cf Christos Stavrakakis
        # Set all subnets as deleted
446 a96e84cf Christos Stavrakakis
        network.subnets.update(deleted=True)
447 a96e84cf Christos Stavrakakis
        # And delete the IP pools
448 a96e84cf Christos Stavrakakis
        network.subnets.ip_pools.all().delete()
449 cb4eee84 Christos Stavrakakis
    network.save()
450 cb4eee84 Christos Stavrakakis
451 cb4eee84 Christos Stavrakakis
452 fd2bdbb2 Christos Stavrakakis
@transaction.commit_on_success
453 fd2bdbb2 Christos Stavrakakis
def process_network_modify(back_network, etime, jobid, opcode, status,
454 e6fbada1 Christos Stavrakakis
                           job_fields):
455 fd2bdbb2 Christos Stavrakakis
    assert (opcode == "OP_NETWORK_SET_PARAMS")
456 fd2bdbb2 Christos Stavrakakis
    if status not in [x[0] for x in BACKEND_STATUSES]:
457 fd2bdbb2 Christos Stavrakakis
        raise Network.InvalidBackendMsgError(opcode, status)
458 fd2bdbb2 Christos Stavrakakis
459 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobid = jobid
460 fd2bdbb2 Christos Stavrakakis
    back_network.backendjobstatus = status
461 fd2bdbb2 Christos Stavrakakis
    back_network.opcode = opcode
462 fd2bdbb2 Christos Stavrakakis
463 e6fbada1 Christos Stavrakakis
    add_reserved_ips = job_fields.get("add_reserved_ips")
464 fc56ae0f Christos Stavrakakis
    if add_reserved_ips:
465 3278725f Christos Stavrakakis
        network = back_network.network
466 3278725f Christos Stavrakakis
        for ip in add_reserved_ips:
467 3278725f Christos Stavrakakis
            network.reserve_address(ip, external=True)
468 fd2bdbb2 Christos Stavrakakis
469 fd2bdbb2 Christos Stavrakakis
    if status == 'success':
470 fd2bdbb2 Christos Stavrakakis
        back_network.backendtime = etime
471 fd2bdbb2 Christos Stavrakakis
    back_network.save()
472 ad2d6807 Vangelis Koukis
473 c25cc9ec Vangelis Koukis
474 9068cd85 Georgios Gousios
@transaction.commit_on_success
475 0827883e Nikos Skalkotos
def process_create_progress(vm, etime, progress):
476 9068cd85 Georgios Gousios
477 0827883e Nikos Skalkotos
    percentage = int(progress)
478 9068cd85 Georgios Gousios
479 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
480 0827883e Nikos Skalkotos
    # snf-image:copy-progress tracks bytes read by image handling processes
481 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
482 af90d919 Vangelis Koukis
    if percentage < 0:
483 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
484 9068cd85 Georgios Gousios
485 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
486 7ec9558b Vangelis Koukis
#   if last_update > percentage:
487 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
488 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
489 9068cd85 Georgios Gousios
490 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
491 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
492 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
493 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
494 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
495 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
496 c25cc9ec Vangelis Koukis
    #
497 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
498 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
499 9068cd85 Georgios Gousios
500 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
501 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
502 9068cd85 Georgios Gousios
    vm.save()
503 ad2d6807 Vangelis Koukis
504 c25cc9ec Vangelis Koukis
505 952b2a48 Christos Stavrakakis
@transaction.commit_on_success
506 7d43565f Kostas Papadimitriou
def create_instance_diagnostic(vm, message, source, level="DEBUG", etime=None,
507 cc92b70f Christos Stavrakakis
                               details=None):
508 7d43565f Kostas Papadimitriou
    """
509 7d43565f Kostas Papadimitriou
    Create virtual machine instance diagnostic entry.
510 7d43565f Kostas Papadimitriou

511 7d43565f Kostas Papadimitriou
    :param vm: VirtualMachine instance to create diagnostic for.
512 7d43565f Kostas Papadimitriou
    :param message: Diagnostic message.
513 7d43565f Kostas Papadimitriou
    :param source: Diagnostic source identifier (e.g. image-helper).
514 7d43565f Kostas Papadimitriou
    :param level: Diagnostic level (`DEBUG`, `INFO`, `WARNING`, `ERROR`).
515 7d43565f Kostas Papadimitriou
    :param etime: The time the message occured (if available).
516 7d43565f Kostas Papadimitriou
    :param details: Additional details or debug information.
517 7d43565f Kostas Papadimitriou
    """
518 7d43565f Kostas Papadimitriou
    VirtualMachineDiagnostic.objects.create_for_vm(vm, level, source=source,
519 cc92b70f Christos Stavrakakis
                                                   source_date=etime,
520 cc92b70f Christos Stavrakakis
                                                   message=message,
521 cc92b70f Christos Stavrakakis
                                                   details=details)
522 7d43565f Kostas Papadimitriou
523 7d43565f Kostas Papadimitriou
524 2c022086 Christos Stavrakakis
def create_instance(vm, nics, flavor, image):
525 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
526 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
527 7f691719 Christos Stavrakakis

528 3a9b3cde Giorgos Verigakis
        metadata value should be a dictionary.
529 3a9b3cde Giorgos Verigakis
    """
530 864bed43 Christos Stavrakakis
531 1c382247 Vangelis Koukis
    # Handle arguments to CreateInstance() as a dictionary,
532 1c382247 Vangelis Koukis
    # initialize it based on a deployment-specific value.
533 1c382247 Vangelis Koukis
    # This enables the administrator to override deployment-specific
534 c25cc9ec Vangelis Koukis
    # arguments, such as the disk template to use, name of os provider
535 1c382247 Vangelis Koukis
    # and hypervisor-specific parameters at will (see Synnefo #785, #835).
536 1c382247 Vangelis Koukis
    #
537 bd87213f Christos Stavrakakis
    kw = vm.backend.get_create_params()
538 1c382247 Vangelis Koukis
    kw['mode'] = 'create'
539 924d8085 Christos Stavrakakis
    kw['name'] = vm.backend_vm_id
540 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
541 296682fe Kostas Papadimitriou
542 2a599282 Christos Stavrakakis
    kw['disk_template'] = flavor.disk_template
543 d7841399 Christos Stavrakakis
    kw['disks'] = [{"size": flavor.disk * 1024}]
544 006c6249 Christos Stavrakakis
    provider = flavor.disk_provider
545 296682fe Kostas Papadimitriou
    if provider:
546 296682fe Kostas Papadimitriou
        kw['disks'][0]['provider'] = provider
547 b2222a7f Christos Stavrakakis
        kw['disks'][0]['origin'] = flavor.disk_origin
548 296682fe Kostas Papadimitriou
549 7c714455 Christos Stavrakakis
    kw['nics'] = [{"name": nic.backend_uuid,
550 7c714455 Christos Stavrakakis
                   "network": nic.network.backend_id,
551 92d2d1ce Christos Stavrakakis
                   "ip": nic.ipv4_address}
552 cb66110b Christos Stavrakakis
                  for nic in nics]
553 cb66110b Christos Stavrakakis
    backend = vm.backend
554 cb66110b Christos Stavrakakis
    depend_jobs = []
555 cb66110b Christos Stavrakakis
    for nic in nics:
556 92d2d1ce Christos Stavrakakis
        network = Network.objects.select_for_update().get(id=nic.network_id)
557 cb66110b Christos Stavrakakis
        bnet, created = BackendNetwork.objects.get_or_create(backend=backend,
558 cb66110b Christos Stavrakakis
                                                             network=network)
559 cb66110b Christos Stavrakakis
        if bnet.operstate != "ACTIVE":
560 437e1eee Christos Stavrakakis
            depend_jobs = create_network(network, backend, connect=True)
561 cb66110b Christos Stavrakakis
    kw["depends"] = [[job, ["success", "error", "canceled"]]
562 cb66110b Christos Stavrakakis
                     for job in depend_jobs]
563 cb66110b Christos Stavrakakis
564 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
565 1c382247 Vangelis Koukis
    # kw['os'] = settings.GANETI_OS_PROVIDER
566 1c382247 Vangelis Koukis
    kw['ip_check'] = False
567 1c382247 Vangelis Koukis
    kw['name_check'] = False
568 79b7dbb7 Christos Stavrakakis
569 1c382247 Vangelis Koukis
    # Do not specific a node explicitly, have
570 1c382247 Vangelis Koukis
    # Ganeti use an iallocator instead
571 f8d1eaf4 Kostas Papadimitriou
    #kw['pnode'] = rapi.GetNodes()[0]
572 79b7dbb7 Christos Stavrakakis
573 1c382247 Vangelis Koukis
    kw['dry_run'] = settings.TEST
574 41303ed0 Vangelis Koukis
575 2b1db26f Giorgos Verigakis
    kw['beparams'] = {
576 cc92b70f Christos Stavrakakis
        'auto_balance': True,
577 cc92b70f Christos Stavrakakis
        'vcpus': flavor.cpu,
578 cc92b70f Christos Stavrakakis
        'memory': flavor.ram}
579 79b7dbb7 Christos Stavrakakis
580 e3b5be49 Giorgos Verigakis
    kw['osparams'] = {
581 79b7dbb7 Christos Stavrakakis
        'config_url': vm.config_url,
582 79b7dbb7 Christos Stavrakakis
        # Store image id and format to Ganeti
583 2a599282 Christos Stavrakakis
        'img_id': image['backend_id'],
584 3a9b3cde Giorgos Verigakis
        'img_format': image['format']}
585 d1eaa651 Christos Stavrakakis
586 e9d59f5e Christos Stavrakakis
    # Use opportunistic locking
587 e9d59f5e Christos Stavrakakis
    kw['opportunistic_locking'] = True
588 e9d59f5e Christos Stavrakakis
589 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
590 1c382247 Vangelis Koukis
    # kw['hvparams'] = dict(serial_console=False)
591 79b7dbb7 Christos Stavrakakis
592 6afeb85d Christos Stavrakakis
    log.debug("Creating instance %s", utils.hide_pass(kw))
593 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
594 3524241a Christos Stavrakakis
        return client.CreateInstance(**kw)
595 f533f224 Vangelis Koukis
596 529178b1 Giorgos Verigakis
597 529178b1 Giorgos Verigakis
def delete_instance(vm):
598 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
599 3524241a Christos Stavrakakis
        return client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
600 529178b1 Giorgos Verigakis
601 ad2d6807 Vangelis Koukis
602 529178b1 Giorgos Verigakis
def reboot_instance(vm, reboot_type):
603 529178b1 Giorgos Verigakis
    assert reboot_type in ('soft', 'hard')
604 bbae3e45 Christos Stavrakakis
    kwargs = {"instance": vm.backend_vm_id,
605 bbae3e45 Christos Stavrakakis
              "reboot_type": "hard"}
606 bbae3e45 Christos Stavrakakis
    # XXX: Currently shutdown_timeout parameter is not supported from the
607 bbae3e45 Christos Stavrakakis
    # Ganeti RAPI. Until supported, we will fallback for both reboot types
608 bbae3e45 Christos Stavrakakis
    # to the default shutdown timeout of Ganeti (120s). Note that reboot
609 bbae3e45 Christos Stavrakakis
    # type of Ganeti job must be always hard. The 'soft' and 'hard' type
610 bbae3e45 Christos Stavrakakis
    # of OS API is different from the one in Ganeti, and maps to
611 bbae3e45 Christos Stavrakakis
    # 'shutdown_timeout'.
612 bbae3e45 Christos Stavrakakis
    #if reboot_type == "hard":
613 bbae3e45 Christos Stavrakakis
    #    kwargs["shutdown_timeout"] = 0
614 bbae3e45 Christos Stavrakakis
    if settings.TEST:
615 bbae3e45 Christos Stavrakakis
        kwargs["dry_run"] = True
616 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
617 bbae3e45 Christos Stavrakakis
        return client.RebootInstance(**kwargs)
618 529178b1 Giorgos Verigakis
619 ad2d6807 Vangelis Koukis
620 529178b1 Giorgos Verigakis
def startup_instance(vm):
621 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
622 3524241a Christos Stavrakakis
        return client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
623 529178b1 Giorgos Verigakis
624 ad2d6807 Vangelis Koukis
625 529178b1 Giorgos Verigakis
def shutdown_instance(vm):
626 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
627 3524241a Christos Stavrakakis
        return client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
628 529178b1 Giorgos Verigakis
629 ad2d6807 Vangelis Koukis
630 2cd3f389 Christos Stavrakakis
def resize_instance(vm, vcpus, memory):
631 2cd3f389 Christos Stavrakakis
    beparams = {"vcpus": int(vcpus),
632 2cd3f389 Christos Stavrakakis
                "minmem": int(memory),
633 2cd3f389 Christos Stavrakakis
                "maxmem": int(memory)}
634 2cd3f389 Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
635 2cd3f389 Christos Stavrakakis
        return client.ModifyInstance(vm.backend_vm_id, beparams=beparams)
636 2cd3f389 Christos Stavrakakis
637 2cd3f389 Christos Stavrakakis
638 529178b1 Giorgos Verigakis
def get_instance_console(vm):
639 71099804 Vangelis Koukis
    # RAPI GetInstanceConsole() returns endpoints to the vnc_bind_address,
640 71099804 Vangelis Koukis
    # which is a cluster-wide setting, either 0.0.0.0 or 127.0.0.1, and pretty
641 71099804 Vangelis Koukis
    # useless (see #783).
642 71099804 Vangelis Koukis
    #
643 71099804 Vangelis Koukis
    # Until this is fixed on the Ganeti side, construct a console info reply
644 71099804 Vangelis Koukis
    # directly.
645 9afeb669 Kostas Papadimitriou
    #
646 71099804 Vangelis Koukis
    # WARNING: This assumes that VNC runs on port network_port on
647 71099804 Vangelis Koukis
    #          the instance's primary node, and is probably
648 71099804 Vangelis Koukis
    #          hypervisor-specific.
649 71099804 Vangelis Koukis
    #
650 bf5c82dc Christos Stavrakakis
    log.debug("Getting console for vm %s", vm)
651 bf5c82dc Christos Stavrakakis
652 71099804 Vangelis Koukis
    console = {}
653 71099804 Vangelis Koukis
    console['kind'] = 'vnc'
654 3524241a Christos Stavrakakis
655 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
656 3524241a Christos Stavrakakis
        i = client.GetInstance(vm.backend_vm_id)
657 3524241a Christos Stavrakakis
658 bd87213f Christos Stavrakakis
    if vm.backend.hypervisor == "kvm" and i['hvparams']['serial_console']:
659 71099804 Vangelis Koukis
        raise Exception("hv parameter serial_console cannot be true")
660 71099804 Vangelis Koukis
    console['host'] = i['pnode']
661 71099804 Vangelis Koukis
    console['port'] = i['network_port']
662 9afeb669 Kostas Papadimitriou
663 71099804 Vangelis Koukis
    return console
664 604b2bf8 Georgios Gousios
665 604b2bf8 Georgios Gousios
666 3524241a Christos Stavrakakis
def get_instance_info(vm):
667 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
668 198d91c3 Christos Stavrakakis
        return client.GetInstance(vm.backend_vm_id)
669 198d91c3 Christos Stavrakakis
670 198d91c3 Christos Stavrakakis
671 198d91c3 Christos Stavrakakis
def vm_exists_in_backend(vm):
672 198d91c3 Christos Stavrakakis
    try:
673 198d91c3 Christos Stavrakakis
        get_instance_info(vm)
674 198d91c3 Christos Stavrakakis
        return True
675 198d91c3 Christos Stavrakakis
    except GanetiApiError as e:
676 198d91c3 Christos Stavrakakis
        if e.code == 404:
677 198d91c3 Christos Stavrakakis
            return False
678 198d91c3 Christos Stavrakakis
        raise e
679 198d91c3 Christos Stavrakakis
680 198d91c3 Christos Stavrakakis
681 198d91c3 Christos Stavrakakis
def get_network_info(backend_network):
682 198d91c3 Christos Stavrakakis
    with pooled_rapi_client(backend_network) as client:
683 198d91c3 Christos Stavrakakis
        return client.GetNetwork(backend_network.network.backend_id)
684 198d91c3 Christos Stavrakakis
685 198d91c3 Christos Stavrakakis
686 198d91c3 Christos Stavrakakis
def network_exists_in_backend(backend_network):
687 198d91c3 Christos Stavrakakis
    try:
688 198d91c3 Christos Stavrakakis
        get_network_info(backend_network)
689 198d91c3 Christos Stavrakakis
        return True
690 198d91c3 Christos Stavrakakis
    except GanetiApiError as e:
691 198d91c3 Christos Stavrakakis
        if e.code == 404:
692 198d91c3 Christos Stavrakakis
            return False
693 f533f224 Vangelis Koukis
694 c25cc9ec Vangelis Koukis
695 99af08a4 Christos Stavrakakis
def create_network(network, backend, connect=True):
696 99af08a4 Christos Stavrakakis
    """Create a network in a Ganeti backend"""
697 99af08a4 Christos Stavrakakis
    log.debug("Creating network %s in backend %s", network, backend)
698 64938cb0 Giorgos Verigakis
699 99af08a4 Christos Stavrakakis
    job_id = _create_network(network, backend)
700 c25cc9ec Vangelis Koukis
701 99af08a4 Christos Stavrakakis
    if connect:
702 99af08a4 Christos Stavrakakis
        job_ids = connect_network(network, backend, depends=[job_id])
703 99af08a4 Christos Stavrakakis
        return job_ids
704 99af08a4 Christos Stavrakakis
    else:
705 99af08a4 Christos Stavrakakis
        return [job_id]
706 37ca953f Christodoulos Psaltis
707 64938cb0 Giorgos Verigakis
708 3524241a Christos Stavrakakis
def _create_network(network, backend):
709 3524241a Christos Stavrakakis
    """Create a network."""
710 c25cc9ec Vangelis Koukis
711 22ee6892 Christos Stavrakakis
    tags = network.backend_tag
712 92d2d1ce Christos Stavrakakis
    subnet = None
713 92d2d1ce Christos Stavrakakis
    subnet6 = None
714 92d2d1ce Christos Stavrakakis
    gateway = None
715 92d2d1ce Christos Stavrakakis
    gateway6 = None
716 3278725f Christos Stavrakakis
    for _subnet in network.subnets.all():
717 3278725f Christos Stavrakakis
        if _subnet.ipversion == 4:
718 3278725f Christos Stavrakakis
            if _subnet.dhcp:
719 92d2d1ce Christos Stavrakakis
                tags.append('nfdhcpd')
720 fe3b2809 Christos Stavrakakis
            subnet = _subnet.cidr
721 fe3b2809 Christos Stavrakakis
            gateway = _subnet.gateway
722 3278725f Christos Stavrakakis
        elif _subnet.ipversion == 6:
723 fe3b2809 Christos Stavrakakis
            subnet6 = _subnet.cidr
724 fe3b2809 Christos Stavrakakis
            gateway6 = _subnet.gateway
725 2d762302 Dimitris Aragiorgis
726 2d762302 Dimitris Aragiorgis
    if network.public:
727 2d762302 Dimitris Aragiorgis
        conflicts_check = True
728 700b85be Dimitris Aragiorgis
        tags.append('public')
729 2d762302 Dimitris Aragiorgis
    else:
730 2d762302 Dimitris Aragiorgis
        conflicts_check = False
731 700b85be Dimitris Aragiorgis
        tags.append('private')
732 22ee6892 Christos Stavrakakis
733 5aeb4e93 Christos Stavrakakis
    # Use a dummy network subnet for IPv6 only networks. Currently Ganeti does
734 5aeb4e93 Christos Stavrakakis
    # not support IPv6 only networks. To bypass this limitation, we create the
735 5aeb4e93 Christos Stavrakakis
    # network with a dummy network subnet, and make Cyclades connect instances
736 5aeb4e93 Christos Stavrakakis
    # to such networks, with address=None.
737 5aeb4e93 Christos Stavrakakis
    if subnet is None:
738 5aeb4e93 Christos Stavrakakis
        subnet = "10.0.0.0/24"
739 5aeb4e93 Christos Stavrakakis
740 3524241a Christos Stavrakakis
    try:
741 3524241a Christos Stavrakakis
        bn = BackendNetwork.objects.get(network=network, backend=backend)
742 3524241a Christos Stavrakakis
        mac_prefix = bn.mac_prefix
743 3524241a Christos Stavrakakis
    except BackendNetwork.DoesNotExist:
744 cc92b70f Christos Stavrakakis
        raise Exception("BackendNetwork for network '%s' in backend '%s'"
745 3524241a Christos Stavrakakis
                        " does not exist" % (network.id, backend.id))
746 3524241a Christos Stavrakakis
747 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
748 3524241a Christos Stavrakakis
        return client.CreateNetwork(network_name=network.backend_id,
749 5aeb4e93 Christos Stavrakakis
                                    network=subnet,
750 92d2d1ce Christos Stavrakakis
                                    network6=subnet6,
751 92d2d1ce Christos Stavrakakis
                                    gateway=gateway,
752 92d2d1ce Christos Stavrakakis
                                    gateway6=gateway6,
753 3524241a Christos Stavrakakis
                                    mac_prefix=mac_prefix,
754 2d762302 Dimitris Aragiorgis
                                    conflicts_check=conflicts_check,
755 3524241a Christos Stavrakakis
                                    tags=tags)
756 3524241a Christos Stavrakakis
757 3524241a Christos Stavrakakis
758 99af08a4 Christos Stavrakakis
def connect_network(network, backend, depends=[], group=None):
759 3524241a Christos Stavrakakis
    """Connect a network to nodegroups."""
760 bf5c82dc Christos Stavrakakis
    log.debug("Connecting network %s to backend %s", network, backend)
761 bf5c82dc Christos Stavrakakis
762 2d762302 Dimitris Aragiorgis
    if network.public:
763 2d762302 Dimitris Aragiorgis
        conflicts_check = True
764 2d762302 Dimitris Aragiorgis
    else:
765 2d762302 Dimitris Aragiorgis
        conflicts_check = False
766 2d762302 Dimitris Aragiorgis
767 99af08a4 Christos Stavrakakis
    depends = [[job, ["success", "error", "canceled"]] for job in depends]
768 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
769 99af08a4 Christos Stavrakakis
        groups = [group] if group is not None else client.GetGroups()
770 99af08a4 Christos Stavrakakis
        job_ids = []
771 99af08a4 Christos Stavrakakis
        for group in groups:
772 99af08a4 Christos Stavrakakis
            job_id = client.ConnectNetwork(network.backend_id, group,
773 99af08a4 Christos Stavrakakis
                                           network.mode, network.link,
774 99af08a4 Christos Stavrakakis
                                           conflicts_check,
775 99af08a4 Christos Stavrakakis
                                           depends=depends)
776 99af08a4 Christos Stavrakakis
            job_ids.append(job_id)
777 99af08a4 Christos Stavrakakis
    return job_ids
778 22ee6892 Christos Stavrakakis
779 22ee6892 Christos Stavrakakis
780 99af08a4 Christos Stavrakakis
def delete_network(network, backend, disconnect=True):
781 99af08a4 Christos Stavrakakis
    log.debug("Deleting network %s from backend %s", network, backend)
782 22ee6892 Christos Stavrakakis
783 99af08a4 Christos Stavrakakis
    depends = []
784 99af08a4 Christos Stavrakakis
    if disconnect:
785 99af08a4 Christos Stavrakakis
        depends = disconnect_network(network, backend)
786 99af08a4 Christos Stavrakakis
    _delete_network(network, backend, depends=depends)
787 bf5c82dc Christos Stavrakakis
788 22ee6892 Christos Stavrakakis
789 99af08a4 Christos Stavrakakis
def _delete_network(network, backend, depends=[]):
790 99af08a4 Christos Stavrakakis
    depends = [[job, ["success", "error", "canceled"]] for job in depends]
791 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
792 99af08a4 Christos Stavrakakis
        return client.DeleteNetwork(network.backend_id, depends)
793 22ee6892 Christos Stavrakakis
794 22ee6892 Christos Stavrakakis
795 3524241a Christos Stavrakakis
def disconnect_network(network, backend, group=None):
796 bf5c82dc Christos Stavrakakis
    log.debug("Disconnecting network %s to backend %s", network, backend)
797 22ee6892 Christos Stavrakakis
798 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
799 99af08a4 Christos Stavrakakis
        groups = [group] if group is not None else client.GetGroups()
800 99af08a4 Christos Stavrakakis
        job_ids = []
801 99af08a4 Christos Stavrakakis
        for group in groups:
802 99af08a4 Christos Stavrakakis
            job_id = client.DisconnectNetwork(network.backend_id, group)
803 99af08a4 Christos Stavrakakis
            job_ids.append(job_id)
804 99af08a4 Christos Stavrakakis
    return job_ids
805 36f4cb29 Christos Stavrakakis
806 36f4cb29 Christos Stavrakakis
807 2a2b01e5 Christos Stavrakakis
def connect_to_network(vm, nic):
808 2a2b01e5 Christos Stavrakakis
    network = nic.network
809 99af08a4 Christos Stavrakakis
    backend = vm.backend
810 acfc71ef Christos Stavrakakis
    network = Network.objects.select_for_update().get(id=network.id)
811 99af08a4 Christos Stavrakakis
    bnet, created = BackendNetwork.objects.get_or_create(backend=backend,
812 99af08a4 Christos Stavrakakis
                                                         network=network)
813 99af08a4 Christos Stavrakakis
    depend_jobs = []
814 99af08a4 Christos Stavrakakis
    if bnet.operstate != "ACTIVE":
815 99af08a4 Christos Stavrakakis
        depend_jobs = create_network(network, backend, connect=True)
816 99af08a4 Christos Stavrakakis
817 99af08a4 Christos Stavrakakis
    depends = [[job, ["success", "error", "canceled"]] for job in depend_jobs]
818 99af08a4 Christos Stavrakakis
819 7c714455 Christos Stavrakakis
    nic = {'name': nic.backend_uuid,
820 7c714455 Christos Stavrakakis
           'network': network.backend_id,
821 8764d304 Christos Stavrakakis
           'ip': nic.ipv4_address}
822 22ee6892 Christos Stavrakakis
823 7c714455 Christos Stavrakakis
    log.debug("Adding NIC %s to VM %s", nic, vm)
824 22ee6892 Christos Stavrakakis
825 6488097c Christos Stavrakakis
    kwargs = {
826 6488097c Christos Stavrakakis
        "instance": vm.backend_vm_id,
827 1d74f135 Dimitris Aragiorgis
        "nics": [("add", "-1", nic)],
828 6488097c Christos Stavrakakis
        "depends": depends,
829 6488097c Christos Stavrakakis
    }
830 6488097c Christos Stavrakakis
    if vm.backend.use_hotplug():
831 6488097c Christos Stavrakakis
        kwargs["hotplug"] = True
832 6488097c Christos Stavrakakis
    if settings.TEST:
833 6488097c Christos Stavrakakis
        kwargs["dry_run"] = True
834 6488097c Christos Stavrakakis
835 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
836 6488097c Christos Stavrakakis
        return client.ModifyInstance(**kwargs)
837 22ee6892 Christos Stavrakakis
838 22ee6892 Christos Stavrakakis
839 3524241a Christos Stavrakakis
def disconnect_from_network(vm, nic):
840 7c714455 Christos Stavrakakis
    log.debug("Removing NIC %s of VM %s", nic, vm)
841 22ee6892 Christos Stavrakakis
842 6488097c Christos Stavrakakis
    kwargs = {
843 6488097c Christos Stavrakakis
        "instance": vm.backend_vm_id,
844 cd7ed999 Christos Stavrakakis
        "nics": [("remove", nic.backend_uuid, {})],
845 6488097c Christos Stavrakakis
    }
846 6488097c Christos Stavrakakis
    if vm.backend.use_hotplug():
847 6488097c Christos Stavrakakis
        kwargs["hotplug"] = True
848 6488097c Christos Stavrakakis
    if settings.TEST:
849 6488097c Christos Stavrakakis
        kwargs["dry_run"] = True
850 6488097c Christos Stavrakakis
851 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
852 6488097c Christos Stavrakakis
        jobID = client.ModifyInstance(**kwargs)
853 27435d42 Christos Stavrakakis
        firewall_profile = nic.firewall_profile
854 231b0fb6 Christos Stavrakakis
        if firewall_profile and firewall_profile != "DISABLED":
855 d0545590 Christos Stavrakakis
            tag = _firewall_tags[firewall_profile] % nic.backend_uuid
856 27435d42 Christos Stavrakakis
            client.DeleteInstanceTags(vm.backend_vm_id, [tag],
857 27435d42 Christos Stavrakakis
                                      dry_run=settings.TEST)
858 27435d42 Christos Stavrakakis
859 27435d42 Christos Stavrakakis
        return jobID
860 91826390 Giorgos Verigakis
861 c25cc9ec Vangelis Koukis
862 d0545590 Christos Stavrakakis
def set_firewall_profile(vm, profile, nic):
863 d0545590 Christos Stavrakakis
    uuid = nic.backend_uuid
864 26563957 Giorgos Verigakis
    try:
865 d0545590 Christos Stavrakakis
        tag = _firewall_tags[profile] % uuid
866 26563957 Giorgos Verigakis
    except KeyError:
867 91826390 Giorgos Verigakis
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
868 37ca953f Christodoulos Psaltis
869 d0545590 Christos Stavrakakis
    log.debug("Setting tag of VM %s, NIC %s, to %s", vm, nic, profile)
870 bf5c82dc Christos Stavrakakis
871 3524241a Christos Stavrakakis
    with pooled_rapi_client(vm) as client:
872 b2791a77 Christos Stavrakakis
        # Delete previous firewall tags
873 b2791a77 Christos Stavrakakis
        old_tags = client.GetInstanceTags(vm.backend_vm_id)
874 d0545590 Christos Stavrakakis
        delete_tags = [(t % uuid) for t in _firewall_tags.values()
875 d0545590 Christos Stavrakakis
                       if (t % uuid) in old_tags]
876 b2791a77 Christos Stavrakakis
        if delete_tags:
877 b2791a77 Christos Stavrakakis
            client.DeleteInstanceTags(vm.backend_vm_id, delete_tags,
878 3524241a Christos Stavrakakis
                                      dry_run=settings.TEST)
879 37ca953f Christodoulos Psaltis
880 27435d42 Christos Stavrakakis
        if profile != "DISABLED":
881 27435d42 Christos Stavrakakis
            client.AddInstanceTags(vm.backend_vm_id, [tag],
882 27435d42 Christos Stavrakakis
                                   dry_run=settings.TEST)
883 9afeb669 Kostas Papadimitriou
884 3524241a Christos Stavrakakis
        # XXX NOP ModifyInstance call to force process_net_status to run
885 3524241a Christos Stavrakakis
        # on the dispatcher
886 cc92b70f Christos Stavrakakis
        os_name = settings.GANETI_CREATEINSTANCE_KWARGS['os']
887 3524241a Christos Stavrakakis
        client.ModifyInstance(vm.backend_vm_id,
888 cc92b70f Christos Stavrakakis
                              os_name=os_name)
889 41a7fae7 Christos Stavrakakis
    return None
890 5eedb0e4 Vangelis Koukis
891 41303ed0 Vangelis Koukis
892 e77a29ab Christos Stavrakakis
def get_instances(backend, bulk=True):
893 e77a29ab Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
894 e77a29ab Christos Stavrakakis
        return c.GetInstances(bulk=bulk)
895 d986cb32 Christos Stavrakakis
896 f5b4f2a3 Christos Stavrakakis
897 e77a29ab Christos Stavrakakis
def get_nodes(backend, bulk=True):
898 e77a29ab Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
899 e77a29ab Christos Stavrakakis
        return c.GetNodes(bulk=bulk)
900 1a894bfe Christos Stavrakakis
901 1a894bfe Christos Stavrakakis
902 70a0afab Christos Stavrakakis
def get_jobs(backend, bulk=True):
903 e77a29ab Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
904 70a0afab Christos Stavrakakis
        return c.GetJobs(bulk=bulk)
905 f5b4f2a3 Christos Stavrakakis
906 17852fe9 Giorgos Verigakis
907 1a894bfe Christos Stavrakakis
def get_physical_resources(backend):
908 1a894bfe Christos Stavrakakis
    """ Get the physical resources of a backend.
909 1a894bfe Christos Stavrakakis

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

912 1a894bfe Christos Stavrakakis
    """
913 e77a29ab Christos Stavrakakis
    nodes = get_nodes(backend, bulk=True)
914 1a894bfe Christos Stavrakakis
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
915 1a894bfe Christos Stavrakakis
    res = {}
916 1a894bfe Christos Stavrakakis
    for a in attr:
917 1a894bfe Christos Stavrakakis
        res[a] = 0
918 1a894bfe Christos Stavrakakis
    for n in nodes:
919 1a894bfe Christos Stavrakakis
        # Filter out drained, offline and not vm_capable nodes since they will
920 1a894bfe Christos Stavrakakis
        # not take part in the vm allocation process
921 cc92b70f Christos Stavrakakis
        can_host_vms = n['vm_capable'] and not (n['drained'] or n['offline'])
922 cc92b70f Christos Stavrakakis
        if can_host_vms and n['cnodes']:
923 1a894bfe Christos Stavrakakis
            for a in attr:
924 121b8921 Christos Stavrakakis
                res[a] += int(n[a] or 0)
925 1a894bfe Christos Stavrakakis
    return res
926 1a894bfe Christos Stavrakakis
927 1a894bfe Christos Stavrakakis
928 1da50fe3 Christos Stavrakakis
def update_backend_resources(backend, resources=None):
929 1a894bfe Christos Stavrakakis
    """ Update the state of the backend resources in db.
930 1a894bfe Christos Stavrakakis

931 1a894bfe Christos Stavrakakis
    """
932 17852fe9 Giorgos Verigakis
933 1a894bfe Christos Stavrakakis
    if not resources:
934 1a894bfe Christos Stavrakakis
        resources = get_physical_resources(backend)
935 41303ed0 Vangelis Koukis
936 1a894bfe Christos Stavrakakis
    backend.mfree = resources['mfree']
937 1a894bfe Christos Stavrakakis
    backend.mtotal = resources['mtotal']
938 1a894bfe Christos Stavrakakis
    backend.dfree = resources['dfree']
939 1a894bfe Christos Stavrakakis
    backend.dtotal = resources['dtotal']
940 1a894bfe Christos Stavrakakis
    backend.pinst_cnt = resources['pinst_cnt']
941 1a894bfe Christos Stavrakakis
    backend.ctotal = resources['ctotal']
942 1a894bfe Christos Stavrakakis
    backend.updated = datetime.now()
943 1a894bfe Christos Stavrakakis
    backend.save()
944 1a894bfe Christos Stavrakakis
945 1a894bfe Christos Stavrakakis
946 1a894bfe Christos Stavrakakis
def get_memory_from_instances(backend):
947 1a894bfe Christos Stavrakakis
    """ Get the memory that is used from instances.
948 1a894bfe Christos Stavrakakis

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

952 1a894bfe Christos Stavrakakis
    """
953 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
954 3524241a Christos Stavrakakis
        instances = client.GetInstances(bulk=True)
955 1a894bfe Christos Stavrakakis
    mem = 0
956 1a894bfe Christos Stavrakakis
    for i in instances:
957 1a894bfe Christos Stavrakakis
        mem += i['oper_ram']
958 1a894bfe Christos Stavrakakis
    return mem
959 b3d28af2 Christos Stavrakakis
960 1da50fe3 Christos Stavrakakis
961 1da50fe3 Christos Stavrakakis
def get_available_disk_templates(backend):
962 1da50fe3 Christos Stavrakakis
    """Get the list of available disk templates of a Ganeti backend.
963 1da50fe3 Christos Stavrakakis

964 1da50fe3 Christos Stavrakakis
    The list contains the disk templates that are enabled in the Ganeti backend
965 1da50fe3 Christos Stavrakakis
    and also included in ipolicy-disk-templates.
966 1da50fe3 Christos Stavrakakis

967 1da50fe3 Christos Stavrakakis
    """
968 1da50fe3 Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
969 1da50fe3 Christos Stavrakakis
        info = c.GetInfo()
970 1da50fe3 Christos Stavrakakis
    ipolicy_disk_templates = info["ipolicy"]["disk-templates"]
971 a8ae6989 Christos Stavrakakis
    try:
972 a8ae6989 Christos Stavrakakis
        enabled_disk_templates = info["enabled_disk_templates"]
973 a8ae6989 Christos Stavrakakis
        return [dp for dp in enabled_disk_templates
974 a8ae6989 Christos Stavrakakis
                if dp in ipolicy_disk_templates]
975 a8ae6989 Christos Stavrakakis
    except KeyError:
976 a8ae6989 Christos Stavrakakis
        # Ganeti < 2.8 does not have 'enabled_disk_templates'
977 a8ae6989 Christos Stavrakakis
        return ipolicy_disk_templates
978 1da50fe3 Christos Stavrakakis
979 1da50fe3 Christos Stavrakakis
980 1da50fe3 Christos Stavrakakis
def update_backend_disk_templates(backend):
981 1da50fe3 Christos Stavrakakis
    disk_templates = get_available_disk_templates(backend)
982 1da50fe3 Christos Stavrakakis
    backend.disk_templates = disk_templates
983 1da50fe3 Christos Stavrakakis
    backend.save()
984 1da50fe3 Christos Stavrakakis
985 1da50fe3 Christos Stavrakakis
986 b3d28af2 Christos Stavrakakis
##
987 b3d28af2 Christos Stavrakakis
## Synchronized operations for reconciliation
988 b3d28af2 Christos Stavrakakis
##
989 b3d28af2 Christos Stavrakakis
990 b3d28af2 Christos Stavrakakis
991 b3d28af2 Christos Stavrakakis
def create_network_synced(network, backend):
992 b3d28af2 Christos Stavrakakis
    result = _create_network_synced(network, backend)
993 b3d28af2 Christos Stavrakakis
    if result[0] != 'success':
994 b3d28af2 Christos Stavrakakis
        return result
995 b3d28af2 Christos Stavrakakis
    result = connect_network_synced(network, backend)
996 b3d28af2 Christos Stavrakakis
    return result
997 b3d28af2 Christos Stavrakakis
998 b3d28af2 Christos Stavrakakis
999 b3d28af2 Christos Stavrakakis
def _create_network_synced(network, backend):
1000 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
1001 e60b4630 Christos Stavrakakis
        job = _create_network(network, backend)
1002 3524241a Christos Stavrakakis
        result = wait_for_job(client, job)
1003 3524241a Christos Stavrakakis
    return result
1004 b3d28af2 Christos Stavrakakis
1005 b3d28af2 Christos Stavrakakis
1006 b3d28af2 Christos Stavrakakis
def connect_network_synced(network, backend):
1007 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as client:
1008 3524241a Christos Stavrakakis
        for group in client.GetGroups():
1009 b7d38981 Dimitris Aragiorgis
            job = client.ConnectNetwork(network.backend_id, group,
1010 b7d38981 Dimitris Aragiorgis
                                        network.mode, network.link)
1011 3524241a Christos Stavrakakis
            result = wait_for_job(client, job)
1012 3524241a Christos Stavrakakis
            if result[0] != 'success':
1013 3524241a Christos Stavrakakis
                return result
1014 b3d28af2 Christos Stavrakakis
1015 b3d28af2 Christos Stavrakakis
    return result
1016 b3d28af2 Christos Stavrakakis
1017 b3d28af2 Christos Stavrakakis
1018 b3d28af2 Christos Stavrakakis
def wait_for_job(client, jobid):
1019 b3d28af2 Christos Stavrakakis
    result = client.WaitForJobChange(jobid, ['status', 'opresult'], None, None)
1020 b3d28af2 Christos Stavrakakis
    status = result['job_info'][0]
1021 b3d28af2 Christos Stavrakakis
    while status not in ['success', 'error', 'cancel']:
1022 b3d28af2 Christos Stavrakakis
        result = client.WaitForJobChange(jobid, ['status', 'opresult'],
1023 cc92b70f Christos Stavrakakis
                                         [result], None)
1024 b3d28af2 Christos Stavrakakis
        status = result['job_info'][0]
1025 b3d28af2 Christos Stavrakakis
1026 b3d28af2 Christos Stavrakakis
    if status == 'success':
1027 b3d28af2 Christos Stavrakakis
        return (status, None)
1028 b3d28af2 Christos Stavrakakis
    else:
1029 b3d28af2 Christos Stavrakakis
        error = result['job_info'][1]
1030 b3d28af2 Christos Stavrakakis
        return (status, error)