def forwards(self): db.delete_column("ip_ipv4block", "prefix") db.add_column("ip_ipv4block", "prefix", CIDRField("prefix", null=True)) db.execute("UPDATE ip_ipv4block SET prefix=prefix_cidr") db.delete_column("ip_ipv4block", "prefix_cidr") db.execute("ALTER TABLE ip_ipv4block ALTER prefix SET NOT NULL") db.execute("DROP TRIGGER t_ip_ipv4block_modify ON ip_ipv4block") db.execute("DROP FUNCTION f_trigger_ip_ipv4block()") db.delete_column("ip_ipv4blockaccess", "prefix") db.add_column("ip_ipv4blockaccess", "prefix", CIDRField("prefix", null=True)) db.execute("UPDATE ip_ipv4blockaccess SET prefix=prefix_cidr") db.delete_column("ip_ipv4blockaccess", "prefix_cidr") db.execute("ALTER TABLE ip_ipv4blockaccess ALTER prefix SET NOT NULL") db.execute( "DROP TRIGGER t_ip_ipv4blockaccess_modify ON ip_ipv4blockaccess") db.execute("DROP FUNCTION f_trigger_ip_ipv4blockaccess()") db.execute(RAW_SQL)
class IPPool(models.Model): class Meta: verbose_name = _("IP Pool") verbose_name_plural = _("IP Pools") db_table = "ip_ippool" app_label = "ip" termination_group = models.ForeignKey(TerminationGroup, verbose_name=_("Termination Group")) name = models.CharField(_("Pool name"), max_length=64, default="default") vrf = models.ForeignKey(VRF, verbose_name=_("VRF")) afi = models.CharField(_("Address Family"), max_length=1, choices=AFI_CHOICES) type = models.CharField(_("Type"), max_length=1, choices=[("D", "Dynamic"), ("S", "Static")]) technologies = TextArrayField(_("Technologies"), default=["IPoE"]) from_address = CIDRField(_("From Address")) to_address = CIDRField(_("To Address")) def __unicode__(self): return u"%s %s %s %s -- %s" % (self.termination_group.name, self.type, self.name, self.from_address, self.to_address) def clean(self): """ Field validation """ print "@@@ CLEAN" super(IPPool, self).clean() # Check prefix is of AFI type if self.afi == "4": check_ipv4(self.from_address) check_ipv4(self.to_address) elif self.afi == "6": check_ipv6(self.from_address) check_ipv6(self.to_address)
class VCBindFilter(models.Model): class Meta: verbose_name = "VC Bind Filter" verbose_name_plural = "VC Bind Filters" db_table = "vc_vcbindfilter" app_label = "vc" vc_domain = models.ForeignKey(VCDomain, verbose_name="VC Domain") vrf = models.ForeignKey("ip.VRF", verbose_name="VRF") afi = models.CharField("Address Family", max_length=1, choices=AFI_CHOICES, default="4") prefix = CIDRField("Prefix") vc_filter = models.ForeignKey(VCFilter, verbose_name="VC Filter") def __unicode__(self): return u"%s %s %s %s" % (self.vc_domain, self.vrf, self.prefix, self.vc_filter) @classmethod def get_vcs(cls, vrf, afi, prefix): """ Returns queryset with all suitable VCs """ if hasattr(prefix, "prefix"): prefix = prefix.prefix c = connection.cursor() c.execute( """ SELECT v.id,v.l1,vf.id FROM vc_vcdomain d JOIN vc_vcbindfilter f ON (d.id=f.vc_domain_id) JOIN vc_vcfilter vf ON (f.vc_filter_id=vf.id) JOIN vc_vc v ON (v.vc_domain_id=d.id) WHERE f.vrf_id=%s AND f.afi=%s AND f.prefix>>=%s """, [vrf.id, afi, prefix]) vcs = set() # vc.id F = {} # id -> filter for vc_id, l1, vf_id in c.fetchall(): try: f = F[vf_id] except KeyError: f = VCFilter.objects.get(id=vf_id) F[vf_id] = f if f.check(l1): vcs.add(vc_id) return VC.objects.filter(id__in=vcs).order_by("l1")
class PrefixTablePrefix(models.Model): class Meta: verbose_name = _("Prefix") verbose_name_plural = _("Prefixes") db_table = "main_prefixtableprefix" unique_together = [("table", "afi", "prefix")] ordering = ["table", "afi", "prefix"] table = models.ForeignKey(PrefixTable, verbose_name=_("Prefix Table")) afi = models.CharField(_("Address Family"), max_length=1, choices=[("4", _("IPv4")), ("6", _("IPv6"))]) prefix = CIDRField(_("Prefix")) def __unicode__(self): return u"%s %s" % (self.table.name, self.prefix) def save(self, *args, **kwargs): # Set AFI self.afi = IP.prefix(self.prefix).afi return super(PrefixTablePrefix, self).save(*args, **kwargs)
class Prefix(models.Model): """ Allocated prefix """ class Meta: verbose_name = _("Prefix") verbose_name_plural = _("Prefixes") db_table = "ip_prefix" app_label = "ip" unique_together = [("vrf", "afi", "prefix")] parent = models.ForeignKey("self", related_name="children_set", verbose_name=_("Parent"), null=True, blank=True) vrf = models.ForeignKey(VRF, verbose_name=_("VRF"), default=VRF.get_global) afi = models.CharField(_("Address Family"), max_length=1, choices=AFI_CHOICES) prefix = CIDRField(_("Prefix")) asn = models.ForeignKey( AS, verbose_name=_("AS"), help_text=_("Autonomous system granted with prefix"), default=AS.default_as) project = models.ForeignKey(Project, verbose_name="Project", on_delete=models.SET_NULL, null=True, blank=True, related_name="prefix_set") vc = models.ForeignKey(VC, verbose_name=_("VC"), null=True, blank=True, on_delete=models.SET_NULL, help_text=_("VC bound to prefix")) description = models.TextField(_("Description"), blank=True, null=True) tags = TagsField("Tags", null=True, blank=True) tt = models.IntegerField("TT", blank=True, null=True, help_text=_("Ticket #")) style = models.ForeignKey(Style, verbose_name=_("Style"), blank=True, null=True) state = models.ForeignKey(ResourceState, verbose_name=_("State"), default=ResourceState.get_default) allocated_till = models.DateField( _("Allocated till"), null=True, blank=True, help_text=_("Prefix temporary allocated till the date")) ipv6_transition = models.OneToOneField("self", related_name="ipv4_transition", null=True, blank=True, limit_choices_to={"afi": "6"}, on_delete=models.SET_NULL) enable_ip_discovery = models.CharField(_("Enable IP Discovery"), max_length=1, choices=[("I", "Inherit"), ("E", "Enable"), ("D", "Disable")], default="I", blank=False, null=False) csv_ignored_fields = ["parent"] def __unicode__(self): return u"%s(%s): %s" % (self.vrf.name, self.afi, self.prefix) def get_absolute_url(self): return site.reverse("ip:ipam:vrf_index", self.vrf.id, self.afi, self.prefix) @property def has_transition(self): """ Check prefix has ipv4/ipv6 transition :return: """ if self.afi == "4": return bool(self.ipv6_transition) else: try: self.ipv4_transition return True except Prefix.DoesNotExist: return False def clear_transition(self): if self.has_transition: if self.afi == "4": self.ipv6_transition = None self.save() else: self.ipv4_transition.ipv6_transition = None self.ipv4_transition.save() @classmethod def get_parent(cls, vrf, afi, prefix): """ Get nearest closing prefix """ r = list( Prefix.objects.raw( """ SELECT id, prefix FROM ip_prefix WHERE vrf_id=%s AND afi=%s AND prefix >> %s ORDER BY masklen(prefix) DESC LIMIT 1 """, [vrf.id, str(afi), str(prefix)])) if not r: return None return r[0] @property def is_root(self): """ Returns true if the prefix is a root of VRF """ return (self.afi == "4" and self.prefix == "0.0.0.0/0") or (self.afi == "6" and self.prefix == "::/0") def clean(self): """ Field validation """ super(Prefix, self).clean() # Check prefix is of AFI type if self.afi == "4": check_ipv4_prefix(self.prefix) elif self.afi == "6": check_ipv6_prefix(self.prefix) # Check root prefix have no parent if self.is_root and self.parent: raise ValidationError("Root prefix cannot have parent") def save(self, **kwargs): """ Save prefix """ # Set defaults self.afi = "6" if ":" in self.prefix else "4" if not self.vrf: self.vrf = VRF.get_global() if not self.asn: self.asn = AS.default_as() if not self.is_root: # Set proper parent self.parent = Prefix.get_parent(self.vrf, self.afi, self.prefix) super(Prefix, self).save(**kwargs) # Rebuild tree if necessary # Reconnect children children prefixes c = connection.cursor() c.execute( """ UPDATE %s SET parent_id=%%s WHERE vrf_id=%%s AND afi=%%s AND prefix << %%s AND parent_id=%%s """ % Prefix._meta.db_table, [ self.id, self.vrf.id, self.afi, self.prefix, self.parent.id if self.parent else None ]) # Reconnect children addresses c.execute( """ UPDATE %s SET prefix_id=%%s WHERE prefix_id=%%s AND address << %%s """ % Address._meta.db_table, [self.id, self.parent.id if self.parent else None, self.prefix]) def delete(self, *args, **kwargs): """ Delete prefix """ if self.is_root: raise ValidationError("Cannot delete root prefix") # Reconnect children prefixes self.children_set.update(parent=self.parent) # Reconnect children addresses self.address_set.update(prefix=self.parent) # Unlink dual-stack allocations self.clear_transition() # Remove bookmarks self.prefixbookmark_set.all().delete() # Finally delete super(Prefix, self).delete(*args, **kwargs) def delete_recursive(self): """ Delete prefix and all descendancies """ # Unlink dual-stack allocations self.clear_transition() # Recursive delete # Get nested prefixes ids = Prefix.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["prefix <<= %s"], params=[self.prefix]).values_list("id", flat=True) # zones = set() for a in Address.objects.filter(prefix__in=ids): zones.add(a.address) zones.add(a.fqdn) # Delete nested addresses Address.objects.filter(prefix__in=ids).delete() # Delete nested prefixes Prefix.objects.filter(id__in=ids).delete() # Delete permissions PrefixAccess.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["prefix <<= %s"], params=[self.prefix]) # Touch dns zones for z in zones: DNSZone.touch(z) @property def maintainers(self): """ List of persons having write access @todo: PostgreSQL-independent implementation """ return User.objects.raw( """ SELECT id,username,first_name,last_name FROM %s u WHERE is_active=TRUE AND (is_superuser=TRUE OR EXISTS(SELECT id FROM %s a WHERE user_id=u.id AND vrf_id=%%s AND afi=%%s AND prefix>>=%%s AND can_change=TRUE )) ORDER BY username""" % (User._meta.db_table, PrefixAccess._meta.db_table), [self.vrf.id, self.afi, self.prefix]) ## ## First line of description ## @property def short_description(self): if self.description: return self.description.split("\n", 1)[0].strip() else: return "" ## ## Netmask for IPv4 ## @property def netmask(self): if self.afi == "4": return IPv4(self.prefix).netmask.address else: return None ## ## Broadcast for IPv4 ## @property def broadcast(self): if self.afi == "4": return IPv4(self.prefix).last.address else: return None ## ## Cisco wildcard for IPv4 ## @property def wildcard(self): if self.afi == "4": return IPv4(self.prefix).wildcard.address else: return "" ## ## IPv4 prefix size ## @property def size(self): if self.afi == "4": return IPv4(self.prefix).size else: return None ## ## Return True if user has view access ## def can_view(self, user): return PrefixAccess.user_can_view(user, self.vrf, self.afi, self.prefix) ## ## Return True if user has change access ## def can_change(self, user): return PrefixAccess.user_can_change(user, self.vrf, self.afi, self.prefix) ## ## Check the user has bookmark on prefix ## def has_bookmark(self, user): try: PrefixBookmark.objects.get(user=user, prefix=self) return True except PrefixBookmark.DoesNotExist: return False ## ## Toggle user bookmark. Returns new bookmark state ## def toggle_bookmark(self, user): b, created = PrefixBookmark.objects.get_or_create(user=user, prefix=self) if created: return True else: b.delete() return False def get_index(self): """ Full-text search """ content = [self.prefix] card = "Prefix %s" % self.prefix if self.description: content += [self.description] card += " (%s)" % self.description r = { "id": "ip.prefix:%s" % self.id, "title": self.prefix, "content": "\n".join(content), "card": card } if self.tags: r["tags"] = self.tags return r def get_search_info(self, user): # @todo: Check user access return ("iframe", None, { "title": "Assigned addresses", "url": "/ip/ipam/%s/%s/%s/" % (self.vrf.id, self.afi, self.prefix) }) ## ## All prefix-related address ranges ## @property def address_ranges(self): return list( AddressRange.objects.raw( """ SELECT * FROM ip_addressrange WHERE vrf_id=%s AND afi=%s AND is_active=TRUE AND ( from_address << %s OR to_address << %s OR %s BETWEEN from_address AND to_address ) ORDER BY from_address, to_address """, [self.vrf.id, self.afi, self.prefix, self.prefix, self.prefix ])) @property def ippools(self): """ All nested IP Pools """ return list( IPPool.objects.raw( """ SELECT * FROM ip_ippool i WHERE vrf_id = %s AND afi = %s AND from_address << %s AND to_address << %s AND NOT EXISTS ( SELECT id FROM ip_prefix p WHERE vrf_id = i.vrf_id AND afi = i.afi AND prefix << %s AND ( from_address << p.prefix OR to_address << p.prefix ) ) ORDER BY from_address """, [self.vrf.id, self.afi, self.prefix, self.prefix, self.prefix])) def rebase(self, vrf, new_prefix): """ Rebase prefix to a new location :param vrf: :param new_prefix: :return: """ b = IP.prefix(self.prefix) nb = IP.prefix(new_prefix) # Rebase prefix and all nested prefixes # Parents are left untouched for p in Prefix.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["prefix <<= %s"], params=[self.prefix]): np = IP.prefix(p.prefix).rebase(b, nb).prefix # Prefix.objects.filter(pk=p.pk).update(prefix=np, vrf=vrf) p.prefix = np p.vrf = vrf p.save() # Raise events # Rebase addresses # Parents are left untouched for a in Address.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["address <<= %s"], params=[self.prefix]): na = IP.prefix(a.address).rebase(b, nb).address # Address.objects.filter(pk=a.pk).update(address=na, vrf=vrf) a.address = na a.vrf = vrf a.save() # Raise events # Rebase permissions # move all permissions to the nested blocks for pa in PrefixAccess.objects.filter(vrf=self.vrf).extra( where=["prefix <<= %s"], params=[self.prefix]): np = IP.prefix(pa.prefix).rebase(b, nb).prefix PrefixAccess.objects.filter(pk=pa.pk).update(prefix=np, vrf=vrf) # create permissions for covered blocks for pa in PrefixAccess.objects.filter(vrf=self.vrf).extra( where=["prefix >> %s"], params=[self.prefix]): PrefixAccess(user=pa.user, vrf=vrf, afi=pa.afi, prefix=new_prefix, can_view=pa.can_view, can_change=pa.can_change).save() # @todo: Rebase bookmarks # Return rebased prefix return Prefix.objects.get(pk=self.pk) # Updated object @property def nested_prefix_set(self): """ Queryset returning all nested prefixes inside the prefix """ return Prefix.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["prefix <<= %s"], params=[self.prefix]) @property def nested_address_set(self): """ Queryset returning all nested addresses inside the prefix """ return Address.objects.filter(vrf=self.vrf, afi=self.afi).extra( where=["address <<= %s"], params=[self.prefix]) def iter_free(self): """ Generator returning all available free prefixes inside :return: """ for fp in IP.prefix(self.prefix).iter_free( [p.prefix for p in self.children_set.all()]): yield str(fp) @property def effective_ip_discovery(self): if self.enable_ip_discovery == "I": if self.parent: return self.parent.effective_ip_discovery else: return "E" else: return self.enable_ip_discovery @property def usage(self): if self.afi == "4": size = IPv4(self.prefix).size if not size: return 100.0 n_ips = Address.objects.filter(prefix=self).count() n_pfx = sum( IPv4(p).size for p in Prefix.objects.filter(parent=self).only( "prefix").values_list("prefix", flat=True)) if n_ips: if size > 2: # Not /31 or /32 size -= 2 # Exclude broadcast and network return float(n_ips + n_pfx) * 100.0 / float(size) else: return None @property def usage_percent(self): u = self.usage if u is None: return "" else: return "%.2f%%" % u
class PrefixAccess(models.Model): class Meta: verbose_name = _("Prefix Access") verbose_name_plural = _("Prefix Access") db_table = "ip_prefixaccess" app_label = "ip" unique_together = [("user", "vrf", "afi", "prefix")] ordering = ["user", "vrf", "afi", "prefix"] user = models.ForeignKey(User, verbose_name=_("User")) vrf = models.ForeignKey(VRF, verbose_name=_("VRF")) afi = models.CharField( _("Address Family"), max_length=1, choices=AFI_CHOICES) prefix = CIDRField(_("Prefix")) can_view = models.BooleanField(_("Can View"), default=False) can_change = models.BooleanField(_("Can Change"), default=False) def __unicode__(self): perms = [] if self.can_view: perms += ["View"] if self.can_change: perms += ["Change"] return u"%s: %s(%s): %s: %s" % ( self.user.username, self.vrf.name, self.afi, self.prefix, ", ".join(perms)) def clean(self): """ Field validation :return: """ super(PrefixAccess, self).clean() # Check prefix is of AFI type if self.afi == "4": check_ipv4_prefix(self.prefix) elif self.afi == "6": check_ipv6_prefix(self.prefix) @classmethod def user_can_view(cls, user, vrf, afi, prefix): """ Check user has read access to prefix :param user: :param vrf: :param afi: :param prefix: :return: """ if user.is_superuser: return True if isinstance(prefix, Prefix): prefix = prefix.prefix else: prefix = str(prefix) # @todo: PostgreSQL-independed implementation c = connection.cursor() c.execute("""SELECT COUNT(*) FROM %s WHERE prefix >>= %%s AND vrf_id=%%s AND afi=%%s AND user_id=%%s AND can_view=TRUE """ % PrefixAccess._meta.db_table, [str(prefix), vrf.id, afi, user.id]) return c.fetchall()[0][0] > 0 @classmethod def user_can_change(cls, user, vrf, afi, prefix): """ Check user has write access to prefix :param cls: :param user: :param vrf: :param afi: :param prefix: :return: """ if user.is_superuser: return True # @todo: PostgreSQL-independed implementation c = connection.cursor() c.execute("""SELECT COUNT(*) FROM %s WHERE prefix >>= %%s AND vrf_id=%%s AND afi=%%s AND user_id=%%s AND can_change=TRUE """ % PrefixAccess._meta.db_table, [str(prefix), vrf.id, afi, user.id]) return c.fetchall()[0][0] > 0
class AddressRange(models.Model): class Meta: verbose_name = _("Address Range") verbose_name = _("Address Ranges") db_table = "ip_addressrange" app_label = "ip" unique_together = [("vrf", "afi", "from_address", "to_address")] name = models.CharField(_("Name"), max_length=64, unique=True) is_active = models.BooleanField(_("Is Active"), default=True) vrf = models.ForeignKey(VRF, verbose_name=_("VRF")) afi = models.CharField( _("Address Family"), max_length=1, choices=AFI_CHOICES) from_address = CIDRField(_("From Address")) to_address = CIDRField(_("To address")) description = models.TextField(_("Description"), blank=True, null=True) is_locked = models.BooleanField( _("Is Locked"), default=False, help_text=_("Check to deny address creation or editing within the range")) action = models.CharField( _("Action"), max_length=1, choices=[ ("N", _("Do nothing")), ("G", _("Generate FQDNs")), ("D", _("Partial reverse zone delegation")) ], default="N") fqdn_template = models.CharField( _("FQDN Template"), max_length=255, null=True, blank=True, help_text=_("Template to generate FQDNs when 'Action' set to 'Generate FQDNs'")) reverse_nses = models.CharField( _("Reverse NSes"), max_length=255, null=True, blank=True, help_text=_("Comma-separated list of NSes to partial reverse zone delegation when 'Action' set to 'Partial reverse zone delegation")) tags = TagsField(_("Tags"), null=True, blank=True) tt = models.IntegerField( "TT", blank=True, null=True, help_text=_("Ticket #")) allocated_till = models.DateField( _("Allocated till"), null=True, blank=True, help_text=_("VRF temporary allocated till the date")) def __unicode__(self): return u"%s (IPv%s): %s -- %s" % ( self.vrf.name, self.afi, self.from_address, self.to_address) def clean(self): """ Field validation """ super(AddressRange, self).clean() # Check prefix is of AFI type if self.afi == "4": check_ipv4(self.from_address) check_ipv4(self.to_address) elif self.afi == "6": check_ipv6(self.from_address) check_ipv6(self.to_address) def get_absolute_url(self): return site.reverse("ip:addressrange:change", self.id) ## ## Save instance ## def save(self, **kwargs): def generate_fqdns(): # Prepare FQDN template t = Template(self.fqdn_template) # Sync FQDNs sn = 0 for ip in self.addresses: # Generage FQDN vars = { "afi": self.afi, "vrf": self.vrf, "range": self, "n": sn } sn += 1 if self.afi == "4": i = ip.address.split(".") vars["ip"] = i # ip.0 .. ip.3 # ip1, ip2, ip3, ip4 for backward compatibility for n, i in enumerate(i): vars["ip%d" % (n + 1)] = i elif self.afi == "6": vars["ip"] = ip.digits # ip.0 .. ip.31 fqdn = t.render(Context(vars)) description = "Generated by address range '%s'" % self.name # Create or update address record when necessary a, created = Address.objects.get_or_create( vrf=self.vrf, afi=self.afi, address=ip.address) if created: a.fqdn = fqdn a.description = description a.save() elif a.fqdn != fqdn or a.description != a.description: a.fqdn = fqdn a.description = description a.save() created = self.id is None if not created: # Get old values old = AddressRange.objects.get(id=self.id) super(AddressRange, self).save(**kwargs) if created: # New if self.action == "G": generate_fqdns() else: # Changed if old.action == "G" and self.action != "G": # Drop all auto-generated IPs Address.objects.filter(vrf=self.vrf, afi=self.afi, address__gte=self.from_address, address__lte=self.to_address).delete() elif old.action != "G" and self.action == "G": # Generate IPs generate_fqdns() elif self.action == "G": # Check for boundaries change if IP.prefix(old.from_address) < IP.prefix(self.from_address): # Lower boundary raised up. Clean up addresses falled out of range Address.objects.filter( vrf=self.vrf, afi=self.afi, address__gte=old.from_address, address__lt=self.to_address).delete() if IP.prefix(old.to_address) > IP.prefix(self.to_address): # Upper boundary is lowered. Clean up addressess falled out of range Address.objects.filter( vrf=self.vrf, afi=self.afi, address__gt=self.to_address, address__lte=old.to_address).delete() # Finally recheck FQDNs generate_fqdns() @property def short_description(self): """ First line of description """ if self.description: return self.description.split("\n", 1)[0].strip() else: return "" @property def addresses(self): """ Generator returning all addresses in range """ return IP.prefix(self.from_address).iter_address( until=IP.prefix(self.to_address)) ## ## Returns a list of overlapping ranges ## @classmethod def get_overlapping_ranges(cls, vrf, afi, from_address, to_address): return AddressRange.objects.raw(""" SELECT * FROM ip_addressrange WHERE vrf_id=%(vrf)s AND afi=%(afi)s AND is_active AND ( from_address BETWEEN %(from_address)s AND %(to_address)s OR to_address BETWEEN %(from_address)s AND %(to_address)s OR %(from_address)s BETWEEN from_address AND to_address OR %(to_address)s BETWEEN from_address AND to_address ) """, { "vrf": vrf.id, "afi": afi, "from_address": from_address, "to_address": to_address }) ## ## Returns a queryset with overlapped ranges ## @property def overlapping_ranges(self): return self.get_overlapping_ranges( self.vrf, self.afi, self.from_address, self.to_address) @classmethod def address_is_locked(cls, vrf, afi, address): """ Check wrether address is locked by any range """ return AddressRange.objects.filter( vrf=vrf, afi=afi, is_locked=True, is_active=True, from_address__lte=address, to_address__gte=address).exists()
def forwards(self): AFI_CHOICES = [("4", "IPv4"), ("6", "IPv6")] # Style Style = db.mock_model(model_name='Style', db_table='main_style', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) # VRF Group db.add_column( "ip_vrfgroup", "address_constraint", models.CharField("Address Constraint", max_length=1, choices=[("V", "Addresses are unique per VRF"), ("G", "Addresses are unique per VRF Group")], default="V")) db.alter_column( "ip_vrfgroup", "description", models.TextField("Description", blank=True, null=True, default="V")) db.add_column("ip_vrfgroup", "tags", AutoCompleteTagsField("Tags", null=True, blank=True)) # VRF db.add_column("ip_vrf", "is_active", models.BooleanField("Is Active", default=True)) db.add_column("ip_vrf", "afi_ipv4", models.BooleanField("IPv4", default=True)) db.add_column("ip_vrf", "afi_ipv6", models.BooleanField("IPv6", default=False)) db.alter_column( "ip_vrf", "description", models.TextField("Description", blank=True, null=True, default="V")) db.add_column( "ip_vrf", "style", models.ForeignKey(Style, verbose_name="Style", blank=True, null=True)) db.add_column( "ip_vrf", "allocated_till", models.DateField("Allocated till", null=True, blank=True)) # Prefix VRF = db.mock_model(model_name='VRF', db_table='ip_vrf', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) AS = db.mock_model(model_name='AS', db_table='peer_as', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) VC = db.mock_model(model_name='VC', db_table='vc_vc', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) ManagedObject = db.mock_model(model_name='ManagedObject', db_table='sa_managedobject', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) Prefix = db.mock_model(model_name='Prefix', db_table='ip_prefix', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) db.create_table( 'ip_prefix', (('id', models.AutoField( verbose_name='ID', primary_key=True, auto_created=True)), ("parent", models.ForeignKey(Prefix, related_name="children_set", verbose_name="Parent", null=True, blank=True)), ("vrf", models.ForeignKey(VRF, verbose_name="VRF")), ("afi", models.CharField( "Address Family", max_length=1, choices=AFI_CHOICES)), ("prefix", CIDRField("Prefix")), ("asn", models.ForeignKey(AS, verbose_name="AS")), ("vc", models.ForeignKey(VC, verbose_name="VC", null=True, blank=True)), ("description", models.TextField("Description", blank=True, null=True)), ("tags", AutoCompleteTagsField("Tags", null=True, blank=True)), ("tt", models.IntegerField("TT", blank=True, null=True)), ('style', models.ForeignKey( Style, verbose_name="Style", blank=True, null=True)), ("allocated_till", models.DateField("Allocated till", null=True, blank=True)))) db.create_index('ip_prefix', ['vrf_id', 'afi', 'prefix'], unique=True, db_tablespace='') # Address db.create_table('ip_address', ( ('id', models.AutoField( verbose_name='ID', primary_key=True, auto_created=True)), ("prefix", models.ForeignKey(Prefix, verbose_name="Prefix")), ("vrf", models.ForeignKey(VRF, verbose_name="VRF")), ("afi", models.CharField( "Address Family", max_length=1, choices=AFI_CHOICES)), ("address", INETField("Address")), ("fqdn", models.CharField("FQDN", max_length=255)), ("mac", MACField("MAC", null=True, blank=True)), ("auto_update_mac", models.BooleanField("Auto Update MAC", default=False)), ("managed_object", models.ForeignKey(ManagedObject, verbose_name="Managed Object", null=True, blank=True, related_name="address_set")), ("description", models.TextField("Description", blank=True, null=True)), ("tags", AutoCompleteTagsField("Tags", null=True, blank=True)), ("tt", models.IntegerField("TT", blank=True, null=True)), ('style', models.ForeignKey( Style, verbose_name="Style", blank=True, null=True)), ("allocated_till", models.DateField("Allocated till", null=True, blank=True)), )) db.create_index('ip_address', ['prefix_id', 'vrf_id', 'afi', 'address'], unique=True, db_tablespace='') # PrefixAccess User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField) db.create_table('ip_prefixaccess', ( ('id', models.AutoField( verbose_name='ID', primary_key=True, auto_created=True)), ("user", models.ForeignKey(User, verbose_name="User")), ("vrf", models.ForeignKey(VRF, verbose_name="VRF")), ("afi", models.CharField( "Address Family", max_length=1, choices=AFI_CHOICES)), ("prefix", CIDRField("Prefix")), ("can_view", models.BooleanField("Can View", default=False)), ("can_change", models.BooleanField("Can Change", default=False)), )) db.create_index('ip_prefixaccess', ['user_id', 'vrf_id', 'afi', 'prefix'], unique=True, db_tablespace='') # AddressRange db.create_table('ip_addressrange', ( ('id', models.AutoField( verbose_name='ID', primary_key=True, auto_created=True)), ('name', models.CharField(_("Name"), max_length=64, unique=True)), ('is_active', models.BooleanField(_("Is Active"), default=True)), ("vrf", models.ForeignKey(VRF, verbose_name="VRF")), ("afi", models.CharField( "Address Family", max_length=1, choices=AFI_CHOICES)), ("from_address", INETField("Address")), ("to_address", INETField("Address")), ("description", models.TextField("Description", blank=True, null=True)), ('is_locked', models.BooleanField(_("Is Active"), default=True)), ('action', models.CharField(_("FQDN Action"), max_length=1, choices=[("N", "Do nothing"), ("G", "Generate FQDNs"), ("D", "Partial reverse zone delegation") ], default="N")), ('fqdn_template', models.CharField( _("FQDN Template"), max_length=255, null=True, blank=True)), ('reverse_nses', models.CharField( _("Reverse NSes"), max_length=255, null=True, blank=True)), ("tags", AutoCompleteTagsField("Tags", null=True, blank=True)), ("tt", models.IntegerField("TT", blank=True, null=True)), ("allocated_till", models.DateField("Allocated till", null=True, blank=True)), )) db.create_index('ip_addressrange', ['vrf_id', 'afi', 'from_address', 'to_address'], unique=True, db_tablespace='') # PrefixBookmark db.create_table( 'ip_prefixbookmark', (('id', models.AutoField( verbose_name='ID', primary_key=True, auto_created=True)), ("user", models.ForeignKey(User, verbose_name="User")), ("prefix", models.ForeignKey(Prefix, verbose_name="Prefix")))) db.create_index('ip_prefixbookmark', ['user_id', 'prefix_id'], unique=True, db_tablespace='') db.send_create_signal('ip', ["Prefix", "Address", "PrefixBookmark"])