mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Model import/export route targets on VRFs
This commit is contained in:
@ -26,14 +26,16 @@ from .nested_serializers import *
|
|||||||
class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
|
class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
|
import_targets = NestedRouteTargetSerializer(required=False, allow_null=True, many=True)
|
||||||
|
export_targets = NestedRouteTargetSerializer(required=False, allow_null=True, many=True)
|
||||||
ipaddress_count = serializers.IntegerField(read_only=True)
|
ipaddress_count = serializers.IntegerField(read_only=True)
|
||||||
prefix_count = serializers.IntegerField(read_only=True)
|
prefix_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VRF
|
model = VRF
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name',
|
'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets',
|
||||||
'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
|
'tags', 'display_name', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,9 @@ class IPAMRootView(APIRootView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VRFViewSet(CustomFieldModelViewSet):
|
class VRFViewSet(CustomFieldModelViewSet):
|
||||||
queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate(
|
queryset = VRF.objects.prefetch_related('tenant').prefetch_related(
|
||||||
|
'import_targets', 'export_targets', 'tags'
|
||||||
|
).annotate(
|
||||||
ipaddress_count=get_subquery(IPAddress, 'vrf'),
|
ipaddress_count=get_subquery(IPAddress, 'vrf'),
|
||||||
prefix_count=get_subquery(Prefix, 'vrf')
|
prefix_count=get_subquery(Prefix, 'vrf')
|
||||||
).order_by(*VRF._meta.ordering)
|
).order_by(*VRF._meta.ordering)
|
||||||
|
@ -35,6 +35,28 @@ class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, Create
|
|||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
|
import_target_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='import_targets',
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
label='Import target',
|
||||||
|
)
|
||||||
|
import_target = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='import_targets__name',
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
label='Import target (name)',
|
||||||
|
)
|
||||||
|
export_target_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='export_targets',
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
label='Export target',
|
||||||
|
)
|
||||||
|
export_target = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='export_targets__name',
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
label='Export target (name)',
|
||||||
|
)
|
||||||
tag = TagFilter()
|
tag = TagFilter()
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
@ -56,6 +78,28 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet
|
|||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
|
importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='importing_vrfs',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
label='Importing VRF',
|
||||||
|
)
|
||||||
|
importing_vrf = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='importing_vrfs__rd',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
to_field_name='rd',
|
||||||
|
label='Import VRF (RD)',
|
||||||
|
)
|
||||||
|
exporting_vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='exporting_vrfs',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
label='Exporting VRF',
|
||||||
|
)
|
||||||
|
exporting_vrf = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='exporting_vrfs__rd',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
to_field_name='rd',
|
||||||
|
label='Export VRF (RD)',
|
||||||
|
)
|
||||||
tag = TagFilter()
|
tag = TagFilter()
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
|
@ -31,6 +31,14 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||||
|
import_targets = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
export_targets = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
tags = DynamicModelMultipleChoiceField(
|
tags = DynamicModelMultipleChoiceField(
|
||||||
queryset=Tag.objects.all(),
|
queryset=Tag.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
@ -39,7 +47,8 @@ class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VRF
|
model = VRF
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant', 'tags',
|
'name', 'rd', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tenant_group', 'tenant',
|
||||||
|
'tags',
|
||||||
]
|
]
|
||||||
labels = {
|
labels = {
|
||||||
'rd': "RD",
|
'rd': "RD",
|
||||||
@ -89,11 +98,21 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
|
|||||||
|
|
||||||
class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||||
model = VRF
|
model = VRF
|
||||||
field_order = ['q', 'tenant_group', 'tenant']
|
field_order = ['q', 'import_target', 'export_target', 'tenant_group', 'tenant']
|
||||||
q = forms.CharField(
|
q = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Search'
|
label='Search'
|
||||||
)
|
)
|
||||||
|
import_target = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
export_target = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=RouteTarget.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
required=False
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
@ -149,11 +168,21 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulk
|
|||||||
|
|
||||||
class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||||
model = RouteTarget
|
model = RouteTarget
|
||||||
field_order = ['q', 'name', 'tenant_group', 'tenant']
|
field_order = ['q', 'name', 'tenant_group', 'tenant', 'importing_vrfs', 'exporting_vrfs']
|
||||||
q = forms.CharField(
|
q = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Search'
|
label='Search'
|
||||||
)
|
)
|
||||||
|
importing_vrf_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label='Imported by VRF'
|
||||||
|
)
|
||||||
|
exporting_vrf_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label='Exported by VRF'
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,4 +31,14 @@ class Migration(migrations.Migration):
|
|||||||
'ordering': ['name'],
|
'ordering': ['name'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vrf',
|
||||||
|
name='export_targets',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='exporting_vrfs', to='ipam.RouteTarget'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vrf',
|
||||||
|
name='import_targets',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='importing_vrfs', to='ipam.RouteTarget'),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -71,6 +71,16 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
|
|||||||
max_length=200,
|
max_length=200,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
import_targets = models.ManyToManyField(
|
||||||
|
to='ipam.RouteTarget',
|
||||||
|
related_name='importing_vrfs',
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
export_targets = models.ManyToManyField(
|
||||||
|
to='ipam.RouteTarget',
|
||||||
|
related_name='exporting_vrfs',
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
objects = RestrictedQuerySet.as_manager()
|
objects = RestrictedQuerySet.as_manager()
|
||||||
|
@ -39,9 +39,20 @@ class VRFView(ObjectView):
|
|||||||
vrf = get_object_or_404(self.queryset, pk=pk)
|
vrf = get_object_or_404(self.queryset, pk=pk)
|
||||||
prefix_count = Prefix.objects.restrict(request.user, 'view').filter(vrf=vrf).count()
|
prefix_count = Prefix.objects.restrict(request.user, 'view').filter(vrf=vrf).count()
|
||||||
|
|
||||||
|
import_targets_table = tables.RouteTargetTable(
|
||||||
|
vrf.import_targets.prefetch_related('tenant'),
|
||||||
|
orderable=False
|
||||||
|
)
|
||||||
|
export_targets_table = tables.RouteTargetTable(
|
||||||
|
vrf.export_targets.prefetch_related('tenant'),
|
||||||
|
orderable=False
|
||||||
|
)
|
||||||
|
|
||||||
return render(request, 'ipam/vrf.html', {
|
return render(request, 'ipam/vrf.html', {
|
||||||
'vrf': vrf,
|
'vrf': vrf,
|
||||||
'prefix_count': prefix_count,
|
'prefix_count': prefix_count,
|
||||||
|
'import_targets_table': import_targets_table,
|
||||||
|
'export_targets_table': export_targets_table,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -91,8 +102,19 @@ class RouteTargetView(ObjectView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
routetarget = get_object_or_404(self.queryset, pk=pk)
|
routetarget = get_object_or_404(self.queryset, pk=pk)
|
||||||
|
|
||||||
|
importing_vrfs_table = tables.VRFTable(
|
||||||
|
routetarget.importing_vrfs.prefetch_related('tenant'),
|
||||||
|
orderable=False
|
||||||
|
)
|
||||||
|
exporting_vrfs_table = tables.VRFTable(
|
||||||
|
routetarget.exporting_vrfs.prefetch_related('tenant'),
|
||||||
|
orderable=False
|
||||||
|
)
|
||||||
|
|
||||||
return render(request, 'ipam/routetarget.html', {
|
return render(request, 'ipam/routetarget.html', {
|
||||||
'routetarget': routetarget,
|
'routetarget': routetarget,
|
||||||
|
'importing_vrfs_table': importing_vrfs_table,
|
||||||
|
'exporting_vrfs_table': exporting_vrfs_table,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,10 +83,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% include 'extras/inc/tags_panel.html' with tags=routetarget.tags.all url='ipam:routetarget_list' %}
|
{% include 'extras/inc/tags_panel.html' with tags=routetarget.tags.all url='ipam:routetarget_list' %}
|
||||||
|
{% include 'inc/custom_fields_panel.html' with obj=routetarget %}
|
||||||
{% plugin_left_page routetarget %}
|
{% plugin_left_page routetarget %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{% include 'inc/custom_fields_panel.html' with obj=routetarget %}
|
{% include 'panel_table.html' with table=importing_vrfs_table heading="Importing VRFs" %}
|
||||||
|
{% include 'panel_table.html' with table=exporting_vrfs_table heading="Exporting VRFs" %}
|
||||||
{% plugin_right_page routetarget %}
|
{% plugin_right_page routetarget %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,10 +99,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% include 'extras/inc/tags_panel.html' with tags=vrf.tags.all url='ipam:vrf_list' %}
|
{% include 'extras/inc/tags_panel.html' with tags=vrf.tags.all url='ipam:vrf_list' %}
|
||||||
|
{% include 'inc/custom_fields_panel.html' with obj=vrf %}
|
||||||
{% plugin_left_page vrf %}
|
{% plugin_left_page vrf %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{% include 'inc/custom_fields_panel.html' with obj=vrf %}
|
{% include 'panel_table.html' with table=import_targets_table heading="Import Route Targets" %}
|
||||||
|
{% include 'panel_table.html' with table=export_targets_table heading="Export Route Targets" %}
|
||||||
{% plugin_right_page vrf %}
|
{% plugin_right_page vrf %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,13 @@
|
|||||||
{% render_field form.description %}
|
{% render_field form.description %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><strong>Route Targets</strong></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{% render_field form.import_targets %}
|
||||||
|
{% render_field form.export_targets %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><strong>Tenancy</strong></div>
|
<div class="panel-heading"><strong>Tenancy</strong></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
Reference in New Issue
Block a user