Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions netbox/ipam/api/serializers_/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,24 @@ class PrefixSerializer(NetBoxModelSerializer):
vlan = VLANSerializer(nested=True, required=False, allow_null=True)
status = ChoiceField(choices=PrefixStatusChoices, required=False)
role = RoleSerializer(nested=True, required=False, allow_null=True)
children = serializers.IntegerField(read_only=True)
_children = serializers.IntegerField(read_only=True)
_depth = serializers.IntegerField(read_only=True)
prefix = IPNetworkField()

class Meta:
model = Prefix
fields = [
'id', 'url', 'display_url', 'display', 'family', 'prefix', 'vrf', 'scope_type', 'scope_id', 'scope',
'tenant', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'children', '_depth',
'id', 'url', 'display_url', 'display', 'family', 'aggregate', 'parent', 'prefix', 'vrf', 'scope_type',
'scope_id', 'scope', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_children', '_depth',
]
brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth')
brief_fields = ('id', 'url', 'display', 'family', 'aggregate', 'parent', 'prefix', 'description', '_depth')

def get_fields(self):
fields = super(PrefixSerializer, self).get_fields()
fields['parent'] = PrefixSerializer(nested=True, read_only=True)

return fields

@extend_schema_field(serializers.JSONField(allow_null=True))
def get_scope(self, obj):
Expand Down Expand Up @@ -134,6 +140,7 @@ def to_representation(self, instance):
#

class IPRangeSerializer(NetBoxModelSerializer):
prefix = PrefixSerializer(nested=True, required=False, allow_null=True)
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
start_address = IPAddressField()
end_address = IPAddressField()
Expand All @@ -145,18 +152,19 @@ class IPRangeSerializer(NetBoxModelSerializer):
class Meta:
model = IPRange
fields = [
'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant',
'status', 'role', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'url', 'display_url', 'display', 'family', 'prefix', 'start_address', 'end_address', 'size', 'vrf',
'tenant', 'status', 'role', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'mark_populated', 'mark_utilized',
]
brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description')
brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'start_address', 'end_address', 'description')


#
# IP addresses
#

class IPAddressSerializer(NetBoxModelSerializer):
prefix = PrefixSerializer(nested=True, required=False, allow_null=True)
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
address = IPAddressField()
vrf = VRFSerializer(nested=True, required=False, allow_null=True)
Expand All @@ -175,11 +183,11 @@ class IPAddressSerializer(NetBoxModelSerializer):
class Meta:
model = IPAddress
fields = [
'id', 'url', 'display_url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role',
'id', 'url', 'display_url', 'display', 'family', 'prefix', 'address', 'vrf', 'tenant', 'status', 'role',
'assigned_object_type', 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside',
'dns_name', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'family', 'address', 'description')
brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'address', 'description')

@extend_schema_field(serializers.JSONField(allow_null=True))
def get_assigned_object(self, obj):
Expand Down
40 changes: 40 additions & 0 deletions netbox/ipam/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,26 @@ class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet, C
field_name='prefix',
lookup_expr='net_mask_length__lte'
)
aggregate_id = django_filters.ModelMultipleChoiceFilter(
queryset=Aggregate.objects.all(),
label=_('Aggregate'),
)
aggregate = django_filters.ModelMultipleChoiceFilter(
field_name='aggregate__prefix',
queryset=Aggregate.objects.all(),
to_field_name='prefix',
label=_('Aggregate (Prefix)'),
)
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=Prefix.objects.all(),
label=_('Parent Prefix'),
)
parent = django_filters.ModelMultipleChoiceFilter(
field_name='parent__prefix',
queryset=Prefix.objects.all(),
to_field_name='prefix',
label=_('Parent Prefix (Prefix)'),
)
vrf_id = django_filters.ModelMultipleChoiceFilter(
queryset=VRF.objects.all(),
label=_('VRF'),
Expand Down Expand Up @@ -473,6 +493,16 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet, ContactModelFilte
method='search_contains',
label=_('Ranges which contain this prefix or IP'),
)
prefix_id = django_filters.ModelMultipleChoiceFilter(
queryset=Prefix.objects.all(),
label=_('Prefix (ID)'),
)
prefix = django_filters.ModelMultipleChoiceFilter(
field_name='prefix__prefix',
queryset=Prefix.objects.all(),
to_field_name='prefix',
label=_('Prefix'),
)
vrf_id = django_filters.ModelMultipleChoiceFilter(
queryset=VRF.objects.all(),
label=_('VRF'),
Expand Down Expand Up @@ -557,6 +587,16 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFil
method='search_by_parent',
label=_('Parent prefix'),
)
prefix_id = django_filters.ModelMultipleChoiceFilter(
queryset=Prefix.objects.all(),
label=_('Prefix (ID)'),
)
prefix = django_filters.ModelMultipleChoiceFilter(
field_name='prefix__prefix',
queryset=Prefix.objects.all(),
to_field_name='prefix',
label=_('Prefix (prefix)'),
)
address = MultiValueCharFilter(
method='filter_address',
label=_('Address'),
Expand Down
26 changes: 23 additions & 3 deletions netbox/ipam/forms/bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ class RoleBulkEditForm(NetBoxModelBulkEditForm):


class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):
parent = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Parent Prefix')
)
vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(),
required=False,
Expand Down Expand Up @@ -266,7 +271,7 @@ class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):
model = Prefix
fieldsets = (
FieldSet('tenant', 'status', 'role', 'description'),
FieldSet('vrf', 'prefix_length', 'is_pool', 'mark_utilized', name=_('Addressing')),
FieldSet('parent', 'vrf', 'prefix_length', 'is_pool', 'mark_utilized', name=_('Addressing')),
FieldSet('scope_type', 'scope', name=_('Scope')),
FieldSet('vlan_group', 'vlan', name=_('VLAN Assignment')),
)
Expand All @@ -276,6 +281,11 @@ class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):


class IPRangeBulkEditForm(NetBoxModelBulkEditForm):
prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Prefix')
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
Expand Down Expand Up @@ -323,6 +333,16 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm):


class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Prefix')
)
prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Prefix')
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
Expand Down Expand Up @@ -364,10 +384,10 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
model = IPAddress
fieldsets = (
FieldSet('status', 'role', 'tenant', 'description'),
FieldSet('vrf', 'mask_length', 'dns_name', name=_('Addressing')),
FieldSet('prefix', 'vrf', 'mask_length', 'dns_name', name=_('Addressing')),
)
nullable_fields = (
'vrf', 'role', 'tenant', 'dns_name', 'description', 'comments',
'prefix', 'vrf', 'role', 'tenant', 'dns_name', 'description', 'comments',
)


Expand Down
64 changes: 62 additions & 2 deletions netbox/ipam/forms/bulk_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@ class Meta:


class PrefixImportForm(ScopedImportForm, NetBoxModelImportForm):
aggregate = CSVModelChoiceField(
label=_('Aggregate'),
queryset=Aggregate.objects.all(),
to_field_name='prefix',
required=False
)
parent = CSVModelChoiceField(
label=_('Prefix'),
queryset=Prefix.objects.all(),
to_field_name='prefix',
required=False
)
vrf = CSVModelChoiceField(
label=_('VRF'),
queryset=VRF.objects.all(),
Expand Down Expand Up @@ -243,8 +255,26 @@ def __init__(self, data=None, *args, **kwargs):
queryset = self.fields['vlan'].queryset.filter(query)
self.fields['vlan'].queryset = queryset

# Limit Prefix queryset by assigned vrf
vrf = data.get('vrf')
query = Q()
if vrf:
query &= Q(**{
f"vrf__{self.fields['vrf'].to_field_name}": vrf
})

queryset = self.fields['parent'].queryset.filter(query)
self.fields['parent'].queryset = queryset


class IPRangeImportForm(NetBoxModelImportForm):
prefix = CSVModelChoiceField(
label=_('Prefix'),
queryset=Prefix.objects.all(),
to_field_name='prefix',
required=True,
help_text=_('Assigned prefix')
)
vrf = CSVModelChoiceField(
label=_('VRF'),
queryset=VRF.objects.all(),
Expand Down Expand Up @@ -279,8 +309,29 @@ class Meta:
'description', 'comments', 'tags',
)

def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs)

# Limit Prefix queryset by assigned vrf
vrf = data.get('vrf')
query = Q()
if vrf:
query &= Q(**{
f"vrf__{self.fields['vrf'].to_field_name}": vrf
})

queryset = self.fields['prefix'].queryset.filter(query)
self.fields['prefix'].queryset = queryset


class IPAddressImportForm(NetBoxModelImportForm):
prefix = CSVModelChoiceField(
label=_('Prefix'),
queryset=Prefix.objects.all(),
required=False,
to_field_name='prefix',
help_text=_('Assigned prefix')
)
vrf = CSVModelChoiceField(
label=_('VRF'),
queryset=VRF.objects.all(),
Expand Down Expand Up @@ -348,15 +399,24 @@ class IPAddressImportForm(NetBoxModelImportForm):
class Meta:
model = IPAddress
fields = [
'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface', 'fhrp_group',
'is_primary', 'is_oob', 'dns_name', 'description', 'comments', 'tags',
'prefix', 'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface',
'fhrp_group', 'is_primary', 'is_oob', 'dns_name', 'description', 'comments', 'tags',
]

def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs)

if data:

# Limit Prefix queryset by assigned vrf
vrf = data.get('vrf')
query = Q()
if vrf:
query &= Q(**{f"vrf__{self.fields['vrf'].to_field_name}": vrf})

queryset = self.fields['prefix'].queryset.filter(query)
self.fields['prefix'].queryset = queryset

# Limit interface queryset by assigned device
if data.get('device'):
self.fields['interface'].queryset = Interface.objects.filter(
Expand Down
25 changes: 22 additions & 3 deletions netbox/ipam/forms/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFil
choices=PREFIX_MASK_LENGTH_CHOICES,
label=_('Mask length')
)
aggregate_id = DynamicModelMultipleChoiceField(
queryset=Aggregate.objects.all(),
required=False,
label=_('Aggregate'),
null_option='Global'
)
vrf_id = DynamicModelMultipleChoiceField(
queryset=VRF.objects.all(),
required=False,
Expand Down Expand Up @@ -278,10 +284,18 @@ class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFi
model = IPRange
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')),
FieldSet(
'prefix', 'family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')
),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
prefix = DynamicModelMultipleChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Prefix'),
null_option='None'
)
family = forms.ChoiceField(
required=False,
choices=add_blank_choice(IPAddressFamilyChoices),
Expand Down Expand Up @@ -326,15 +340,15 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModel
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
'prefix', 'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
name=_('Attributes')
),
FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role')
selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'prefix_id', 'parent', 'status', 'role')
parent = forms.CharField(
required=False,
widget=forms.TextInput(
Expand All @@ -354,6 +368,11 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModel
choices=IPADDRESS_MASK_LENGTH_CHOICES,
label=_('Mask length')
)
prefix_id = DynamicModelMultipleChoiceField(
queryset=Prefix.objects.all(),
required=False,
label=_('Prefix'),
)
vrf_id = DynamicModelMultipleChoiceField(
queryset=VRF.objects.all(),
required=False,
Expand Down
Loading
Loading