Parcourir la source

Introduced ability to edit/delete modules

Jeremy Stretch il y a 8 ans
Parent
commit
4b34af3e1d

+ 1 - 1
netbox/dcim/admin.py

@@ -146,7 +146,7 @@ class InterfaceAdmin(admin.TabularInline):
 
 class ModuleAdmin(admin.TabularInline):
     model = Module
-    readonly_fields = ['parent']
+    readonly_fields = ['parent', 'discovered']
 
 
 @admin.register(Device)

+ 12 - 1
netbox/dcim/forms.py

@@ -12,7 +12,7 @@ from utilities.forms import (
 from .models import (
     CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED, ConsolePort, ConsolePortTemplate,
     ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType, Interface, IFACE_FF_VIRTUAL,
-    InterfaceConnection, InterfaceTemplate, Manufacturer, Platform, PowerOutlet, PowerOutletTemplate, PowerPort,
+    InterfaceConnection, InterfaceTemplate, Manufacturer, Module, Platform, PowerOutlet, PowerOutletTemplate, PowerPort,
     PowerPortTemplate, Rack, RackGroup, Site, STATUS_CHOICES
 )
 
@@ -1107,3 +1107,14 @@ class IPAddressForm(forms.ModelForm, BootstrapMixin):
         # If this device does not have any IP addresses assigned, default to setting the first IP as its primary
         if not IPAddress.objects.filter(interface__device=device).count():
             self.fields['set_as_primary'].initial = True
+
+
+#
+# Interfaces
+#
+
+class ModuleForm(forms.ModelForm, BootstrapMixin):
+
+    class Meta:
+        model = Module
+        fields = ['name', 'part_id', 'serial']

+ 20 - 0
netbox/dcim/migrations/0007_module_discovered.py

@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.5 on 2016-06-15 16:31
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0006_remove_device_ro_snmp'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='module',
+            name='discovered',
+            field=models.BooleanField(default=False, verbose_name=b'Discovered'),
+        ),
+    ]

+ 1 - 1
netbox/dcim/models.py

@@ -692,7 +692,6 @@ class InterfaceConnection(models.Model):
                                             verbose_name='Status')
 
     def clean(self):
-
         if self.interface_a == self.interface_b:
             raise ValidationError("Cannot connect an interface to itself")
 
@@ -706,6 +705,7 @@ class Module(models.Model):
     name = models.CharField(max_length=50, verbose_name='Name')
     part_id = models.CharField(max_length=50, verbose_name='Part ID', blank=True)
     serial = models.CharField(max_length=50, verbose_name='Serial number', blank=True)
+    discovered = models.BooleanField(default=False, verbose_name='Discovered')
 
     class Meta:
         ordering = ['device__id', 'parent__id', 'name']

+ 4 - 0
netbox/dcim/urls.py

@@ -141,4 +141,8 @@ urlpatterns = [
     url(r'^interfaces/(?P<pk>\d+)/edit/$', views.interface_edit, name='interface_edit'),
     url(r'^interfaces/(?P<pk>\d+)/delete/$', views.interface_delete, name='interface_delete'),
 
+    # Modules
+    url(r'^modules/(?P<pk>\d+)/edit/$', views.module_edit, name='module_edit'),
+    url(r'^modules/(?P<pk>\d+)/delete/$', views.module_delete, name='module_delete'),
+
 ]

+ 48 - 0
netbox/dcim/views.py

@@ -1497,3 +1497,51 @@ def ipaddress_assign(request, pk):
         'form': form,
         'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
     })
+
+
+#
+# Modules
+#
+
+@permission_required('dcim.change_module')
+def module_edit(request, pk):
+
+    module = get_object_or_404(Module, pk=pk)
+
+    if request.method == 'POST':
+        form = forms.ModuleForm(request.POST, instance=module)
+        if form.is_valid():
+            module = form.save()
+            messages.success(request, "Modified {} module {}".format(module.device.name, module.name))
+            return redirect('dcim:device_inventory', pk=module.device.pk)
+
+    else:
+        form = forms.ModuleForm(instance=module)
+
+    return render(request, 'dcim/module_edit.html', {
+        'module': module,
+        'form': form,
+        'cancel_url': reverse('dcim:device_inventory', kwargs={'pk': module.device.pk}),
+    })
+
+
+@permission_required('dcim.delete_module')
+def module_delete(request, pk):
+
+    module = get_object_or_404(Module, pk=pk)
+
+    if request.method == 'POST':
+        form = ConfirmationForm(request.POST)
+        if form.is_valid():
+            module.delete()
+            messages.success(request, "Module {} has been deleted from {}".format(module, module.device))
+            return redirect('dcim:device_inventory', pk=module.device.pk)
+
+    else:
+        form = ConfirmationForm()
+
+    return render(request, 'dcim/module_delete.html', {
+        'module': module,
+        'form': form,
+        'cancel_url': reverse('dcim:device_inventory', kwargs={'pk': module.device.pk}),
+    })

+ 2 - 2
netbox/extras/management/commands/run_inventory.py

@@ -28,7 +28,7 @@ class Command(BaseCommand):
         def create_modules(modules, parent=None):
             for module in modules:
                 m = Module(device=device, parent=parent, name=module['name'], part_id=module['part_id'],
-                           serial=module['serial'])
+                           serial=module['serial'], discovered=True)
                 m.save()
                 create_modules(module.get('modules', []), parent=m)
 
@@ -119,7 +119,7 @@ class Command(BaseCommand):
                     if device.serial != inventory['chassis']['serial']:
                         device.serial = inventory['chassis']['serial']
                         device.save()
-                    Module.objects.filter(device=device).delete()
+                    Module.objects.filter(device=device, discovered=True).delete()
                     create_modules(inventory.get('modules', []))
 
         self.stdout.write("Finished!")

+ 39 - 1
netbox/templates/dcim/device_inventory.html

@@ -42,38 +42,76 @@
             <div class="panel-heading">
                 <strong>Hardware</strong>
             </div>
-            <table class="table table-hover panel-body" id="hardware">
+            <table class="table table-hover table-condensed panel-body" id="hardware">
                 <thead>
                     <tr>
+                        <th></th>
                         <th>Module</th>
                         <th>Part Number</th>
                         <th>Serial Number</th>
+                        <th></th>
                     </tr>
                 </thead>
                 <tbody>
                     {% for m in modules %}
                         <tr>
+                            <td>{% if not m.discovered %}<i class="fa fa-asterisk" title="Manually created"></i>{% endif %}</td>
                             <td>{{ m.name }}</td>
                             <td>{{ m.part_id }}</td>
                             <td>{{ m.serial }}</td>
+                            <td class="text-right">
+                                {% if perms.dcim.change_module %}
+                                    <a href="{% url 'dcim:module_edit' pk=m.pk %}" class="btn btn-xs btn-warning"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span></a>
+                                {% endif %}
+                                {% if perms.dcim.delete_module %}
+                                    <a href="{% url 'dcim:module_delete' pk=m.pk %}" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a>
+                                {% endif %}
+                            </td>
                         </tr>
                         {% for m2 in m.submodules.all %}
                             <tr>
+                                <td>{% if not m.discovered %}<i class="fa fa-asterisk" title="Manually created"></i>{% endif %}</td>
                                 <td style="padding-left: 20px">{{ m2.name }}</td>
                                 <td>{{ m2.part_id }}</td>
                                 <td>{{ m2.serial }}</td>
+                                <td class="text-right">
+                                    {% if perms.dcim.change_module %}
+                                        <a href="{% url 'dcim:module_edit' pk=m.pk %}" class="btn btn-xs btn-warning"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span></a>
+                                    {% endif %}
+                                    {% if perms.dcim.delete_module %}
+                                        <a href="{% url 'dcim:module_delete' pk=m.pk %}" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a>
+                                    {% endif %}
+                                </td>
                             </tr>
                             {% for m3 in m2.submodules.all %}
                                 <tr>
+                                    <td>{% if not m.discovered %}<i class="fa fa-asterisk" title="Manually created"></i>{% endif %}</td>
                                     <td style="padding-left: 40px">{{ m3.name }}</td>
                                     <td>{{ m3.part_id }}</td>
                                     <td>{{ m3.serial }}</td>
+                                    <td class="text-right">
+                                        {% if perms.dcim.change_module %}
+                                            <a href="{% url 'dcim:module_edit' pk=m.pk %}" class="btn btn-xs btn-warning"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span></a>
+                                        {% endif %}
+                                        {% if perms.dcim.delete_module %}
+                                            <a href="{% url 'dcim:module_delete' pk=m.pk %}" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a>
+                                        {% endif %}
+                                    </td>
                                 </tr>
                                 {% for m4 in m3.submodules.all %}
                                     <tr>
+                                        <td>{% if not m.discovered %}<i class="fa fa-asterisk" title="Manually created"></i>{% endif %}</td>
                                         <td style="padding-left: 60px">{{ m4.name }}</td>
                                         <td>{{ m4.part_id }}</td>
                                         <td>{{ m4.serial }}</td>
+                                        <td class="text-right">
+                                            {% if perms.dcim.change_module %}
+                                                <a href="{% url 'dcim:module_edit' pk=m.pk %}" class="btn btn-xs btn-warning"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span></a>
+                                            {% endif %}
+                                            {% if perms.dcim.delete_module %}
+                                                <a href="{% url 'dcim:module_delete' pk=m.pk %}" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a>
+                                            {% endif %}
+                                        </td>
                                     </tr>
                                 {% endfor %}
                             {% endfor %}

+ 8 - 0
netbox/templates/dcim/module_delete.html

@@ -0,0 +1,8 @@
+{% extends 'utilities/confirmation_form.html' %}
+{% load form_helpers %}
+
+{% block title %}Delete module {{ module }}?{% endblock %}
+
+{% block message %}
+    <p>Are you sure you want to delete this module from <strong>{{ module.device }}</strong>?</p>
+{% endblock %}

+ 47 - 0
netbox/templates/dcim/module_edit.html

@@ -0,0 +1,47 @@
+{% extends '_base.html' %}
+{% load form_helpers %}
+
+{% block title %}Editing {{ module.device }} {{ module }}{% 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>Editing {{ module.device }} {{ module }}</strong>
+                </div>
+                <div class="panel-body">
+                    <div class="form-group">
+                        <label class="col-md-3 control-label required">Device</label>
+                        <div class="col-md-9">
+                            <p class="form-control-static">{{ module.device }}</p>
+                        </div>
+                    </div>
+                    {% render_form form %}
+                </div>
+            </div>
+		    <div class="form-group">
+                <div class="col-md-9 col-md-offset-3">
+                    {% if module.pk %}
+                        <button type="submit" name="_update" class="btn btn-primary">Save</button>
+                    {% else %}
+                        <button type="submit" name="_create" class="btn btn-primary">Create</button>
+                        <button type="submit" name="_addanother" class="btn btn-primary">Create and Add More</button>
+                    {% endif %}
+                    <a href="{{ cancel_url }}" class="btn btn-default">Cancel</a>
+                </div>
+		    </div>
+        </div>
+    </div>
+</form>
+{% endblock %}