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()
|