Revision 0e0a6ef9
b/snf-cyclades-app/synnefo/db/models.py | ||
---|---|---|
532 | 532 |
if not backend_exists: |
533 | 533 |
BackendNetwork.objects.create(backend=backend, network=self) |
534 | 534 |
|
535 |
def get_pool(self, locked=True): |
|
536 |
try: |
|
537 |
subnet = self.subnets.get(ipversion=4, deleted=False) |
|
538 |
except Subnet.DoesNotExist: |
|
539 |
raise pools.EmptyPool |
|
540 |
return subnet.get_pool(locked=locked) |
|
541 |
|
|
542 |
def allocate_address(self, userid): |
|
543 |
try: |
|
544 |
subnet = self.subnets.get(ipversion=4, deleted=False) |
|
545 |
except Subnet.DoesNotExist: |
|
546 |
raise pools.EmptyPool |
|
547 |
return subnet.allocate_address(userid) |
|
535 |
def get_ip_pools(self, locked=True): |
|
536 |
subnets = self.subnets.filter(ipversion=4, deleted=False)\ |
|
537 |
.prefetch_related("ip_pools") |
|
538 |
return [ip_pool for subnet in subnets |
|
539 |
for ip_pool in subnet.get_ip_pools(locked=locked)] |
|
548 | 540 |
|
549 | 541 |
def reserve_address(self, address, external=False): |
550 |
pool = self.get_pool() |
|
551 |
pool.reserve(address, external=external) |
|
552 |
pool.save() |
|
542 |
for ip_pool in self.get_ip_pools(): |
|
543 |
if ip_pool.contains(address): |
|
544 |
ip_pool.reserve(address, external=external) |
|
545 |
ip_pool.save() |
|
546 |
return |
|
547 |
raise pools.InvalidValue("Network %s does not have an IP pool that" |
|
548 |
" contains address %s" % (self, address)) |
|
553 | 549 |
|
554 | 550 |
def release_address(self, address, external=True): |
555 |
pool = self.get_pool() |
|
556 |
pool.put(address, external=external) |
|
557 |
pool.save() |
|
551 |
for ip_pool in self.get_ip_pools(): |
|
552 |
if ip_pool.contains(address): |
|
553 |
ip_pool.release(address, external=external) |
|
554 |
ip_pool.save() |
|
555 |
return |
|
556 |
raise pools.InvalidValue("Network %s does not have an IP pool that" |
|
557 |
" contains address %s" % (self, address)) |
|
558 | 558 |
|
559 | 559 |
@property |
560 | 560 |
def subnet4(self): |
... | ... | |
571 | 571 |
|
572 | 572 |
def ip_count(self): |
573 | 573 |
"""Return the total and free IPv4 addresses of the network.""" |
574 |
subnets = self.subnets.filter(ipversion=4).prefetch_related("ip_pools") |
|
575 | 574 |
total, free = 0, 0 |
576 |
for subnet in subnets: |
|
577 |
for ip_pool in subnet.ip_pools.all(): |
|
578 |
pool = ip_pool.pool |
|
579 |
total += pool.pool_size |
|
580 |
free += pool.count_available() |
|
575 |
ip_pools = self.get_ip_pools(locked=False) |
|
576 |
for ip_pool in ip_pools: |
|
577 |
total += ip_pool.pool_size |
|
578 |
free += ip_pool.count_available() |
|
581 | 579 |
return total, free |
582 | 580 |
|
583 | 581 |
class InvalidBackendIdError(Exception): |
... | ... | |
624 | 622 |
msg = u"<Subnet %s, Network: %s, CIDR: %s>" |
625 | 623 |
return msg % (self.id, self.network_id, self.cidr) |
626 | 624 |
|
627 |
def get_pool(self, locked=True): |
|
628 |
if self.ipversion == 6: |
|
629 |
raise Exception("IPv6 Subnets have no IP Pool.") |
|
625 |
def get_ip_pools(self, locked=True): |
|
630 | 626 |
ip_pools = self.ip_pools |
631 | 627 |
if locked: |
632 | 628 |
ip_pools = ip_pools.select_for_update() |
633 |
return ip_pools.all()[0].pool |
|
634 |
|
|
635 |
def allocate_address(self, userid): |
|
636 |
pool = self.get_pool(locked=True) |
|
637 |
address = pool.get() |
|
638 |
pool.save() |
|
639 |
return IPAddress.objects.create(network=self.network, subnet=self, |
|
640 |
address=address, userid=userid) |
|
629 |
return map(lambda ip_pool: ip_pool.pool, ip_pools.all()) |
|
641 | 630 |
|
642 | 631 |
|
643 | 632 |
class BackendNetwork(models.Model): |
b/snf-cyclades-app/synnefo/logic/reconciliation.py | ||
---|---|---|
508 | 508 |
corresponding Ganeti networks in all Ganeti backends. |
509 | 509 |
|
510 | 510 |
""" |
511 |
network_ip_pool = network.get_pool() # X-Lock on IP Pool
|
|
511 |
ip_pools = network.get_ip_pools() # X-Lock on IP pools
|
|
512 | 512 |
for bend in self.backends: |
513 | 513 |
bnet = get_backend_network(network, bend) |
514 | 514 |
gnet = self.ganeti_networks[bend].get(network.id) |
... | ... | |
563 | 563 |
if externally_reserved: |
564 | 564 |
for ip in externally_reserved.split(","): |
565 | 565 |
ip = ip.strip() |
566 |
if not network_ip_pool.is_reserved(ip): |
|
567 |
msg = ("D: IP '%s' is reserved for network '%s' in" |
|
568 |
" backend '%s' but not in DB.") |
|
569 |
self.log.info(msg, ip, network, bend) |
|
570 |
if self.fix: |
|
571 |
network_ip_pool.reserve(ip, external=True) |
|
572 |
network_ip_pool.save() |
|
573 |
self.log.info("F: Reserved IP '%s'", ip) |
|
566 |
for ip_pool in ip_pools: |
|
567 |
if ip_pool.contains(ip): |
|
568 |
if not ip_pool.is_reserved(ip): |
|
569 |
msg = ("D: IP '%s' is reserved for network" |
|
570 |
" '%s' in backend '%s' but not in DB.") |
|
571 |
self.log.info(msg, ip, network, bend) |
|
572 |
if self.fix: |
|
573 |
ip_pool.reserve(ip, external=True) |
|
574 |
ip_pool.save() |
|
575 |
self.log.info("F: Reserved IP '%s'", ip) |
|
574 | 576 |
|
575 | 577 |
def reconcile_parted_network(self, network, backend): |
576 | 578 |
self.log.info("D: Missing DB entry for network %s in backend %s", |
... | ... | |
699 | 701 |
@transaction.commit_on_success |
700 | 702 |
def reconcile_ip_pool(self, network): |
701 | 703 |
# Check that all NICs have unique IPv4 address |
702 |
nics = network.nics.filter(ipv4__isnull=False) |
|
703 |
check_unique_values(objects=nics, field='ipv4', logger=self.log) |
|
704 |
|
|
705 |
# Check that all Floating IPs have unique IPv4 address |
|
706 |
floating_ips = network.floating_ips.filter(deleted=False) |
|
707 |
check_unique_values(objects=floating_ips, field='ipv4', |
|
708 |
logger=self.log) |
|
709 |
|
|
710 |
# First get(lock) the IP pool of the network to prevent new NICs |
|
711 |
# from being created. |
|
712 |
network_ip_pool = network.get_pool() |
|
713 |
used_ips = set(list(nics.values_list("ipv4", flat=True)) + |
|
714 |
list(floating_ips.values_list("ipv4", flat=True))) |
|
715 |
|
|
716 |
check_pool_consistent(pool=network_ip_pool, |
|
717 |
pool_class=pools.IPPool, |
|
718 |
used_values=used_ips, |
|
719 |
fix=self.fix, logger=self.log) |
|
704 |
nics = network.ips.all() |
|
705 |
check_unique_values(objects=nics, field="address", logger=self.log) |
|
706 |
|
|
707 |
for ip_pool in network.get_ip_pools(): |
|
708 |
used_ips = ip_pool.pool_table.subnet.ips.values_list("address", |
|
709 |
flat=True) |
|
710 |
used_ips = filter(lambda x: ip_pool.contains(x), used_ips) |
|
711 |
check_pool_consistent(pool=ip_pool, |
|
712 |
pool_class=pools.IPPool, |
|
713 |
used_values=used_ips, |
|
714 |
fix=self.fix, logger=self.log) |
|
720 | 715 |
|
721 | 716 |
|
722 | 717 |
def check_unique_values(objects, field, logger): |
Also available in: Unified diff