diff --git a/netbox/ipam/forms/models.py b/netbox/ipam/forms/models.py index d28f7b3ae..c15a19fb0 100644 --- a/netbox/ipam/forms/models.py +++ b/netbox/ipam/forms/models.py @@ -20,6 +20,7 @@ __all__ = ( 'IPAddressForm', 'IPRangeForm', 'PrefixForm', + 'PrefixAssignForm', 'RIRForm', 'RoleForm', 'RouteTargetForm', @@ -203,6 +204,23 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): } +class PrefixAssignForm(BootstrapMixin, forms.Form): + site_id = DynamicModelChoiceField( + queryset=Site.objects.all(), + required=False, + label='Site' + ) + vrf_id = DynamicModelChoiceField( + queryset=VRF.objects.all(), + required=False, + label='VRF' + ) + q = forms.CharField( + required=False, + label='Search', + ) + + class IPRangeForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 410af78f1..ad41c4427 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -16,6 +16,7 @@ __all__ = ( 'IPAddressTable', 'IPRangeTable', 'PrefixTable', + 'PrefixAssignTable', 'RIRTable', 'RoleTable', ) @@ -43,6 +44,10 @@ PREFIXFLAT_LINK = """ {% endif %} """ +PREFIX_ASSIGN_LINK = """ +{{ record }} +""" + IPADDRESS_LINK = """ {% if record.pk %} {{ record.address }} @@ -246,6 +251,23 @@ class PrefixTable(BaseTable): } +class PrefixAssignTable(BaseTable): + prefix = tables.TemplateColumn( + template_code=PREFIX_ASSIGN_LINK, + verbose_name='Prefix' + ) + status = ChoiceFieldColumn() + is_pool = BooleanColumn( + verbose_name='Pool' + ) + + class Meta(BaseTable.Meta): + model = Prefix + fields = ('prefix', 'site', 'vrf', 'tenant', 'status', 'role', 'vlan', 'is_pool', 'description') + exclude = ('id', ) + orderable = False + + # # IP ranges # diff --git a/netbox/ipam/urls.py b/netbox/ipam/urls.py index 9d9a846bf..192bcfe64 100644 --- a/netbox/ipam/urls.py +++ b/netbox/ipam/urls.py @@ -71,6 +71,7 @@ urlpatterns = [ path('prefixes/import/', views.PrefixBulkImportView.as_view(), name='prefix_import'), path('prefixes/edit/', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), path('prefixes/delete/', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), + path('prefixes/assign/', views.PrefixAssignView.as_view(), name='prefix_assign'), path('prefixes//', views.PrefixView.as_view(), name='prefix'), path('prefixes//edit/', views.PrefixEditView.as_view(), name='prefix_edit'), path('prefixes//delete/', views.PrefixDeleteView.as_view(), name='prefix_delete'), diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index c24a80124..7a252e9d1 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -494,6 +494,47 @@ class PrefixIPAddressesView(generic.ObjectView): class PrefixEditView(generic.ObjectEditView): queryset = Prefix.objects.all() model_form = forms.PrefixForm + template_name = 'ipam/prefix_edit.html' + + +# TODO: Standardize or remove this view +class PrefixAssignView(generic.ObjectView): + """ + Search for Prefixes to assign to a VLAN + """ + queryset = Prefix.objects.all() + + def dispatch(self, request, *args, **kwargs): + + # Redirect the user if a VLAN has not been provided + if 'vlan' not in request.GET: + return redirect('ipam:prefix_add') + + return super().dispatch(request, *args, **kwargs) + + def get(self, request): + form = forms.PrefixAssignForm() + + return render(request, 'ipam/prefix_assign.html', { + 'form': form, + 'return_url': request.GET.get('return_url', ''), + }) + + def post(self, request): + form = forms.PrefixAssignForm(request.POST) + table = None + + if form.is_valid(): + prefixes = self.queryset.prefetch_related('site', 'vrf', 'tenant') + # Limit to 100 results + prefixes = filtersets.PrefixFilterSet(request.POST, prefixes).qs[:100] + table = tables.PrefixAssignTable(prefixes) + + return render(request, 'ipam/prefix_assign.html', { + 'form': form, + 'table': table, + 'return_url': request.GET.get('return_url'), + }) class PrefixDeleteView(generic.ObjectDeleteView): diff --git a/netbox/templates/ipam/inc/prefix_edit_header.html b/netbox/templates/ipam/inc/prefix_edit_header.html new file mode 100644 index 000000000..9f4df085e --- /dev/null +++ b/netbox/templates/ipam/inc/prefix_edit_header.html @@ -0,0 +1,22 @@ +{% load helpers %} + + + + + {% if obj.pk %}Edit{% else %}Create{% endif %} + + + {% if 'vlan' in request.GET %} + + + Assign Prefix + + + {% endif %} + diff --git a/netbox/templates/ipam/prefix_assign.html b/netbox/templates/ipam/prefix_assign.html new file mode 100644 index 000000000..fafcfde10 --- /dev/null +++ b/netbox/templates/ipam/prefix_assign.html @@ -0,0 +1,46 @@ +{% extends 'generic/object_edit.html' %} +{% load static %} +{% load form_helpers %} +{% load helpers %} + +{% block title %}Assign a Prefix{% endblock title %} + +{% block tabs %} + {% include 'ipam/inc/prefix_edit_header.html' with active_tab='assign' %} +{% endblock %} + +{% block form %} + + {% csrf_token %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} + + + + Select Prefix + {% render_field form.site_id %} + {% render_field form.vrf_id %} + {% render_field form.q %} + + + + + + Cancel + Search + + + + {% if table %} + + + Search Results + {% include 'utilities/obj_table.html' %} + + + {% endif %} +{% endblock form %} + +{% block buttons %} +{% endblock buttons%} diff --git a/netbox/templates/ipam/prefix_edit.html b/netbox/templates/ipam/prefix_edit.html new file mode 100644 index 000000000..8480ad2e1 --- /dev/null +++ b/netbox/templates/ipam/prefix_edit.html @@ -0,0 +1,8 @@ +{% extends 'generic/object_edit.html' %} +{% load static %} +{% load form_helpers %} +{% load helpers %} + +{% block tabs %} + {% include 'ipam/inc/prefix_edit_header.html' with active_tab='add' %} +{% endblock tabs %}