Revision c55b0cdc

b/snf-cyclades-app/synnefo/logic/management/commands/reconcile-networks.py
35 35

  
36 36
"""
37 37
import datetime
38
import bitarray
38 39

  
39 40
from optparse import make_option
40 41

  
41
from django.conf import settings
42
from django.core.management.base import BaseCommand, CommandError
42
from django.core.management.base import BaseCommand
43
from django.db import transaction
43 44

  
44 45
from synnefo.db.models import Backend, Network, BackendNetwork
45 46
from synnefo.logic import reconciliation, backend, utils
46 47

  
47 48

  
48 49
class Command(BaseCommand):
49
    can_import_settings = True
50

  
51 50
    help = 'Reconcile contents of Synnefo DB with state of Ganeti backend'
52 51
    output_transaction = True  # The management command runs inside
53 52
                               # an SQL transaction
......
55 54
        make_option('--fix-all', action='store_true',
56 55
                    dest='fix', default=False,
57 56
                    help='Fix all issues.'),
57
        make_option('--conflicting-ips', action='store_true',
58
                    dest='conflicting_ips', default=False,
59
                    help='Detect conflicting ips')
58 60
        )
59 61

  
60 62
    def handle(self, **options):
61 63
        self.verbosity = int(options['verbosity'])
62 64
        fix = options['fix']
63
        reconcile_networks(self.stdout, fix)
65
        conflicting_ips = options['conflicting_ips']
66
        reconcile_networks(self.stdout, fix, conflicting_ips)
64 67

  
65 68

  
66
def reconcile_networks(out, fix):
69
def reconcile_networks(out, fix, conflicting_ips):
67 70
    # Get models from DB
68 71
    backends = Backend.objects.exclude(offline=True)
69 72
    networks = Network.objects.filter(deleted=False)
......
81 84
    for network in networks:
82 85
        net_id = network.id
83 86
        destroying = network.action == 'DESTROY'
87
        ip_address_maps = []
84 88

  
85 89
        # Perform reconcilliation for each backend
86 90
        for b in backends:
......
149 153
                                        0, 'OP_NETWORK_CONNECT', 'success',
150 154
                                        'Reconciliation simulated event.')
151 155

  
156
            # Reconcile IP Pools
157
            ip_map = ganeti_networks[b][net_id]['map']
158
            ip_address_maps.append(bitarray_from_o1(ip_map))
159

  
160
        network_bitarray = reduce(lambda x, y: x | y, ip_address_maps)
161
        if not network.pool.reservations == network_bitarray:
162
            out.write('D: Unsynced pool of network %d\n' % net_id)
163
            out.write('\t DB:\t%s\n' % network.pool.reservations.to01())
164
            out.write('\t Ganeti:%s\n' % network_bitarray.to01())
165
            if fix:
166
                update_network_reservations(network, network_bitarray)
167
                out.write('F: Synchronized network pools\n')
168

  
169
        # Detect conflicting IPs: Detect NIC's that have the same IP
170
        # in the same network.
171
        if conflicting_ips:
172
            machine_ips = network.nics.all().values_list('ipv4', 'machine')
173
            ips = map(lambda x: x[0], machine_ips)
174
            distinct_ips = set(ips)
175
            if len(distinct_ips) < len(ips):
176
                out.write('D: Conflicting IP in network %s.\n' % net_id)
177
                conflicts = ips
178
                for i in distinct_ips:
179
                    conflicts.remove(i)
180
                for i in conflicts:
181
                    machines = [utils.id_to_instance_name(x[1]) \
182
                                for x in machine_ips if x[0] == i]
183
                    out.write('\tIP:%s Machines: %s\n' %
184
                              (i, ', '.join(machines)))
185
                if fix:
186
                    out.write('F: Can not fix it. Manually resolve the'
187
                              ' conflict.\n')
188

  
152 189
    # Detect Orphan Networks in Ganeti
153 190
    db_network_ids = set([net.id for net in networks])
154 191
    for back_end, ganeti_networks in ganeti_networks.items():
......
167 204
                    for group in client.GetGroups():
168 205
                        client.DisconnectNetwork(network, group)
169 206
                        client.DeleteNetwork(network)
207

  
208

  
209
def bitarray_from_o1(bitmap):
210
    return bitarray.bitarray(bitmap.replace("X", "1").replace(".", "0"))
211

  
212

  
213
@transaction.commit_on_success
214
def update_network_reservations(network, reservations):
215
    network.pool.reservations = reservations
216
    network.pool.save()
b/snf-cyclades-app/synnefo/logic/utils.py
50 50

  
51 51

  
52 52
def id_to_instance_name(id):
53
    return "%s%s" (settings.BACKEND_PREFIX_ID, str(id))
53
    return "%s%s" % (settings.BACKEND_PREFIX_ID, str(id))
54 54

  
55 55

  
56 56
def id_from_network_name(name):

Also available in: Unified diff