Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11 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 4161cb41 Christos Stavrakakis
74 3524241a Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, pooled_rapi_client)
75 3524241a Christos Stavrakakis
from synnefo.logic.rapi import GanetiApiError
76 e77a29ab Christos Stavrakakis
from synnefo.logic.backend import get_instances
77 d30f29aa Christos Stavrakakis
from synnefo.logic import utils
78 9fea53cc Vangelis Koukis
79 9fea53cc Vangelis Koukis
80 9e98ba3c Giorgos Verigakis
log = logging.getLogger()
81 9e98ba3c Giorgos Verigakis
82 e63050ca Christos Stavrakakis
try:
83 e63050ca Christos Stavrakakis
    CHECK_INTERVAL = settings.RECONCILIATION_CHECK_INTERVAL
84 e63050ca Christos Stavrakakis
except AttributeError:
85 e63050ca Christos Stavrakakis
    CHECK_INTERVAL = 60
86 e63050ca Christos Stavrakakis
87 e63050ca Christos Stavrakakis
88 e63050ca Christos Stavrakakis
def needs_reconciliation(vm):
89 e63050ca Christos Stavrakakis
    now = datetime.now()
90 e63050ca Christos Stavrakakis
    return (now > vm.updated + timedelta(seconds=CHECK_INTERVAL)) or\
91 e63050ca Christos Stavrakakis
           (now > vm.backendtime + timedelta(seconds=2*CHECK_INTERVAL))
92 e63050ca Christos Stavrakakis
93 9e98ba3c Giorgos Verigakis
94 9fea53cc Vangelis Koukis
def stale_servers_in_db(D, G):
95 9fea53cc Vangelis Koukis
    idD = set(D.keys())
96 9fea53cc Vangelis Koukis
    idG = set(G.keys())
97 9fea53cc Vangelis Koukis
98 4161cb41 Christos Stavrakakis
    stale = set()
99 4161cb41 Christos Stavrakakis
    for i in idD - idG:
100 4161cb41 Christos Stavrakakis
        if D[i] == 'BUILD':
101 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
102 e63050ca Christos Stavrakakis
            if needs_reconciliation(vm):
103 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
104 4216cd83 Christos Stavrakakis
                    try:
105 3524241a Christos Stavrakakis
                        job_status = c.GetJobStatus(vm.backendjobid)['status']
106 3524241a Christos Stavrakakis
                        if job_status in ('queued', 'waiting', 'running'):
107 3524241a Christos Stavrakakis
                            # Server is still building in Ganeti
108 3524241a Christos Stavrakakis
                            continue
109 3524241a Christos Stavrakakis
                        else:
110 3524241a Christos Stavrakakis
                            c.GetInstance(utils.id_to_instance_name(i))
111 3524241a Christos Stavrakakis
                            # Server has just been created in Ganeti
112 3524241a Christos Stavrakakis
                            continue
113 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
114 4216cd83 Christos Stavrakakis
                        stale.add(i)
115 4161cb41 Christos Stavrakakis
        else:
116 4161cb41 Christos Stavrakakis
            stale.add(i)
117 4161cb41 Christos Stavrakakis
118 4161cb41 Christos Stavrakakis
    return stale
119 9fea53cc Vangelis Koukis
120 9fea53cc Vangelis Koukis
121 9fea53cc Vangelis Koukis
def orphan_instances_in_ganeti(D, G):
122 9fea53cc Vangelis Koukis
    idD = set(D.keys())
123 9fea53cc Vangelis Koukis
    idG = set(G.keys())
124 9fea53cc Vangelis Koukis
125 9fea53cc Vangelis Koukis
    return idG - idD
126 9fea53cc Vangelis Koukis
127 9fea53cc Vangelis Koukis
128 9fea53cc Vangelis Koukis
def unsynced_operstate(D, G):
129 9fea53cc Vangelis Koukis
    unsynced = set()
130 9fea53cc Vangelis Koukis
    idD = set(D.keys())
131 9fea53cc Vangelis Koukis
    idG = set(G.keys())
132 9fea53cc Vangelis Koukis
133 9fea53cc Vangelis Koukis
    for i in idD & idG:
134 c4e45b57 Christos Stavrakakis
        vm_unsynced = (G[i] and D[i] != "STARTED") or\
135 c4e45b57 Christos Stavrakakis
                      (not G[i] and D[i] not in ('BUILD', 'ERROR', 'STOPPED'))
136 c4e45b57 Christos Stavrakakis
        if vm_unsynced:
137 9fea53cc Vangelis Koukis
            unsynced.add((i, D[i], G[i]))
138 4161cb41 Christos Stavrakakis
        if not G[i] and D[i] == 'BUILD':
139 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
140 e63050ca Christos Stavrakakis
            if needs_reconciliation(vm):
141 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
142 4216cd83 Christos Stavrakakis
                    try:
143 3524241a Christos Stavrakakis
                        job_info = c.GetJobStatus(job_id=vm.backendjobid)
144 3524241a Christos Stavrakakis
                        if job_info['status'] == 'success':
145 3524241a Christos Stavrakakis
                            unsynced.add((i, D[i], G[i]))
146 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
147 4216cd83 Christos Stavrakakis
                        pass
148 9fea53cc Vangelis Koukis
149 9fea53cc Vangelis Koukis
    return unsynced
150 9fea53cc Vangelis Koukis
151 9fea53cc Vangelis Koukis
152 4161cb41 Christos Stavrakakis
def instances_with_build_errors(D, G):
153 4161cb41 Christos Stavrakakis
    failed = set()
154 4161cb41 Christos Stavrakakis
    idD = set(D.keys())
155 4161cb41 Christos Stavrakakis
    idG = set(G.keys())
156 4161cb41 Christos Stavrakakis
157 4161cb41 Christos Stavrakakis
    for i in idD & idG:
158 4161cb41 Christos Stavrakakis
        if not G[i] and D[i] == 'BUILD':
159 4161cb41 Christos Stavrakakis
            vm = VirtualMachine.objects.get(id=i)
160 1ad47ca5 Christos Stavrakakis
            if not vm.backendjobid:  # VM has not been enqueued in the backend
161 1ad47ca5 Christos Stavrakakis
                if datetime.now() > vm.created + timedelta(seconds=120):
162 1ad47ca5 Christos Stavrakakis
                    # If a job has not been enqueued after 2 minutues, then
163 1ad47ca5 Christos Stavrakakis
                    # it must be a stale entry..
164 1ad47ca5 Christos Stavrakakis
                    failed.add(i)
165 e63050ca Christos Stavrakakis
            elif needs_reconciliation(vm):
166 1ad47ca5 Christos Stavrakakis
                # Check time to avoid many rapi calls
167 4216cd83 Christos Stavrakakis
                with pooled_rapi_client(vm) as c:
168 4216cd83 Christos Stavrakakis
                    try:
169 3524241a Christos Stavrakakis
                        job_info = c.GetJobStatus(job_id=vm.backendjobid)
170 3524241a Christos Stavrakakis
                        if job_info['status'] == 'error':
171 3524241a Christos Stavrakakis
                            failed.add(i)
172 4216cd83 Christos Stavrakakis
                    except GanetiApiError:
173 4216cd83 Christos Stavrakakis
                        failed.add(i)
174 4161cb41 Christos Stavrakakis
175 4161cb41 Christos Stavrakakis
    return failed
176 4161cb41 Christos Stavrakakis
177 4161cb41 Christos Stavrakakis
178 e77a29ab Christos Stavrakakis
def get_servers_from_db(backends):
179 c414bc87 Christos Stavrakakis
    vms = VirtualMachine.objects.filter(deleted=False, backend__in=backends)
180 9fea53cc Vangelis Koukis
    return dict(map(lambda x: (x.id, x.operstate), vms))
181 9fea53cc Vangelis Koukis
182 9fea53cc Vangelis Koukis
183 e77a29ab Christos Stavrakakis
def get_instances_from_ganeti(backends):
184 e77a29ab Christos Stavrakakis
    instances = []
185 e77a29ab Christos Stavrakakis
    for backend in backends:
186 e77a29ab Christos Stavrakakis
        instances.append(get_instances(backend))
187 e77a29ab Christos Stavrakakis
    ganeti_instances = reduce(list.__add__, instances, [])
188 9fea53cc Vangelis Koukis
    snf_instances = {}
189 c6ad2f2d Christos Stavrakakis
    snf_nics = {}
190 9fea53cc Vangelis Koukis
191 9fea53cc Vangelis Koukis
    prefix = settings.BACKEND_PREFIX_ID
192 9fea53cc Vangelis Koukis
    for i in ganeti_instances:
193 9fea53cc Vangelis Koukis
        if i['name'].startswith(prefix):
194 9fea53cc Vangelis Koukis
            try:
195 d30f29aa Christos Stavrakakis
                id = utils.id_from_instance_name(i['name'])
196 9fea53cc Vangelis Koukis
            except Exception:
197 9e98ba3c Giorgos Verigakis
                log.error("Ignoring instance with malformed name %s",
198 cc92b70f Christos Stavrakakis
                          i['name'])
199 9fea53cc Vangelis Koukis
                continue
200 9fea53cc Vangelis Koukis
201 9fea53cc Vangelis Koukis
            if id in snf_instances:
202 9e98ba3c Giorgos Verigakis
                log.error("Ignoring instance with duplicate Synnefo id %s",
203 cc92b70f Christos Stavrakakis
                          i['name'])
204 9fea53cc Vangelis Koukis
                continue
205 9fea53cc Vangelis Koukis
206 9fea53cc Vangelis Koukis
            snf_instances[id] = i['oper_state']
207 c6ad2f2d Christos Stavrakakis
            snf_nics[id] = get_nics_from_instance(i)
208 9fea53cc Vangelis Koukis
209 c6ad2f2d Christos Stavrakakis
    return snf_instances, snf_nics
210 9fea53cc Vangelis Koukis
211 cc92b70f Christos Stavrakakis
212 0e9a423f Christos Stavrakakis
#
213 0e9a423f Christos Stavrakakis
# Nics
214 0e9a423f Christos Stavrakakis
#
215 e77a29ab Christos Stavrakakis
def get_nics_from_ganeti(backends):
216 0e9a423f Christos Stavrakakis
    """Get network interfaces for each ganeti instance.
217 0e9a423f Christos Stavrakakis

218 0e9a423f Christos Stavrakakis
    """
219 e77a29ab Christos Stavrakakis
    instances = []
220 e77a29ab Christos Stavrakakis
    for backend in backends:
221 e77a29ab Christos Stavrakakis
        instances.append(get_instances(backend))
222 e77a29ab Christos Stavrakakis
    instances = reduce(list.__add__, instances, [])
223 0e9a423f Christos Stavrakakis
    prefix = settings.BACKEND_PREFIX_ID
224 0e9a423f Christos Stavrakakis
225 0e9a423f Christos Stavrakakis
    snf_instances_nics = {}
226 0e9a423f Christos Stavrakakis
    for i in instances:
227 0e9a423f Christos Stavrakakis
        if i['name'].startswith(prefix):
228 0e9a423f Christos Stavrakakis
            try:
229 d30f29aa Christos Stavrakakis
                id = utils.id_from_instance_name(i['name'])
230 0e9a423f Christos Stavrakakis
            except Exception:
231 0e9a423f Christos Stavrakakis
                log.error("Ignoring instance with malformed name %s",
232 cc92b70f Christos Stavrakakis
                          i['name'])
233 0e9a423f Christos Stavrakakis
                continue
234 0e9a423f Christos Stavrakakis
            if id in snf_instances_nics:
235 0e9a423f Christos Stavrakakis
                log.error("Ignoring instance with duplicate Synnefo id %s",
236 cc92b70f Christos Stavrakakis
                          i['name'])
237 0e9a423f Christos Stavrakakis
                continue
238 0e9a423f Christos Stavrakakis
239 c6ad2f2d Christos Stavrakakis
            snf_instances_nics[id] = get_nics_from_instance(i)
240 0e9a423f Christos Stavrakakis
241 0e9a423f Christos Stavrakakis
    return snf_instances_nics
242 0e9a423f Christos Stavrakakis
243 0e9a423f Christos Stavrakakis
244 c6ad2f2d Christos Stavrakakis
def get_nics_from_instance(i):
245 c6ad2f2d Christos Stavrakakis
    ips = zip(itertools.repeat('ipv4'), i['nic.ips'])
246 c6ad2f2d Christos Stavrakakis
    macs = zip(itertools.repeat('mac'), i['nic.macs'])
247 c6ad2f2d Christos Stavrakakis
    networks = zip(itertools.repeat('network'), i['nic.networks'])
248 c6ad2f2d Christos Stavrakakis
    # modes = zip(itertools.repeat('mode'), i['nic.modes'])
249 c6ad2f2d Christos Stavrakakis
    # links = zip(itertools.repeat('link'), i['nic.links'])
250 c6ad2f2d Christos Stavrakakis
    # nics = zip(ips,macs,modes,networks,links)
251 c6ad2f2d Christos Stavrakakis
    nics = zip(ips, macs, networks)
252 c6ad2f2d Christos Stavrakakis
    nics = map(lambda x: dict(x), nics)
253 c6ad2f2d Christos Stavrakakis
    nics = dict(enumerate(nics))
254 c6ad2f2d Christos Stavrakakis
    return nics
255 c6ad2f2d Christos Stavrakakis
256 c6ad2f2d Christos Stavrakakis
257 e77a29ab Christos Stavrakakis
def get_nics_from_db(backends):
258 0e9a423f Christos Stavrakakis
    """Get network interfaces for each vm in DB.
259 0e9a423f Christos Stavrakakis

260 0e9a423f Christos Stavrakakis
    """
261 c414bc87 Christos Stavrakakis
    instances = VirtualMachine.objects.filter(deleted=False,
262 c414bc87 Christos Stavrakakis
                                              backend__in=backends)
263 0e9a423f Christos Stavrakakis
    instances_nics = {}
264 0e9a423f Christos Stavrakakis
    for instance in instances:
265 0e9a423f Christos Stavrakakis
        nics = {}
266 0e9a423f Christos Stavrakakis
        for n in instance.nics.all():
267 0e9a423f Christos Stavrakakis
            ipv4 = n.ipv4
268 0e9a423f Christos Stavrakakis
            nic = {'mac':      n.mac,
269 0e9a423f Christos Stavrakakis
                   'network':  n.network.backend_id,
270 0e9a423f Christos Stavrakakis
                   'ipv4':     ipv4 if ipv4 != '' else None
271 0e9a423f Christos Stavrakakis
                   }
272 0e9a423f Christos Stavrakakis
            nics[n.index] = nic
273 0e9a423f Christos Stavrakakis
        instances_nics[instance.id] = nics
274 0e9a423f Christos Stavrakakis
    return instances_nics
275 0e9a423f Christos Stavrakakis
276 0e9a423f Christos Stavrakakis
277 0e9a423f Christos Stavrakakis
def unsynced_nics(DBNics, GNics):
278 0e9a423f Christos Stavrakakis
    """Find unsynced network interfaces between DB and Ganeti.
279 0e9a423f Christos Stavrakakis

280 0e9a423f Christos Stavrakakis
    @ rtype: dict; {instance_id: ganeti_nics}
281 0e9a423f Christos Stavrakakis
    @ return Dictionary containing the instances ids that have unsynced network
282 0e9a423f Christos Stavrakakis
    interfaces between DB and Ganeti and the network interfaces in Ganeti.
283 0e9a423f Christos Stavrakakis

284 0e9a423f Christos Stavrakakis
    """
285 0e9a423f Christos Stavrakakis
    idD = set(DBNics.keys())
286 0e9a423f Christos Stavrakakis
    idG = set(GNics.keys())
287 0e9a423f Christos Stavrakakis
288 0e9a423f Christos Stavrakakis
    unsynced = {}
289 0e9a423f Christos Stavrakakis
    for i in idD & idG:
290 0e9a423f Christos Stavrakakis
        nicsD = DBNics[i]
291 0e9a423f Christos Stavrakakis
        nicsG = GNics[i]
292 0e9a423f Christos Stavrakakis
        if len(nicsD) != len(nicsG):
293 0e9a423f Christos Stavrakakis
            unsynced[i] = (nicsD, nicsG)
294 0e9a423f Christos Stavrakakis
            continue
295 0e9a423f Christos Stavrakakis
        for index in nicsG.keys():
296 0e9a423f Christos Stavrakakis
            nicD = nicsD[index]
297 0e9a423f Christos Stavrakakis
            nicG = nicsG[index]
298 c4e45b57 Christos Stavrakakis
            diff = (nicD['ipv4'] != nicG['ipv4'] or
299 c4e45b57 Christos Stavrakakis
                    nicD['mac'] != nicG['mac'] or
300 c4e45b57 Christos Stavrakakis
                    nicD['network'] != nicG['network'])
301 c4e45b57 Christos Stavrakakis
            if diff:
302 cc92b70f Christos Stavrakakis
                    unsynced[i] = (nicsD, nicsG)
303 cc92b70f Christos Stavrakakis
                    break
304 0e9a423f Christos Stavrakakis
305 0e9a423f Christos Stavrakakis
    return unsynced
306 0e9a423f Christos Stavrakakis
307 0e9a423f Christos Stavrakakis
#
308 0e9a423f Christos Stavrakakis
# Networks
309 0e9a423f Christos Stavrakakis
#
310 3524241a Christos Stavrakakis
311 3524241a Christos Stavrakakis
312 0e9a423f Christos Stavrakakis
def get_networks_from_ganeti(backend):
313 44e2c577 Christos Stavrakakis
    prefix = settings.BACKEND_PREFIX_ID + 'net-'
314 0e9a423f Christos Stavrakakis
315 0e9a423f Christos Stavrakakis
    networks = {}
316 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
317 3524241a Christos Stavrakakis
        for net in c.GetNetworks(bulk=True):
318 3524241a Christos Stavrakakis
            if net['name'].startswith(prefix):
319 3524241a Christos Stavrakakis
                id = utils.id_from_network_name(net['name'])
320 3524241a Christos Stavrakakis
                networks[id] = net
321 0e9a423f Christos Stavrakakis
322 0e9a423f Christos Stavrakakis
    return networks
323 0e9a423f Christos Stavrakakis
324 0e9a423f Christos Stavrakakis
325 0e9a423f Christos Stavrakakis
def hanging_networks(backend, GNets):
326 0e9a423f Christos Stavrakakis
    """Get networks that are not connected to all Nodegroups.
327 0e9a423f Christos Stavrakakis

328 0e9a423f Christos Stavrakakis
    """
329 0e9a423f Christos Stavrakakis
    def get_network_groups(group_list):
330 0e9a423f Christos Stavrakakis
        groups = set()
331 0e9a423f Christos Stavrakakis
        for g in group_list:
332 0e9a423f Christos Stavrakakis
            g_name = g.split('(')[0]
333 0e9a423f Christos Stavrakakis
            groups.add(g_name)
334 0e9a423f Christos Stavrakakis
        return groups
335 0e9a423f Christos Stavrakakis
336 3524241a Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
337 3524241a Christos Stavrakakis
        groups = set(c.GetGroups())
338 0e9a423f Christos Stavrakakis
339 0e9a423f Christos Stavrakakis
    hanging = {}
340 0e9a423f Christos Stavrakakis
    for id, info in GNets.items():
341 0e9a423f Christos Stavrakakis
        group_list = get_network_groups(info['group_list'])
342 0e9a423f Christos Stavrakakis
        if group_list != groups:
343 0e9a423f Christos Stavrakakis
            hanging[id] = groups - group_list
344 0e9a423f Christos Stavrakakis
    return hanging
345 0e9a423f Christos Stavrakakis
346 9fea53cc Vangelis Koukis
347 a65ee5fc Vangelis Koukis
# Only for testing this module individually
348 9fea53cc Vangelis Koukis
def main():
349 9fea53cc Vangelis Koukis
    print get_instances_from_ganeti()
350 9fea53cc Vangelis Koukis
351 9fea53cc Vangelis Koukis
352 9fea53cc Vangelis Koukis
if __name__ == "__main__":
353 9fea53cc Vangelis Koukis
    sys.exit(main())