Browse Source

Added views to create device component templates

Jeremy Stretch 9 years ago
parent
commit
009ef41e92

+ 46 - 1
netbox/dcim/forms.py

@@ -8,7 +8,8 @@ from utilities.forms import BootstrapMixin, SmallTextarea, SelectWithDisabled, C
     Livesearch, CSVDataField, CommentField, BulkImportForm, FlexibleModelChoiceField, ExpandableNameField
     Livesearch, CSVDataField, CommentField, BulkImportForm, FlexibleModelChoiceField, ExpandableNameField
 
 
 from .models import Site, Rack, RackGroup, Device, Manufacturer, DeviceType, DeviceRole, Platform, ConsolePort, \
 from .models import Site, Rack, RackGroup, Device, Manufacturer, DeviceType, DeviceRole, Platform, ConsolePort, \
-    ConsoleServerPort, PowerPort, PowerOutlet, Interface, InterfaceConnection, CONNECTION_STATUS_CHOICES, \
+    ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, PowerPort, PowerPortTemplate, PowerOutlet, \
+    PowerOutletTemplate, Interface, InterfaceTemplate, InterfaceConnection, CONNECTION_STATUS_CHOICES, \
     CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED, IFACE_FF_VIRTUAL, STATUS_CHOICES
     CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED, IFACE_FF_VIRTUAL, STATUS_CHOICES
 
 
 
 
@@ -192,6 +193,50 @@ class DeviceTypeFilterForm(forms.Form, BootstrapMixin):
 
 
 
 
 #
 #
+# Device component templates
+#
+
+class ConsolePortTemplateForm(forms.ModelForm, BootstrapMixin):
+    name_pattern = ExpandableNameField(label='Name')
+
+    class Meta:
+        model = ConsolePortTemplate
+        fields = ['name_pattern']
+
+
+class ConsoleServerPortTemplateForm(forms.ModelForm, BootstrapMixin):
+    name_pattern = ExpandableNameField(label='Name')
+
+    class Meta:
+        model = ConsoleServerPortTemplate
+        fields = ['name_pattern']
+
+
+class PowerPortTemplateForm(forms.ModelForm, BootstrapMixin):
+    name_pattern = ExpandableNameField(label='Name')
+
+    class Meta:
+        model = PowerPortTemplate
+        fields = ['name_pattern']
+
+
+class PowerOutletTemplateForm(forms.ModelForm, BootstrapMixin):
+    name_pattern = ExpandableNameField(label='Name')
+
+    class Meta:
+        model = PowerOutletTemplate
+        fields = ['name_pattern']
+
+
+class InterfaceTemplateForm(forms.ModelForm, BootstrapMixin):
+    name_pattern = ExpandableNameField(label='Name')
+
+    class Meta:
+        model = InterfaceTemplate
+        fields = ['name_pattern', 'form_factor', 'mgmt_only']
+
+
+#
 # Devices
 # Devices
 #
 #
 
 

+ 12 - 0
netbox/dcim/urls.py

@@ -3,6 +3,8 @@ from django.conf.urls import url
 from secrets.views import secret_add
 from secrets.views import secret_add
 
 
 from . import views
 from . import views
+from .forms import ConsolePortTemplateForm
+
 
 
 urlpatterns = [
 urlpatterns = [
 
 
@@ -32,6 +34,16 @@ urlpatterns = [
     url(r'^device-types/(?P<pk>\d+)/$', views.devicetype, name='devicetype'),
     url(r'^device-types/(?P<pk>\d+)/$', views.devicetype, name='devicetype'),
     url(r'^device-types/(?P<pk>\d+)/edit/$', views.devicetype_edit, name='devicetype_edit'),
     url(r'^device-types/(?P<pk>\d+)/edit/$', views.devicetype_edit, name='devicetype_edit'),
     url(r'^device-types/(?P<pk>\d+)/delete/$', views.devicetype_delete, name='devicetype_delete'),
     url(r'^device-types/(?P<pk>\d+)/delete/$', views.devicetype_delete, name='devicetype_delete'),
+    url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortTemplateAddView.as_view(),
+        name='devicetype_add_consoleport'),
+    url(r'^device-types/(?P<pk>\d+)/console-server-ports/add/$', views.ConsolePortTemplateAddView.as_view(),
+        name='devicetype_add_consoleserverport'),
+    url(r'^device-types/(?P<pk>\d+)/power-ports/add/$', views.PowerPortTemplateAddView.as_view(),
+        name='devicetype_add_powerport'),
+    url(r'^device-types/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletTemplateAddView.as_view(),
+        name='devicetype_add_poweroutlet'),
+    url(r'^device-types/(?P<pk>\d+)/interfaces/add/$', views.InterfaceTemplateAddView.as_view(),
+        name='devicetype_add_interface'),
 
 
     # Devices
     # Devices
     url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),
     url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),

+ 80 - 2
netbox/dcim/views.py

@@ -3,11 +3,13 @@ import re
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.auth.mixins import PermissionRequiredMixin
+from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.db.models import Count, ProtectedError
 from django.db.models import Count, ProtectedError
 from django.http import HttpResponseRedirect
 from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.http import urlencode
 from django.utils.http import urlencode
+from django.views.generic import View
 
 
 from ipam.models import Prefix, IPAddress, VLAN
 from ipam.models import Prefix, IPAddress, VLAN
 from circuits.models import Circuit
 from circuits.models import Circuit
@@ -25,8 +27,10 @@ from .forms import SiteForm, SiteImportForm, RackForm, RackImportForm, RackBulkE
     PowerPortCreateForm, PowerPortConnectionForm, PowerConnectionImportForm, PowerOutletForm, PowerOutletCreateForm, \
     PowerPortCreateForm, PowerPortConnectionForm, PowerConnectionImportForm, PowerOutletForm, PowerOutletCreateForm, \
     PowerOutletConnectionForm, InterfaceForm, InterfaceCreateForm, InterfaceBulkCreateForm, InterfaceConnectionForm, \
     PowerOutletConnectionForm, InterfaceForm, InterfaceCreateForm, InterfaceBulkCreateForm, InterfaceConnectionForm, \
     InterfaceConnectionDeletionForm, InterfaceConnectionImportForm, ConsoleConnectionFilterForm, \
     InterfaceConnectionDeletionForm, InterfaceConnectionImportForm, ConsoleConnectionFilterForm, \
-    PowerConnectionFilterForm, InterfaceConnectionFilterForm, IPAddressForm
-from .models import Site, Rack, DeviceType, Device, ConsolePort, ConsoleServerPort, PowerPort, PowerOutlet, Interface, \
+    PowerConnectionFilterForm, InterfaceConnectionFilterForm, IPAddressForm, ConsolePortTemplateForm, \
+    ConsoleServerPortTemplateForm, PowerPortTemplateForm, PowerOutletTemplateForm, InterfaceTemplateForm
+from .models import Site, Rack, DeviceType, ConsolePortTemplate, ConsoleServerPortTemplate, PowerPortTemplate, \
+    PowerOutletTemplate, InterfaceTemplate, Device, ConsolePort, ConsoleServerPort, PowerPort, PowerOutlet, Interface, \
     InterfaceConnection, Module, CONNECTION_STATUS_CONNECTED
     InterfaceConnection, Module, CONNECTION_STATUS_CONNECTED
 from .tables import SiteTable, RackTable, RackBulkEditTable, DeviceTypeTable, DeviceTypeBulkEditTable, DeviceTable, \
 from .tables import SiteTable, RackTable, RackBulkEditTable, DeviceTypeTable, DeviceTypeBulkEditTable, DeviceTable, \
     DeviceBulkEditTable, DeviceImportTable, ConsoleConnectionTable, PowerConnectionTable, InterfaceConnectionTable
     DeviceBulkEditTable, DeviceImportTable, ConsoleConnectionTable, PowerConnectionTable, InterfaceConnectionTable
@@ -428,6 +432,80 @@ class DeviceTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     redirect_url = 'dcim:devicetype_list'
     redirect_url = 'dcim:devicetype_list'
 
 
 
 
+class ComponentTemplateCreateView(View):
+    model = None
+    form = None
+
+    def get(self, request, pk, *args, **kwargs):
+
+        devicetype = get_object_or_404(DeviceType, pk=pk)
+
+        return render(request, 'dcim/component_template_add.html', {
+            'devicetype': devicetype,
+            'component_type': self.model._meta.verbose_name,
+            'form': self.form(),
+            'cancel_url': reverse('dcim:devicetype', kwargs={'pk': devicetype.pk}),
+        })
+
+    def post(self, request, pk, *args, **kwargs):
+
+        devicetype = get_object_or_404(DeviceType, pk=pk)
+
+        form = self.form(request.POST)
+        if form.is_valid():
+
+            component_templates = []
+            for name in form.cleaned_data['name_pattern']:
+                component_template = self.form(request.POST).save(commit=False)
+                component_template.device_type = devicetype
+                component_template.name = name
+                try:
+                    component_template.full_clean()
+                    component_templates.append(component_template)
+                except ValidationError:
+                    form.add_error('name_pattern', "Duplicate name found: {}".format(name))
+
+            if not form.errors:
+                self.model.objects.bulk_create(component_templates)
+                messages.success(request, "Added {} compontent(s) to {}".format(len(component_templates), devicetype))
+                if '_addanother' in request.POST:
+                    return redirect(request.path)
+                else:
+                    return redirect('dcim:devicetype', pk=devicetype.pk)
+
+        return render(request, 'dcim/component_template_add.html', {
+            'devicetype': devicetype,
+            'component_type': self.model._meta.verbose_name,
+            'form': form,
+            'cancel_url': reverse('dcim:devicetype', kwargs={'pk': devicetype.pk}),
+        })
+
+
+class ConsolePortTemplateAddView(ComponentTemplateCreateView):
+    model = ConsolePortTemplate
+    form = ConsolePortTemplateForm
+
+
+class ConsoleServerPortTemplateAddView(ComponentTemplateCreateView):
+    model = ConsoleServerPortTemplate
+    form = ConsoleServerPortTemplateForm
+
+
+class PowerPortTemplateAddView(ComponentTemplateCreateView):
+    model = PowerPortTemplate
+    form = PowerPortTemplateForm
+
+
+class PowerOutletTemplateAddView(ComponentTemplateCreateView):
+    model = PowerOutletTemplate
+    form = PowerOutletTemplateForm
+
+
+class InterfaceTemplateAddView(ComponentTemplateCreateView):
+    model = InterfaceTemplate
+    form = InterfaceTemplateForm
+
+
 #
 #
 # Devices
 # Devices
 #
 #

+ 42 - 0
netbox/templates/dcim/component_template_add.html

@@ -0,0 +1,42 @@
+{% extends '_base.html' %}
+{% load form_helpers %}
+
+{% block title %}Add {{ component_type }} to {{ devicetype }}{% endblock %}
+
+{% block content %}
+<form action="." method="post" class="form form-horizontal">
+    {% csrf_token %}
+    <div class="row">
+        <div class="col-md-6 col-md-offset-3">
+            {% if form.non_field_errors %}
+                <div class="panel panel-danger">
+                    <div class="panel-heading"><strong>Errors</strong></div>
+                    <div class="panel-body">
+                        {{ form.non_field_errors }}
+                    </div>
+                </div>
+            {% endif %}
+            <div class="panel panel-default">
+                <div class="panel-heading">
+                    <strong>New {{ component_type }}</strong>
+                </div>
+                <div class="panel-body">
+                    <div class="form-group">
+                        <label class="col-md-3 control-label required">Device Type</label>
+                        <div class="col-md-9">
+                            <p class="form-control-static">{{ devicetype }}</p>
+                        </div>
+                    </div>
+                    {% render_form form %}
+                </div>
+            </div>
+		    <div class="form-group">
+                <div class="col-md-9 col-md-offset-3">
+                    <button type="submit" name="_update" class="btn btn-primary">Save</button>
+                    <a href="{{ cancel_url }}" class="btn btn-default">Cancel</a>
+                </div>
+		    </div>
+        </div>
+    </div>
+</form>
+{% endblock %}

+ 15 - 0
netbox/templates/dcim/devicetype.html

@@ -75,6 +75,9 @@
         </div>
         </div>
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
+                {% if perms.dcim.change_devicetype %}
+                    <a href="{% url 'dcim:devicetype_add_consoleport' pk=devicetype.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Console Ports</a>
+                {% endif %}
                 <strong>Console Ports</strong>
                 <strong>Console Ports</strong>
             </div>
             </div>
             <table class="table table-hover panel-body">
             <table class="table table-hover panel-body">
@@ -88,6 +91,9 @@
         </div>
         </div>
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
+                {% if perms.dcim.change_devicetype %}
+                    <a href="{% url 'dcim:devicetype_add_powerport' pk=devicetype.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Power Ports</a>
+                {% endif %}
                 <strong>Power Ports</strong>
                 <strong>Power Ports</strong>
             </div>
             </div>
             <table class="table table-hover panel-body">
             <table class="table table-hover panel-body">
@@ -103,6 +109,9 @@
 	<div class="col-md-6">
 	<div class="col-md-6">
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
+                {% if perms.dcim.change_devicetype %}
+                    <a href="{% url 'dcim:devicetype_add_interface' pk=devicetype.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Interfaces</a>
+                {% endif %}
                 <strong>Interfaces</strong>
                 <strong>Interfaces</strong>
             </div>
             </div>
             <table class="table table-hover panel-body">
             <table class="table table-hover panel-body">
@@ -118,6 +127,9 @@
         </div>
         </div>
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
+                {% if perms.dcim.change_devicetype %}
+                    <a href="{% url 'dcim:devicetype_add_consoleserverport' pk=devicetype.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Console Server Ports</a>
+                {% endif %}
                 <strong>Console Server Ports</strong>
                 <strong>Console Server Ports</strong>
             </div>
             </div>
             <table class="table table-hover panel-body">
             <table class="table table-hover panel-body">
@@ -131,6 +143,9 @@
         </div>
         </div>
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
+                {% if perms.dcim.change_devicetype %}
+                    <a href="{% url 'dcim:devicetype_add_poweroutlet' pk=devicetype.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Power Outlet</a>
+                {% endif %}
                 <strong>Power Outlets</strong>
                 <strong>Power Outlets</strong>
             </div>
             </div>
             <table class="table table-hover panel-body">
             <table class="table table-hover panel-body">