1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Introduced ability to edit/delete modules

This commit is contained in:
Jeremy Stretch
2016-06-15 13:27:12 -04:00
parent 4258e40ec1
commit 4b34af3e1d
10 changed files with 182 additions and 6 deletions

View File

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

View File

@@ -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']

View File

@@ -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'),
),
]

View File

@@ -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']

View File

@@ -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'),
]

View File

@@ -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}),
})

View File

@@ -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!")

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}