Revision c55b0cdc snf-cyclades-app/synnefo/logic/management/commands/reconcile-networks.py
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() |
Also available in: Unified diff