Просмотр исходного кода

Model import/export route targets on VRFs

Jeremy Stretch 5 лет назад
Родитель
Сommit
f684d07c61

+ 4 - 2
netbox/ipam/api/serializers.py

@@ -26,14 +26,16 @@ from .nested_serializers import *
 class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
     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)
     prefix_count = serializers.IntegerField(read_only=True)
 
     class Meta:
         model = VRF
         fields = [
-            'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name',
-            'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
+            'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets',
+            'tags', 'display_name', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
         ]
 
 

+ 3 - 1
netbox/ipam/api/views.py

@@ -30,7 +30,9 @@ class IPAMRootView(APIRootView):
 #
 
 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'),
         prefix_count=get_subquery(Prefix, 'vrf')
     ).order_by(*VRF._meta.ordering)

+ 44 - 0
netbox/ipam/filters.py

@@ -35,6 +35,28 @@ class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, Create
         method='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()
 
     def search(self, queryset, name, value):
@@ -56,6 +78,28 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet
         method='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()
 
     def search(self, queryset, name, value):

+ 32 - 3
netbox/ipam/forms.py

@@ -31,6 +31,14 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
 #
 
 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(
         queryset=Tag.objects.all(),
         required=False
@@ -39,7 +47,8 @@ class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     class Meta:
         model = VRF
         fields = [
-            'name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant', 'tags',
+            'name', 'rd', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tenant_group', 'tenant',
+            'tags',
         ]
         labels = {
             'rd': "RD",
@@ -89,11 +98,21 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
 
 class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VRF
-    field_order = ['q', 'tenant_group', 'tenant']
+    field_order = ['q', 'import_target', 'export_target', 'tenant_group', 'tenant']
     q = forms.CharField(
         required=False,
         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)
 
 
@@ -149,11 +168,21 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulk
 
 class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = RouteTarget
-    field_order = ['q', 'name', 'tenant_group', 'tenant']
+    field_order = ['q', 'name', 'tenant_group', 'tenant', 'importing_vrfs', 'exporting_vrfs']
     q = forms.CharField(
         required=False,
         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)
 
 

+ 10 - 0
netbox/ipam/migrations/0041_routetarget.py

@@ -31,4 +31,14 @@ class Migration(migrations.Migration):
                 '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'),
+        ),
     ]

+ 10 - 0
netbox/ipam/models.py

@@ -71,6 +71,16 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
         max_length=200,
         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)
 
     objects = RestrictedQuerySet.as_manager()

+ 22 - 0
netbox/ipam/views.py

@@ -39,9 +39,20 @@ class VRFView(ObjectView):
         vrf = get_object_or_404(self.queryset, pk=pk)
         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', {
             'vrf': vrf,
             '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):
         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', {
             'routetarget': routetarget,
+            'importing_vrfs_table': importing_vrfs_table,
+            'exporting_vrfs_table': exporting_vrfs_table,
         })
 
 

+ 3 - 1
netbox/templates/ipam/routetarget.html

@@ -83,10 +83,12 @@
 		    </table>
         </div>
         {% 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 %}
 	</div>
 	<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 %}
     </div>
 </div>

+ 3 - 1
netbox/templates/ipam/vrf.html

@@ -99,10 +99,12 @@
 		    </table>
         </div>
         {% 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 %}
 	</div>
 	<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 %}
     </div>
 </div>

+ 7 - 0
netbox/templates/ipam/vrf_edit.html

@@ -11,6 +11,13 @@
             {% render_field form.description %}
         </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-heading"><strong>Tenancy</strong></div>
         <div class="panel-body">