Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / reconciliation.py @ 28662998

History | View | Annotate | Download (12.6 kB)

1 9fea53cc Vangelis Koukis
#!/usr/bin/env python
2 9fea53cc Vangelis Koukis
# -*- coding: utf-8 -*-
3 9fea53cc Vangelis Koukis
#
4 9fea53cc Vangelis Koukis
# Copyright 2011 GRNET S.A. All rights reserved.
5 9fea53cc Vangelis Koukis
#
6 9fea53cc Vangelis Koukis
# Redistribution and use in source and binary forms, with or
7 9fea53cc Vangelis Koukis
# without modification, are permitted provided that the following
8 9fea53cc Vangelis Koukis
# conditions are met:
9 9fea53cc Vangelis Koukis
#
10 9fea53cc Vangelis Koukis
#   1. Redistributions of source code must retain the above
11 9fea53cc Vangelis Koukis
#      copyright notice, this list of conditions and the following
12 9fea53cc Vangelis Koukis
#      disclaimer.
13 9fea53cc Vangelis Koukis
#
14 9fea53cc Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
15 9fea53cc Vangelis Koukis
#      copyright notice, this list of conditions and the following
16 9fea53cc Vangelis Koukis
#      disclaimer in the documentation and/or other materials
17 9fea53cc Vangelis Koukis
#      provided with the distribution.
18 9fea53cc Vangelis Koukis
#
19 9fea53cc Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20 9fea53cc Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 9fea53cc Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 9fea53cc Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23 9fea53cc Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 9fea53cc Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 9fea53cc Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 9fea53cc Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 9fea53cc Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 9fea53cc Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 9fea53cc Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 9fea53cc Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
31 9fea53cc Vangelis Koukis
#
32 9fea53cc Vangelis Koukis
# The views and conclusions contained in the software and
33 9fea53cc Vangelis Koukis
# documentation are those of the authors and should not be
34 9fea53cc Vangelis Koukis
# interpreted as representing official policies, either expressed
35 9fea53cc Vangelis Koukis
# or implied, of GRNET S.A.
36 9fea53cc Vangelis Koukis
#
37 9fea53cc Vangelis Koukis
"""Business logic for reconciliation
38 9fea53cc Vangelis Koukis

39 9fea53cc Vangelis Koukis
Reconcile the contents of the DB with the actual state of the
40 9fea53cc Vangelis Koukis
Ganeti backend.
41 9fea53cc Vangelis Koukis

42 9fea53cc Vangelis Koukis
Let D be the set of VMs in the DB, G the set of VMs in Ganeti.
43 9fea53cc Vangelis Koukis
RULES:
44 9fea53cc Vangelis Koukis
    R1. Stale servers in DB:
45 9fea53cc Vangelis Koukis
            For any v in D but not in G:
46 9fea53cc Vangelis Koukis
            Set deleted=True.
47 9fea53cc Vangelis Koukis
    R2. Orphan instances in Ganet:
48 9fea53cc Vangelis Koukis
            For any v in G with deleted=True in D:
49 9fea53cc Vangelis Koukis
            Issue OP_INSTANCE_DESTROY.
50 9fea53cc Vangelis Koukis
    R3. Unsynced operstate:
51 9fea53cc Vangelis Koukis
            For any v whose operating state differs between G and V:
52 9fea53cc Vangelis Koukis
            Set the operating state in D based on the state in G.
53 9fea53cc Vangelis Koukis
In the code, D, G are Python dicts mapping instance ids to operating state.
54 9fea53cc Vangelis Koukis
For D, the operating state is chosen from VirtualMachine.OPER_STATES.
55 9fea53cc Vangelis Koukis
For G, the operating state is True if the machine is up, False otherwise.
56 9fea53cc Vangelis Koukis

57 9fea53cc Vangelis Koukis
"""
58 9fea53cc Vangelis Koukis
59 9e98ba3c Giorgos Verigakis
import logging
60 9fea53cc Vangelis Koukis
import sys
61 0e9a423f Christos Stavrakakis
import itertools
62 9fea53cc Vangelis Koukis
63 9fea53cc Vangelis Koukis
from django.core.management import setup_environ
64 9fea53cc Vangelis Koukis
try:
65 9fea53cc Vangelis Koukis
    from synnefo import settings
66 9fea53cc Vangelis Koukis
except ImportError:
67 9fea53cc Vangelis Koukis
    raise Exception("Cannot import settings, make sure PYTHONPATH contains "
68 9fea53cc Vangelis Koukis
                    "the parent directory of the Synnefo Django project.")
69 9fea53cc Vangelis Koukis
setup_environ(settings)
70 9fea53cc Vangelis Koukis
71 4161cb41 Christos Stavrakakis
72 4161cb41 Christos Stavrakakis
from datetime import datetime, timedelta
73 7ab30015 Christos Stavrakakis
from collections import namedtuple
74 4161cb41 Christos Stavrakakis
75 a67419d8 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, NetworkInterface, Flavor,
76 7ab30015 Christos Stavrakakis
                               pooled_rapi_client)
77 3524241a Christos Stavrakakis
from synnefo.logic.rapi import GanetiApiError
78 e77a29ab Christos Stavrakakis
from synnefo.logic.backend import get_instances
79 d30f29aa Christos Stavrakakis
from synnefo.logic import utils
80 9fea53cc Vangelis Koukis
81 9fea53cc Vangelis Koukis
82 9e98ba3c Giorgos Verigakis
log = logging.getLogger()
83 9e98ba3c Giorgos Verigakis
84 e63050ca Christos Stavrakakis
try:
85 e63050ca Christos Stavrakakis
    CHECK_INTERVAL = settings.RECONCILIATION_CHECK_INTERVAL
86 e63050ca Christos Stavrakakis
except AttributeError:
87 e63050ca Christos Stavrakakis
    CHECK_INTERVAL = 60
88 e63050ca Christos Stavrakakis
89 e63050ca Christos Stavrakakis
90 e63050ca Christos Stavrakakis
def needs_reconciliation(vm):
91 e63050ca Christos Stavrakakis
    now = datetime.now()
92 e63050ca Christos Stavrakakis
    return (now > vm.updated + timedelta(seconds=CHECK_INTERVAL)) or\
93 e63050ca Christos Stavrakakis
           (now > vm.backendtime + timedelta(seconds=2*CHECK_INTERVAL))
94 e63050ca Christos Stavrakakis
95 a67419d8 Christos Stavrakakis
VMState = namedtuple("VMState", ["state", "cpu", "ram", "nics"])
96 7ab30015 Christos Stavrakakis
97 9e98ba3c Giorgos Verigakis
98 9fea53cc Vangelis Koukis
def stale_servers_in_db(D, G):
99 9fea53cc Vangelis Koukis
    idD = set(D.keys())
100 9fea53cc Vangelis Koukis
    idG = set(G.keys())
101 9fea53cc Vangelis Koukis
102 4161cb41 Christos Stavrakakis
    stale = set()
103 4161cb41 Christos Stavrakakis
    for i in idD - idG:
104 4161cb41 Christos Stavrakakis
        if D[i] == 'BUILD':
105 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
106 e63050ca Christos Stavrakakis
            if needs_reconciliation(vm):
107 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
108 4216cd83 Christos Stavrakakis
                    try:
109 3524241a Christos Stavrakakis
                        job_status = c.GetJobStatus(vm.backendjobid)['status']
110 3524241a Christos Stavrakakis
                        if job_status in ('queued', 'waiting', 'running'):
111 3524241a Christos Stavrakakis
                            # Server is still building in Ganeti
112 3524241a Christos Stavrakakis
                            continue
113 3524241a Christos Stavrakakis
                        else:
114 3524241a Christos Stavrakakis
                            c.GetInstance(utils.id_to_instance_name(i))
115 3524241a Christos Stavrakakis
                            # Server has just been created in Ganeti
116 3524241a Christos Stavrakakis
                            continue
117 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
118 4216cd83 Christos Stavrakakis
                        stale.add(i)
119 4161cb41 Christos Stavrakakis
        else:
120 4161cb41 Christos Stavrakakis
            stale.add(i)
121 4161cb41 Christos Stavrakakis
122 4161cb41 Christos Stavrakakis
    return stale
123 9fea53cc Vangelis Koukis
124 9fea53cc Vangelis Koukis
125 9fea53cc Vangelis Koukis
def orphan_instances_in_ganeti(D, G):
126 9fea53cc Vangelis Koukis
    idD = set(D.keys())
127 9fea53cc Vangelis Koukis
    idG = set(G.keys())
128 9fea53cc Vangelis Koukis
129 9fea53cc Vangelis Koukis
    return idG - idD
130 9fea53cc Vangelis Koukis
131 9fea53cc Vangelis Koukis
132 9fea53cc Vangelis Koukis
def unsynced_operstate(D, G):
133 9fea53cc Vangelis Koukis
    unsynced = set()
134 9fea53cc Vangelis Koukis
    idD = set(D.keys())
135 9fea53cc Vangelis Koukis
    idG = set(G.keys())
136 9fea53cc Vangelis Koukis
137 9fea53cc Vangelis Koukis
    for i in idD & idG:
138 7ab30015 Christos Stavrakakis
        dbstate = D[i].state
139 7ab30015 Christos Stavrakakis
        gntstate = G[i].state
140 7ab30015 Christos Stavrakakis
        vm_unsynced = (gntstate and dbstate != "STARTED") or\
141 7ab30015 Christos Stavrakakis
            (not gntstate and dbstate not in ('BUILD', 'ERROR', 'STOPPED'))
142 c4e45b57 Christos Stavrakakis
        if vm_unsynced:
143 7ab30015 Christos Stavrakakis
            unsynced.add((i, dbstate, gntstate))
144 7ab30015 Christos Stavrakakis
        if not gntstate and dbstate == 'BUILD':
145 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
146 e63050ca Christos Stavrakakis
            if needs_reconciliation(vm):
147 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
148 4216cd83 Christos Stavrakakis
                    try:
149 3524241a Christos Stavrakakis
                        job_info = c.GetJobStatus(job_id=vm.backendjobid)
150 3524241a Christos Stavrakakis
                        if job_info['status'] == 'success':
151 7ab30015 Christos Stavrakakis
                            unsynced.add((i, dbstate, gntstate))
152 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
153 4216cd83 Christos Stavrakakis
                        pass
154 9fea53cc Vangelis Koukis
155 9fea53cc Vangelis Koukis
    return unsynced
156 9fea53cc Vangelis Koukis
157 9fea53cc Vangelis Koukis
158 a67419d8 Christos Stavrakakis
def unsynced_flavors(D, G):
159 a67419d8 Christos Stavrakakis
    unsynced = set()
160 a67419d8 Christos Stavrakakis
    idD = set(D.keys())
161 a67419d8 Christos Stavrakakis
    idG = set(G.keys())
162 a67419d8 Christos Stavrakakis
163 a67419d8 Christos Stavrakakis
    for i in idD & idG:
164 a67419d8 Christos Stavrakakis
        if D[i].ram != G[i].ram or D[i].cpu != G[i].cpu:
165 a67419d8 Christos Stavrakakis
            db_flavor = VirtualMachine.objects.get(id=i).flavor
166 a67419d8 Christos Stavrakakis
            try:
167 a67419d8 Christos Stavrakakis
                gnt_flavor = Flavor.objects.get(
168 a67419d8 Christos Stavrakakis
                                    ram=G[i].ram, cpu=G[i].cpu,
169 a67419d8 Christos Stavrakakis
                                    disk=db_flavor.disk,
170 a67419d8 Christos Stavrakakis
                                    disk_template=db_flavor.disk_template)
171 a67419d8 Christos Stavrakakis
            except Flavor.DoesNotExist:
172 a67419d8 Christos Stavrakakis
                gnt_flavor = None
173 a67419d8 Christos Stavrakakis
            unsynced.add((i, db_flavor, gnt_flavor))
174 a67419d8 Christos Stavrakakis
    return unsynced
175 a67419d8 Christos Stavrakakis
176 a67419d8 Christos Stavrakakis
177 4161cb41 Christos Stavrakakis
def instances_with_build_errors(D, G):
178 4161cb41 Christos Stavrakakis
    failed = set()
179 4161cb41 Christos Stavrakakis
    idD = set(D.keys())
180 4161cb41 Christos Stavrakakis
    idG = set(G.keys())
181 4161cb41 Christos Stavrakakis
182 4161cb41 Christos Stavrakakis
    for i in idD & idG:
183 4161cb41 Christos Stavrakakis
        if not G[i] and D[i] == 'BUILD':
184 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
185 1ad47ca5 Christos Stavrakakis
            if not vm.backendjobid:  # VM has not been enqueued in the backend
186 1ad47ca5 Christos Stavrakakis
                if datetime.now() > vm.created + timedelta(seconds=120):
187 1ad47ca5 Christos Stavrakakis
                    # If a job has not been enqueued after 2 minutues, then
188 1ad47ca5 Christos Stavrakakis
                    # it must be a stale entry..
189 1ad47ca5 Christos Stavrakakis
                    failed.add(i)
190 e63050ca Christos Stavrakakis
            elif needs_reconciliation(vm):
191 1ad47ca5 Christos Stavrakakis
                # Check time to avoid many rapi calls
192 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
193 4216cd83 Christos Stavrakakis
                    try:
194 3524241a Christos Stavrakakis
                        job_info = c.GetJobStatus(job_id=vm.backendjobid)
195 3524241a Christos Stavrakakis
                        if job_info['status'] == 'error':
196 3524241a Christos Stavrakakis
                            failed.add(i)
197 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
198 4216cd83 Christos Stavrakakis
                        failed.add(i)
199 4161cb41 Christos Stavrakakis
200 4161cb41 Christos Stavrakakis
    return failed
201 4161cb41 Christos Stavrakakis
202 4161cb41 Christos Stavrakakis
203 7ab30015 Christos Stavrakakis
def get_servers_from_db(backends, with_nics=True):
204 c414bc87 Christos Stavrakakis
    vms = VirtualMachine.objects.filter(deleted=False, backend__in=backends)
205 a67419d8 Christos Stavrakakis
    vm_info = vms.values_list("id", "operstate", "flavor__cpu", "flavor__ram")
206 7ab30015 Christos Stavrakakis
    if with_nics:
207 7ab30015 Christos Stavrakakis
        nics = NetworkInterface.objects.filter(machine__in=vms)\
208 7ab30015 Christos Stavrakakis
                               .order_by("machine")\
209 7ab30015 Christos Stavrakakis
                               .values_list("machine", "index", "mac", "ipv4",
210 7ab30015 Christos Stavrakakis
                                            "network")
211 7ab30015 Christos Stavrakakis
        vm_nics = {}
212 7ab30015 Christos Stavrakakis
        for machine, machine_nics in itertools.groupby(nics,
213 7ab30015 Christos Stavrakakis
                                                       lambda nic: nic[0]):
214 7ab30015 Christos Stavrakakis
            vm_nics[machine] = {}
215 7ab30015 Christos Stavrakakis
            for machine, index, mac, ipv4, network in machine_nics:
216 7ab30015 Christos Stavrakakis
                nic = {'mac':      mac,
217 7ab30015 Christos Stavrakakis
                       'network':  utils.id_to_network_name(network),
218 7ab30015 Christos Stavrakakis
                       'ipv4':     ipv4 if ipv4 != '' else None
219 7ab30015 Christos Stavrakakis
                       }
220 7ab30015 Christos Stavrakakis
                vm_nics[machine][index] = nic
221 a67419d8 Christos Stavrakakis
    servers = dict([(vm_id, VMState(state=state,
222 a67419d8 Christos Stavrakakis
                                    cpu=cpu,
223 a67419d8 Christos Stavrakakis
                                    ram=ram,
224 a67419d8 Christos Stavrakakis
                                    nics=vm_nics.get(vm_id, [])))
225 a67419d8 Christos Stavrakakis
                    for vm_id, state, cpu, ram in vm_info])
226 7ab30015 Christos Stavrakakis
    return servers
227 9fea53cc Vangelis Koukis
228 9fea53cc Vangelis Koukis
229 e77a29ab Christos Stavrakakis
def get_instances_from_ganeti(backends):
230 e77a29ab Christos Stavrakakis
    instances = []
231 e77a29ab Christos Stavrakakis
    for backend in backends:
232 e77a29ab Christos Stavrakakis
        instances.append(get_instances(backend))
233 e77a29ab Christos Stavrakakis
    ganeti_instances = reduce(list.__add__, instances, [])
234 9fea53cc Vangelis Koukis
    snf_instances = {}
235 9fea53cc Vangelis Koukis
236 9fea53cc Vangelis Koukis
    prefix = settings.BACKEND_PREFIX_ID
237 9fea53cc Vangelis Koukis
    for i in ganeti_instances:
238 9fea53cc Vangelis Koukis
        if i['name'].startswith(prefix):
239 9fea53cc Vangelis Koukis
            try:
240 d30f29aa Christos Stavrakakis
                id = utils.id_from_instance_name(i['name'])
241 9fea53cc Vangelis Koukis
            except Exception:
242 9e98ba3c Giorgos Verigakis
                log.error("Ignoring instance with malformed name %s",
243 cc92b70f Christos Stavrakakis
                          i['name'])
244 9fea53cc Vangelis Koukis
                continue
245 9fea53cc Vangelis Koukis
246 9fea53cc Vangelis Koukis
            if id in snf_instances:
247 9e98ba3c Giorgos Verigakis
                log.error("Ignoring instance with duplicate Synnefo id %s",
248 cc92b70f Christos Stavrakakis
                          i['name'])
249 9fea53cc Vangelis Koukis
                continue
250 9fea53cc Vangelis Koukis
251 7ab30015 Christos Stavrakakis
            nics = get_nics_from_instance(i)
252 a67419d8 Christos Stavrakakis
            beparams = i["beparams"]
253 a67419d8 Christos Stavrakakis
            vcpus = beparams["vcpus"]
254 a67419d8 Christos Stavrakakis
            ram = beparams["maxmem"]
255 7ab30015 Christos Stavrakakis
            snf_instances[id] = VMState(state=i["oper_state"],
256 a67419d8 Christos Stavrakakis
                                        cpu=vcpus,
257 a67419d8 Christos Stavrakakis
                                        ram=ram,
258 7ab30015 Christos Stavrakakis
                                        nics=nics)
259 9fea53cc Vangelis Koukis
260 7ab30015 Christos Stavrakakis
    return snf_instances
261 9fea53cc Vangelis Koukis
262 cc92b70f Christos Stavrakakis
263 0e9a423f Christos Stavrakakis
#
264 0e9a423f Christos Stavrakakis
# Nics
265 0e9a423f Christos Stavrakakis
#
266 e77a29ab Christos Stavrakakis
def get_nics_from_ganeti(backends):
267 0e9a423f Christos Stavrakakis
    """Get network interfaces for each ganeti instance.
268 0e9a423f Christos Stavrakakis

269 0e9a423f Christos Stavrakakis
    """
270 e77a29ab Christos Stavrakakis
    instances = []
271 e77a29ab Christos Stavrakakis
    for backend in backends:
272 e77a29ab Christos Stavrakakis
        instances.append(get_instances(backend))
273 e77a29ab Christos Stavrakakis
    instances = reduce(list.__add__, instances, [])
274 0e9a423f Christos Stavrakakis
    prefix = settings.BACKEND_PREFIX_ID
275 0e9a423f Christos Stavrakakis
276 0e9a423f Christos Stavrakakis
    snf_instances_nics = {}
277 0e9a423f Christos Stavrakakis
    for i in instances:
278 0e9a423f Christos Stavrakakis
        if i['name'].startswith(prefix):
279 0e9a423f Christos Stavrakakis
            try:
280 d30f29aa Christos Stavrakakis
                id = utils.id_from_instance_name(i['name'])
281 0e9a423f Christos Stavrakakis
            except Exception:
282 0e9a423f Christos Stavrakakis
                log.error("Ignoring instance with malformed name %s",
283 cc92b70f Christos Stavrakakis
                          i['name'])
284 0e9a423f Christos Stavrakakis
                continue
285 0e9a423f Christos Stavrakakis
            if id in snf_instances_nics:
286 0e9a423f Christos Stavrakakis
                log.error("Ignoring instance with duplicate Synnefo id %s",
287 cc92b70f Christos Stavrakakis
                          i['name'])
288 0e9a423f Christos Stavrakakis
                continue
289 0e9a423f Christos Stavrakakis
290 c6ad2f2d Christos Stavrakakis
            snf_instances_nics[id] = get_nics_from_instance(i)
291 0e9a423f Christos Stavrakakis
292 0e9a423f Christos Stavrakakis
    return snf_instances_nics
293 0e9a423f Christos Stavrakakis
294 0e9a423f Christos Stavrakakis
295 c6ad2f2d Christos Stavrakakis
def get_nics_from_instance(i):
296 c6ad2f2d Christos Stavrakakis
    ips = zip(itertools.repeat('ipv4'), i['nic.ips'])
297 c6ad2f2d Christos Stavrakakis
    macs = zip(itertools.repeat('mac'), i['nic.macs'])
298 c6ad2f2d Christos Stavrakakis
    networks = zip(itertools.repeat('network'), i['nic.networks'])
299 c6ad2f2d Christos Stavrakakis
    # modes = zip(itertools.repeat('mode'), i['nic.modes'])
300 c6ad2f2d Christos Stavrakakis
    # links = zip(itertools.repeat('link'), i['nic.links'])
301 c6ad2f2d Christos Stavrakakis
    # nics = zip(ips,macs,modes,networks,links)
302 c6ad2f2d Christos Stavrakakis
    nics = zip(ips, macs, networks)
303 c6ad2f2d Christos Stavrakakis
    nics = map(lambda x: dict(x), nics)
304 c6ad2f2d Christos Stavrakakis
    nics = dict(enumerate(nics))
305 c6ad2f2d Christos Stavrakakis
    return nics
306 c6ad2f2d Christos Stavrakakis
307 c6ad2f2d Christos Stavrakakis
308 7ab30015 Christos Stavrakakis
def unsynced_nics(DBVMs, GanetiVMs):
309 0e9a423f Christos Stavrakakis
    """Find unsynced network interfaces between DB and Ganeti.
310 0e9a423f Christos Stavrakakis

311 0e9a423f Christos Stavrakakis
    @ rtype: dict; {instance_id: ganeti_nics}
312 0e9a423f Christos Stavrakakis
    @ return Dictionary containing the instances ids that have unsynced network
313 0e9a423f Christos Stavrakakis
    interfaces between DB and Ganeti and the network interfaces in Ganeti.
314 0e9a423f Christos Stavrakakis

315 0e9a423f Christos Stavrakakis
    """
316 7ab30015 Christos Stavrakakis
    idD = set(DBVMs.keys())
317 7ab30015 Christos Stavrakakis
    idG = set(GanetiVMs.keys())
318 0e9a423f Christos Stavrakakis
319 0e9a423f Christos Stavrakakis
    unsynced = {}
320 0e9a423f Christos Stavrakakis
    for i in idD & idG:
321 7ab30015 Christos Stavrakakis
        nicsD = DBVMs[i].nics
322 7ab30015 Christos Stavrakakis
        nicsG = GanetiVMs[i].nics
323 0e9a423f Christos Stavrakakis
        if len(nicsD) != len(nicsG):
324 0e9a423f Christos Stavrakakis
            unsynced[i] = (nicsD, nicsG)
325 0e9a423f Christos Stavrakakis
            continue
326 0e9a423f Christos Stavrakakis
        for index in nicsG.keys():
327 0e9a423f Christos Stavrakakis
            nicD = nicsD[index]
328 0e9a423f Christos Stavrakakis
            nicG = nicsG[index]
329 c4e45b57 Christos Stavrakakis
            diff = (nicD['ipv4'] != nicG['ipv4'] or
330 c4e45b57 Christos Stavrakakis
                    nicD['mac'] != nicG['mac'] or
331 c4e45b57 Christos Stavrakakis
                    nicD['network'] != nicG['network'])
332 c4e45b57 Christos Stavrakakis
            if diff:
333 cc92b70f Christos Stavrakakis
                    unsynced[i] = (nicsD, nicsG)
334 cc92b70f Christos Stavrakakis
                    break
335 0e9a423f Christos Stavrakakis
336 0e9a423f Christos Stavrakakis
    return unsynced
337 0e9a423f Christos Stavrakakis
338 0e9a423f Christos Stavrakakis
#
339 0e9a423f Christos Stavrakakis
# Networks
340 0e9a423f Christos Stavrakakis
#
341 3524241a Christos Stavrakakis
342 3524241a Christos Stavrakakis
343 0e9a423f Christos Stavrakakis
def get_networks_from_ganeti(backend):
344 44e2c577 Christos Stavrakakis
    prefix = settings.BACKEND_PREFIX_ID + 'net-'
345 0e9a423f Christos Stavrakakis
346 0e9a423f Christos Stavrakakis
    networks = {}
347 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
348 3524241a Christos Stavrakakis
        for net in c.GetNetworks(bulk=True):
349 3524241a Christos Stavrakakis
            if net['name'].startswith(prefix):
350 3524241a Christos Stavrakakis
                id = utils.id_from_network_name(net['name'])
351 3524241a Christos Stavrakakis
                networks[id] = net
352 0e9a423f Christos Stavrakakis
353 0e9a423f Christos Stavrakakis
    return networks
354 0e9a423f Christos Stavrakakis
355 0e9a423f Christos Stavrakakis
356 0e9a423f Christos Stavrakakis
def hanging_networks(backend, GNets):
357 0e9a423f Christos Stavrakakis
    """Get networks that are not connected to all Nodegroups.
358 0e9a423f Christos Stavrakakis

359 0e9a423f Christos Stavrakakis
    """
360 0e9a423f Christos Stavrakakis
    def get_network_groups(group_list):
361 0e9a423f Christos Stavrakakis
        groups = set()
362 0e9a423f Christos Stavrakakis
        for g in group_list:
363 0e9a423f Christos Stavrakakis
            g_name = g.split('(')[0]
364 0e9a423f Christos Stavrakakis
            groups.add(g_name)
365 0e9a423f Christos Stavrakakis
        return groups
366 0e9a423f Christos Stavrakakis
367 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
368 3524241a Christos Stavrakakis
        groups = set(c.GetGroups())
369 0e9a423f Christos Stavrakakis
370 0e9a423f Christos Stavrakakis
    hanging = {}
371 0e9a423f Christos Stavrakakis
    for id, info in GNets.items():
372 0e9a423f Christos Stavrakakis
        group_list = get_network_groups(info['group_list'])
373 0e9a423f Christos Stavrakakis
        if group_list != groups:
374 0e9a423f Christos Stavrakakis
            hanging[id] = groups - group_list
375 0e9a423f Christos Stavrakakis
    return hanging
376 0e9a423f Christos Stavrakakis
377 9fea53cc Vangelis Koukis
378 a65ee5fc Vangelis Koukis
# Only for testing this module individually
379 9fea53cc Vangelis Koukis
def main():
380 9fea53cc Vangelis Koukis
    print get_instances_from_ganeti()
381 9fea53cc Vangelis Koukis
382 9fea53cc Vangelis Koukis
383 9fea53cc Vangelis Koukis
if __name__ == "__main__":
384 9fea53cc Vangelis Koukis
    sys.exit(main())