|
@@ -1,7 +1,8 @@
|
|
|
|
|
|
from django.db import models
|
|
|
+from django.core.exceptions import ValidationError
|
|
|
from netfields import CidrAddressField, NetManager
|
|
|
-
|
|
|
+from netaddr import IPNetwork, IPSet
|
|
|
|
|
|
class IPPool(models.Model):
|
|
|
"""Pool of IP addresses (either v4 or v6)."""
|
|
@@ -17,11 +18,37 @@ class IPPool(models.Model):
|
|
|
|
|
|
|
|
|
class IPSubnet(models.Model):
|
|
|
- inet = CidrAddressField()
|
|
|
+ inet = CidrAddressField(blank=True, verbose_name="Leave empty for automatic allocation")
|
|
|
objects = NetManager()
|
|
|
ip_pool = models.ForeignKey(IPPool)
|
|
|
offer_subscription = models.ForeignKey('offers.OfferSubscription',
|
|
|
related_name='ip_subnet')
|
|
|
|
|
|
+ def clean(self):
|
|
|
+
|
|
|
+
|
|
|
+ if not self.inet:
|
|
|
+
|
|
|
+ pool = IPSet([self.ip_pool.inet])
|
|
|
+ used = IPSet((s.inet for s in self.ip_pool.ipsubnet_set.all()))
|
|
|
+ free = pool.difference(used)
|
|
|
+ SUBNET_SIZE = 32 if self.ip_pool.inet.version == 4 else 56
|
|
|
+
|
|
|
+ available = (p for p in free.iter_cidrs() if p.prefixlen <= SUBNET_SIZE)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ try:
|
|
|
+ first_free = available.next()
|
|
|
+ except StopIteration:
|
|
|
+ raise ValidationError('Unable to allocate an IP subnet in the specified pool: not enough space left.')
|
|
|
+ self.inet = first_free.subnet(SUBNET_SIZE, 1).next()
|
|
|
+ else:
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ pass
|
|
|
+
|
|
|
def __unicode__(self):
|
|
|
return str(self.inet)
|