| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- from django.core.exceptions import ValidationError
- from django.db import models
- from django.utils.translation import gettext_lazy as _
- from ipam.fields import ASNField
- from ipam.querysets import ASNRangeQuerySet
- from netbox.models import OrganizationalModel, PrimaryModel
- from netbox.models.features import ContactsMixin
- __all__ = (
- 'ASN',
- 'ASNRange',
- )
- class ASNRange(OrganizationalModel):
- name = models.CharField(
- verbose_name=_('name'),
- max_length=100,
- unique=True,
- db_collation="natural_sort"
- )
- slug = models.SlugField(
- verbose_name=_('slug'),
- max_length=100,
- unique=True
- )
- rir = models.ForeignKey(
- to='ipam.RIR',
- on_delete=models.PROTECT,
- related_name='asn_ranges',
- verbose_name=_('RIR')
- )
- start = ASNField(
- verbose_name=_('start'),
- )
- end = ASNField(
- verbose_name=_('end'),
- )
- tenant = models.ForeignKey(
- to='tenancy.Tenant',
- on_delete=models.PROTECT,
- related_name='asn_ranges',
- blank=True,
- null=True
- )
- objects = ASNRangeQuerySet.as_manager()
- class Meta:
- ordering = ('name',)
- verbose_name = _('ASN range')
- verbose_name_plural = _('ASN ranges')
- def __str__(self):
- return f'{self.name} ({self.range_as_string()})'
- def clean(self):
- super().clean()
- if self.end <= self.start:
- raise ValidationError(
- _("Starting ASN ({start}) must be lower than ending ASN ({end}).").format(
- start=self.start, end=self.end
- )
- )
- @property
- def range(self):
- """
- Return a range of integers representing the ASN range.
- """
- return range(self.start, self.end + 1)
- @property
- def start_asdot(self):
- """
- Return ASDOT notation for AS numbers greater than 16 bits.
- """
- return ASNField.to_asdot(self.start)
- @property
- def end_asdot(self):
- """
- Return ASDOT notation for AS numbers greater than 16 bits.
- """
- return ASNField.to_asdot(self.end)
- def range_as_string(self):
- """
- Return a string representation of the ASN range.
- """
- return f'{self.start}-{self.end}'
- def range_as_string_with_asdot(self):
- """
- Return a string representation of the ASN range, including ASDOT notation.
- """
- if self.end >= 65536:
- return f'{self.range_as_string()} ({self.start_asdot}-{self.end_asdot})'
- return self.range_as_string()
- def get_child_asns(self):
- """
- Return all child ASNs (ASNs within the range).
- """
- return ASN.objects.filter(
- asn__gte=self.start,
- asn__lte=self.end
- )
- def get_available_asns(self):
- """
- Return all available ASNs within this range.
- """
- range = set(self.range)
- existing_asns = set(self.get_child_asns().values_list('asn', flat=True))
- available_asns = sorted(range - existing_asns)
- return available_asns
- class ASN(ContactsMixin, PrimaryModel):
- """
- An autonomous system (AS) number is typically used to represent an independent routing domain. A site can have
- one or more ASNs assigned to it.
- """
- rir = models.ForeignKey(
- to='ipam.RIR',
- on_delete=models.PROTECT,
- related_name='asns',
- verbose_name=_('RIR'),
- help_text=_("Regional Internet Registry responsible for this AS number space")
- )
- asn = ASNField(
- unique=True,
- verbose_name=_('ASN'),
- help_text=_('16- or 32-bit autonomous system number')
- )
- tenant = models.ForeignKey(
- to='tenancy.Tenant',
- on_delete=models.PROTECT,
- related_name='asns',
- blank=True,
- null=True
- )
- prerequisite_models = (
- 'ipam.RIR',
- )
- class Meta:
- ordering = ['asn']
- verbose_name = _('ASN')
- verbose_name_plural = _('ASNs')
- def __str__(self):
- return f'AS{self.asn_with_asdot}'
- @property
- def asn_asdot(self):
- """
- Return ASDOT notation for AS numbers greater than 16 bits.
- """
- return ASNField.to_asdot(self.asn)
- @property
- def asn_with_asdot(self):
- """
- Return both plain and ASDOT notation, where applicable.
- """
- if self.asn >= 65536:
- return f'{self.asn} ({self.asn_asdot})'
- return str(self.asn)
- @property
- def prefixed_name(self):
- """
- Return the ASN with ASDOT notation prefixed with "AS".
- """
- return f'AS{self.asn_with_asdot}'
|