mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 17:08:41 -06:00
Prefix.status to slug (#3569)
This commit is contained in:
parent
21fe5902a8
commit
929c0648d0
@ -8,6 +8,7 @@ from taggit_serializer.serializers import TaggitSerializer, TagListSerializerFie
|
|||||||
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerializer
|
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerializer
|
||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
|
from ipam.choices import *
|
||||||
from ipam.constants import *
|
from ipam.constants import *
|
||||||
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.nested_serializers import NestedTenantSerializer
|
||||||
@ -140,7 +141,7 @@ class PrefixSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
vrf = NestedVRFSerializer(required=False, allow_null=True)
|
vrf = NestedVRFSerializer(required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
vlan = NestedVLANSerializer(required=False, allow_null=True)
|
vlan = NestedVLANSerializer(required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=PREFIX_STATUS_CHOICES, required=False)
|
status = ChoiceField(choices=PrefixStatusChoices, required=False)
|
||||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
role = NestedRoleSerializer(required=False, allow_null=True)
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
|
||||||
|
27
netbox/ipam/choices.py
Normal file
27
netbox/ipam/choices.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from utilities.choices import ChoiceSet
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prefixes
|
||||||
|
#
|
||||||
|
|
||||||
|
class PrefixStatusChoices(ChoiceSet):
|
||||||
|
|
||||||
|
STATUS_CONTAINER = 'container'
|
||||||
|
STATUS_ACTIVE = 'active'
|
||||||
|
STATUS_RESERVED = 'reserved'
|
||||||
|
STATUS_DEPRECATED = 'deprecated'
|
||||||
|
|
||||||
|
CHOICES = (
|
||||||
|
(STATUS_CONTAINER, 'Container'),
|
||||||
|
(STATUS_ACTIVE, 'Active'),
|
||||||
|
(STATUS_RESERVED, 'Reserved'),
|
||||||
|
(STATUS_DEPRECATED, 'Deprecated'),
|
||||||
|
)
|
||||||
|
|
||||||
|
LEGACY_MAP = {
|
||||||
|
STATUS_CONTAINER: 0,
|
||||||
|
STATUS_ACTIVE: 1,
|
||||||
|
STATUS_RESERVED: 2,
|
||||||
|
STATUS_DEPRECATED: 3,
|
||||||
|
}
|
@ -4,18 +4,6 @@ AF_CHOICES = (
|
|||||||
(6, 'IPv6'),
|
(6, 'IPv6'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Prefix statuses
|
|
||||||
PREFIX_STATUS_CONTAINER = 0
|
|
||||||
PREFIX_STATUS_ACTIVE = 1
|
|
||||||
PREFIX_STATUS_RESERVED = 2
|
|
||||||
PREFIX_STATUS_DEPRECATED = 3
|
|
||||||
PREFIX_STATUS_CHOICES = (
|
|
||||||
(PREFIX_STATUS_CONTAINER, 'Container'),
|
|
||||||
(PREFIX_STATUS_ACTIVE, 'Active'),
|
|
||||||
(PREFIX_STATUS_RESERVED, 'Reserved'),
|
|
||||||
(PREFIX_STATUS_DEPRECATED, 'Deprecated')
|
|
||||||
)
|
|
||||||
|
|
||||||
# IP address statuses
|
# IP address statuses
|
||||||
IPADDRESS_STATUS_ACTIVE = 1
|
IPADDRESS_STATUS_ACTIVE = 1
|
||||||
IPADDRESS_STATUS_RESERVED = 2
|
IPADDRESS_STATUS_RESERVED = 2
|
||||||
|
@ -9,6 +9,7 @@ from extras.filters import CustomFieldFilterSet
|
|||||||
from tenancy.filtersets import TenancyFilterSet
|
from tenancy.filtersets import TenancyFilterSet
|
||||||
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
|
from .choices import *
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ class PrefixFilter(TenancyFilterSet, CustomFieldFilterSet):
|
|||||||
label='Role (slug)',
|
label='Role (slug)',
|
||||||
)
|
)
|
||||||
status = django_filters.MultipleChoiceFilter(
|
status = django_filters.MultipleChoiceFilter(
|
||||||
choices=PREFIX_STATUS_CHOICES,
|
choices=PrefixStatusChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
tag = TagFilter()
|
tag = TagFilter()
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"site": 1,
|
"site": 1,
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"vlan": null,
|
"vlan": null,
|
||||||
"status": 1,
|
"status": "active",
|
||||||
"role": 1,
|
"role": 1,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@
|
|||||||
"site": 1,
|
"site": 1,
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"vlan": null,
|
"vlan": null,
|
||||||
"status": 1,
|
"status": "active",
|
||||||
"role": 1,
|
"role": 1,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ from utilities.forms import (
|
|||||||
StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
|
from .choices import *
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
|
|
||||||
@ -374,7 +375,7 @@ class PrefixCSVForm(forms.ModelForm):
|
|||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
status = CSVChoiceField(
|
status = CSVChoiceField(
|
||||||
choices=PREFIX_STATUS_CHOICES,
|
choices=PrefixStatusChoices,
|
||||||
help_text='Operational status'
|
help_text='Operational status'
|
||||||
)
|
)
|
||||||
role = forms.ModelChoiceField(
|
role = forms.ModelChoiceField(
|
||||||
@ -459,7 +460,7 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(PREFIX_STATUS_CHOICES),
|
choices=add_blank_choice(PrefixStatusChoices),
|
||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect2()
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
@ -527,7 +528,7 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
status = forms.MultipleChoiceField(
|
status = forms.MultipleChoiceField(
|
||||||
choices=PREFIX_STATUS_CHOICES,
|
choices=PrefixStatusChoices,
|
||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect2Multiple()
|
widget=StaticSelect2Multiple()
|
||||||
)
|
)
|
||||||
|
34
netbox/ipam/migrations/0028_3569_prefix_fields.py
Normal file
34
netbox/ipam/migrations/0028_3569_prefix_fields.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
PREFIX_STATUS_CHOICES = (
|
||||||
|
(0, 'container'),
|
||||||
|
(1, 'active'),
|
||||||
|
(2, 'reserved'),
|
||||||
|
(3, 'deprecated'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def prefix_status_to_slug(apps, schema_editor):
|
||||||
|
Prefix = apps.get_model('ipam', 'Prefix')
|
||||||
|
for id, slug in PREFIX_STATUS_CHOICES:
|
||||||
|
Prefix.objects.filter(status=str(id)).update(status=slug)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
atomic = False
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ipam', '0027_ipaddress_add_dns_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='prefix',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(default='active', max_length=50),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=prefix_status_to_slug
|
||||||
|
),
|
||||||
|
]
|
@ -14,6 +14,7 @@ from extras.models import CustomFieldModel, ObjectChange, TaggedItem
|
|||||||
from utilities.models import ChangeLoggedModel
|
from utilities.models import ChangeLoggedModel
|
||||||
from utilities.utils import serialize_object
|
from utilities.utils import serialize_object
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
|
from .choices import *
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .fields import IPNetworkField, IPAddressField
|
from .fields import IPNetworkField, IPAddressField
|
||||||
from .querysets import PrefixQuerySet
|
from .querysets import PrefixQuerySet
|
||||||
@ -297,9 +298,10 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
null=True,
|
null=True,
|
||||||
verbose_name='VLAN'
|
verbose_name='VLAN'
|
||||||
)
|
)
|
||||||
status = models.PositiveSmallIntegerField(
|
status = models.CharField(
|
||||||
choices=PREFIX_STATUS_CHOICES,
|
max_length=50,
|
||||||
default=PREFIX_STATUS_ACTIVE,
|
choices=PrefixStatusChoices,
|
||||||
|
default=PrefixStatusChoices.STATUS_ACTIVE,
|
||||||
verbose_name='Status',
|
verbose_name='Status',
|
||||||
help_text='Operational status of this prefix'
|
help_text='Operational status of this prefix'
|
||||||
)
|
)
|
||||||
@ -333,6 +335,13 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description',
|
'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
STATUS_CLASS_MAP = {
|
||||||
|
'container': 'default',
|
||||||
|
'active': 'primary',
|
||||||
|
'reserved': 'info',
|
||||||
|
'deprecated': 'danger',
|
||||||
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = [F('vrf').asc(nulls_first=True), 'family', 'prefix']
|
ordering = [F('vrf').asc(nulls_first=True), 'family', 'prefix']
|
||||||
verbose_name_plural = 'prefixes'
|
verbose_name_plural = 'prefixes'
|
||||||
@ -404,7 +413,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
prefix_length = property(fset=_set_prefix_length)
|
prefix_length = property(fset=_set_prefix_length)
|
||||||
|
|
||||||
def get_status_class(self):
|
def get_status_class(self):
|
||||||
return STATUS_CHOICE_CLASSES[self.status]
|
return self.STATUS_CLASS_MAP.get(self.status)
|
||||||
|
|
||||||
def get_duplicates(self):
|
def get_duplicates(self):
|
||||||
return Prefix.objects.filter(vrf=self.vrf, prefix=str(self.prefix)).exclude(pk=self.pk)
|
return Prefix.objects.filter(vrf=self.vrf, prefix=str(self.prefix)).exclude(pk=self.pk)
|
||||||
@ -414,7 +423,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
Return all Prefixes within this Prefix and VRF. If this Prefix is a container in the global table, return child
|
Return all Prefixes within this Prefix and VRF. If this Prefix is a container in the global table, return child
|
||||||
Prefixes belonging to any VRF.
|
Prefixes belonging to any VRF.
|
||||||
"""
|
"""
|
||||||
if self.vrf is None and self.status == PREFIX_STATUS_CONTAINER:
|
if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER:
|
||||||
return Prefix.objects.filter(prefix__net_contained=str(self.prefix))
|
return Prefix.objects.filter(prefix__net_contained=str(self.prefix))
|
||||||
else:
|
else:
|
||||||
return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
|
return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
|
||||||
@ -424,7 +433,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
Return all IPAddresses within this Prefix and VRF. If this Prefix is a container in the global table, return
|
Return all IPAddresses within this Prefix and VRF. If this Prefix is a container in the global table, return
|
||||||
child IPAddresses belonging to any VRF.
|
child IPAddresses belonging to any VRF.
|
||||||
"""
|
"""
|
||||||
if self.vrf is None and self.status == PREFIX_STATUS_CONTAINER:
|
if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER:
|
||||||
return IPAddress.objects.filter(address__net_host_contained=str(self.prefix))
|
return IPAddress.objects.filter(address__net_host_contained=str(self.prefix))
|
||||||
else:
|
else:
|
||||||
return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf)
|
return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf)
|
||||||
@ -490,7 +499,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
|||||||
Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of
|
Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of
|
||||||
"container", calculate utilization based on child prefixes. For all others, count child IP addresses.
|
"container", calculate utilization based on child prefixes. For all others, count child IP addresses.
|
||||||
"""
|
"""
|
||||||
if self.status == PREFIX_STATUS_CONTAINER:
|
if self.status == PrefixStatusChoices.STATUS_CONTAINER:
|
||||||
queryset = Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
|
queryset = Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
|
||||||
child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
|
child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
|
||||||
return int(float(child_prefixes.size) / self.prefix.size * 100)
|
return int(float(child_prefixes.size) / self.prefix.size * 100)
|
||||||
|
@ -14,6 +14,7 @@ from utilities.views import (
|
|||||||
)
|
)
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from . import filters, forms, tables
|
from . import filters, forms, tables
|
||||||
|
from .choices import PrefixStatusChoices
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
|
|
||||||
@ -217,13 +218,13 @@ class RIRListView(PermissionRequiredMixin, ObjectListView):
|
|||||||
|
|
||||||
# Find all consumed space for each prefix status (we ignore containers for this purpose).
|
# Find all consumed space for each prefix status (we ignore containers for this purpose).
|
||||||
active_prefixes = netaddr.cidr_merge(
|
active_prefixes = netaddr.cidr_merge(
|
||||||
[p.prefix for p in queryset.filter(status=PREFIX_STATUS_ACTIVE)]
|
[p.prefix for p in queryset.filter(status=PrefixStatusChoices.STATUS_ACTIVE)]
|
||||||
)
|
)
|
||||||
reserved_prefixes = netaddr.cidr_merge(
|
reserved_prefixes = netaddr.cidr_merge(
|
||||||
[p.prefix for p in queryset.filter(status=PREFIX_STATUS_RESERVED)]
|
[p.prefix for p in queryset.filter(status=PrefixStatusChoices.STATUS_RESERVED)]
|
||||||
)
|
)
|
||||||
deprecated_prefixes = netaddr.cidr_merge(
|
deprecated_prefixes = netaddr.cidr_merge(
|
||||||
[p.prefix for p in queryset.filter(status=PREFIX_STATUS_DEPRECATED)]
|
[p.prefix for p in queryset.filter(status=PrefixStatusChoices.STATUS_DEPRECATED)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Find all available prefixes by subtracting each of the existing prefix sets from the aggregate prefix.
|
# Find all available prefixes by subtracting each of the existing prefix sets from the aggregate prefix.
|
||||||
|
Loading…
Reference in New Issue
Block a user