Skip to content

Commit

Permalink
Merge pull request netbox-community#474 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.5.2
  • Loading branch information
jeremystretch authored Aug 16, 2016
2 parents 20b800b + 28b836a commit 0a36662
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 9 deletions.
7 changes: 7 additions & 0 deletions netbox/dcim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,13 @@ class Meta:
def __unicode__(self):
return self.name

def clean(self):

if self.form_factor == IFACE_FF_VIRTUAL and self.is_connected:
raise ValidationError({'form_factor': "Virtual interfaces cannot be connected to another interface or "
"circuit. Disconnect the interface or choose a physical form "
"factor."})

@property
def is_physical(self):
return self.form_factor != IFACE_FF_VIRTUAL
Expand Down
7 changes: 4 additions & 3 deletions netbox/extras/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
)

EXPORTTEMPLATE_MODELS = [
'site', 'rack', 'device', 'consoleport', 'powerport', 'interfaceconnection',
'aggregate', 'prefix', 'ipaddress', 'vlan',
'provider', 'circuit'
'site', 'rack', 'device', 'consoleport', 'powerport', 'interfaceconnection', # DCIM
'aggregate', 'prefix', 'ipaddress', 'vlan', # IPAM
'provider', 'circuit', # Circuits
'tenant', # Tenants
]

ACTION_CREATE = 1
Expand Down
17 changes: 17 additions & 0 deletions netbox/ipam/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.core.urlresolvers import reverse
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models.expressions import RawSQL

from dcim.models import Interface
from tenancy.models import Tenant
Expand Down Expand Up @@ -295,6 +296,20 @@ def get_status_class(self):
return STATUS_CHOICE_CLASSES[self.status]


class IPAddressManager(models.Manager):

def get_queryset(self):
"""
By default, PostgreSQL will order INETs with shorter (larger) prefix lengths ahead of those with longer
(smaller) masks. This makes no sense when ordering IPs, which should be ordered solely by family and host
address. We can use HOST() to extract just the host portion of the address (ignoring its mask), but we must
then re-cast this value to INET() so that records will be ordered properly. We are essentially re-casting each
IP address as a /32 or /128.
"""
qs = super(IPAddressManager, self).get_queryset()
return qs.annotate(host=RawSQL('INET(HOST(ipam_ipaddress.address))', [])).order_by('family', 'host')


class IPAddress(CreatedUpdatedModel):
"""
An IPAddress represents an individual IPv4 or IPv6 address and its mask. The mask length should match what is
Expand All @@ -317,6 +332,8 @@ class IPAddress(CreatedUpdatedModel):
null=True, verbose_name='NAT IP (inside)')
description = models.CharField(max_length=100, blank=True)

objects = IPAddressManager()

class Meta:
ordering = ['family', 'address']
verbose_name = 'IP address'
Expand Down
2 changes: 1 addition & 1 deletion netbox/netbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"the documentation.")


VERSION = '1.5.1'
VERSION = '1.5.2'

# Import local configuration
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
Expand Down
10 changes: 8 additions & 2 deletions netbox/project-static/js/livesearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ $(document).ready(function() {
}

// Update livesearch text when real field changes
search_field.val(real_field.children('option:selected').text());
real_field.change(function() {
if (real_field.val()) {
search_field.val(real_field.children('option:selected').text());
}
real_field.change(function() {
if (real_field.val()) {
search_field.val(real_field.children('option:selected').text());
} else {
search_field.val('');
}
});

search_field.autocomplete({
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/circuits/circuit_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a circuit
</a>
<a href="{% url 'circuits:circuit_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import circuits
</a>
{% endif %}
{% include 'inc/export_button.html' with obj_type='circuits' %}
</div>
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/circuits/provider_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a provider
</a>
<a href="{% url 'circuits:provider_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import providers
</a>
{% endif %}
{% include 'inc/export_button.html' with obj_type='providers' %}
</div>
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/dcim/inc/_interface.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
<a href="{% url 'dcim:interfaceconnection_delete' pk=iface.connection.pk %}?device={{ device.pk }}" class="btn btn-danger btn-xs" title="Delete connection">
<i class="glyphicon glyphicon-remove" aria-hidden="true"></i>
</a>
{% elif iface.circuit and perms.circuits.change_circuit %}
<a href="{% url 'circuits:circuit_edit' pk=iface.circuit.pk %}" class="btn btn-danger btn-xs" title="Edit circuit">
<i class="glyphicon glyphicon-remove" aria-hidden="true"></i>
</a>
{% else %}
<a href="{% url 'dcim:interfaceconnection_add' pk=device.pk %}?interface={{ iface.pk }}" class="btn btn-success btn-xs" title="Connect">
<i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/ipam/aggregate_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add an aggregate
</a>
<a href="{% url 'ipam:aggregate_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import aggregates
</a>
{% endif %}
{% include 'inc/export_button.html' with obj_type='aggregates' %}
</div>
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/tenancy/tenant_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a tenant
</a>
<a href="{% url 'tenancy:tenant_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import tenants
</a>
{% endif %}
{% include 'inc/export_button.html' with obj_type='tenants' %}
</div>
Expand Down
12 changes: 9 additions & 3 deletions netbox/tenancy/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Count
from django.db.models import Count, Q
from django.shortcuts import get_object_or_404, render

from circuits.models import Circuit
Expand Down Expand Up @@ -59,8 +59,14 @@ def tenant(request, slug):
'rack_count': Rack.objects.filter(tenant=tenant).count(),
'device_count': Device.objects.filter(tenant=tenant).count(),
'vrf_count': VRF.objects.filter(tenant=tenant).count(),
'prefix_count': Prefix.objects.filter(tenant=tenant).count(),
'ipaddress_count': IPAddress.objects.filter(tenant=tenant).count(),
'prefix_count': Prefix.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'ipaddress_count': IPAddress.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'vlan_count': VLAN.objects.filter(tenant=tenant).count(),
'circuit_count': Circuit.objects.filter(tenant=tenant).count(),
}
Expand Down

0 comments on commit 0a36662

Please sign in to comment.