automatically assign unused subnet address
[plstackapi.git] / planetstack / core / models / network.py
index a579490..be13ea7 100644 (file)
@@ -1,36 +1,78 @@
 import os
+import socket
 from django.db import models
-from core.models import PlCoreBase
-from core.models import Site
-from core.models import Deployment
+from core.models import PlCoreBase, Site, Slice, Sliver
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
 
 # Create your models here.
 
+SUBNET_BASE = "10.0.0.0"
+SUBNET_NODE_BITS = 12     # enough for 4096 bits per subnet
+SUBNET_SUBNET_BITS = 12   # enough for 4096 private networks
+
+def find_unused_subnet(base, subnet_bits, node_bits, existing_subnets):
+    i=0
+    while True:
+        subnet_i = (i<<node_bits) | int(socket.inet_aton(base).encode('hex'),16)
+        subnet = socket.inet_ntoa(hex(subnet_i)[2:].zfill(8).decode('hex')) + "/" + str(32-node_bits)
+        if (subnet not in existing_subnets):
+            return subnet
+        i=i+1
+
+class NetworkTemplate(PlCoreBase):
+    VISIBILITY_CHOICES = (('public', 'public'), ('private', 'private'))
+
+    name = models.CharField(max_length=32)
+    guaranteedBandwidth = models.IntegerField(default=0)
+    visibility = models.CharField(max_length=30, choices=VISIBILITY_CHOICES, default="private")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
 class Network(PlCoreBase):
     name = models.CharField(max_length=32)
-    subnet = models.CharField(max_length=32)
+    template = models.ForeignKey(NetworkTemplate)
+    subnet = models.CharField(max_length=32, blank=True, null=True)
     ports = models.CharField(max_length=1024)
     labels = models.CharField(max_length=1024)
     slice = models.ForeignKey(Slice, related_name="networks")
-    guaranteedBandwidth = models.IntField()
+
+    guaranteedBandwidth = models.IntegerField(default=0)
     permittedSlices = models.ManyToManyField(Slice, blank=True, related_name="permittedNetworks")
-    boundSlices = models.ManyToManyField(Slice, blank=True, related_name="boundNetworks")
+    boundSlivers = models.ManyToManyField(Sliver, blank=True, related_name="boundNetworks", through="NetworkSliver")
 
     def __unicode__(self):  return u'%s' % (self.name)
 
+    def allocateSubnet(self):
+        existingSubnets = [x.subnet for x in Network.objects.all()]
+        return find_unused_subnet(SUBNET_BASE, SUBNET_SUBNET_BITS, SUBNET_NODE_BITS, existingSubnets)
+
+    def save(self, *args, **kwds):
+        if not self.subnet:
+            self.subnet = self.allocateSubnet()
+        super(Network, self).save(*args, **kwds)
+
+class NetworkSliver(PlCoreBase):
+    network = models.ForeignKey(Network)
+    sliver = models.ForeignKey(Sliver)
+    ip = models.GenericIPAddressField(help_text="Sliver ip address", blank=True, null=True)
+
+    def __unicode__(self):  return u'foo!'
+
 class Router(PlCoreBase):
     name = models.CharField(max_length=32)
+    owner = models.ForeignKey(Slice, related_name="routers")
     networks = models.ManyToManyField(Network, blank=True, related_name="routers")
 
-    def __unicode__(self):  return u'%s' % (self.name)o
+    def __unicode__(self):  return u'%s' % (self.name)
 
-class ParameterType(PlCoreBase):
+class NetworkParameterType(PlCoreBase):
     name = models.SlugField(help_text="The name of this tag", max_length=128)
 
     def __unicode__(self):  return u'%s' % (self.name)
 
-class Parameter(PlCoreBase):
-    parameterType = models.ForeignKey(ParameterType, related_name="parameters", help_text="The name of the parameter")
+class NetworkParameter(PlCoreBase):
+    networkParameterType = models.ForeignKey(NetworkParameterType, related_name="parameters", help_text="The name of the parameter")
     value = models.CharField(help_text="The value of this parameter", max_length=1024)
 
     # The required fields to do a ObjectType lookup, and object_id assignment
@@ -39,6 +81,6 @@ class Parameter(PlCoreBase):
     content_object = generic.GenericForeignKey('content_type', 'object_id')
 
     def __unicode__(self):
-        return self.tagType.name
+        return self.networkParameterType.name