Merge pull request #1720 from digitalocean/develop

Release v2.2.6
This commit is contained in:
Jeremy Stretch 2017-11-16 12:00:34 -05:00 committed by GitHub
commit 50a451eddc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 87 additions and 16 deletions

View File

@ -1120,6 +1120,8 @@ class ConsoleServerPort(models.Model):
def clean(self):
# Check that the parent device's DeviceType is a console server
if self.device is None:
raise ValidationError("Console server ports must be assigned to devices.")
device_type = self.device.device_type
if not device_type.is_console_server:
raise ValidationError("The {} {} device type not support assignment of console server ports.".format(
@ -1194,6 +1196,8 @@ class PowerOutlet(models.Model):
def clean(self):
# Check that the parent device's DeviceType is a PDU
if self.device is None:
raise ValidationError("Power outlets must be assigned to devices.")
device_type = self.device.device_type
if not device_type.is_pdu:
raise ValidationError("The {} {} device type not support assignment of power outlets.".format(
@ -1257,11 +1261,12 @@ class Interface(models.Model):
def clean(self):
# Check that the parent device's DeviceType is a network device
device_type = self.device.device_type
if not device_type.is_network_device:
raise ValidationError("The {} {} device type not support assignment of network interfaces.".format(
device_type.manufacturer, device_type
))
if self.device is not None:
device_type = self.device.device_type
if not device_type.is_network_device:
raise ValidationError("The {} {} device type not support assignment of network interfaces.".format(
device_type.manufacturer, device_type
))
# An Interface must belong to a Device *or* to a VirtualMachine
if self.device and self.virtual_machine:

View File

@ -689,7 +689,7 @@ class IPAddressBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
class IPAddressAssignForm(BootstrapMixin, forms.Form):
vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF')
vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', empty_label='Global')
address = forms.CharField(label='IP Address')

View File

@ -304,6 +304,16 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
return available_ips
def get_first_available_ip(self):
"""
Return the first available IP within the prefix (or None).
"""
available_ips = self.get_available_ips()
if available_ips:
return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen)
else:
return None
def get_utilization(self):
"""
Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of

View File

@ -13,7 +13,7 @@ except ImportError:
)
VERSION = '2.2.5'
VERSION = '2.2.6'
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

View File

@ -35,8 +35,22 @@ footer p {
margin: 20px 0;
}
/* Collapse the nav menu on displays less than 1200px wide */
/* Hide the username in the navigation menu on displays less than 1400px wide */
@media (max-width: 1399px) {
#navbar_user {
display: none;
}
}
/* Hide the search bar in the navigation menu on displays less than 1200px wide */
@media (max-width: 1199px) {
#navbar_search {
display: none;
}
}
/* Collapse the nav menu on displays less than 960px wide */
@media (max-width: 959px) {
.navbar-header {
float: none;
}
@ -72,12 +86,8 @@ footer p {
.collapse.in {
display:block !important;
}
}
/* Hide the nav search bar on displays less than 1600px wide */
@media (max-width: 1599px) {
#navbar_search {
display: none;
#navbar_user {
display: inline;
}
}

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a circuit type
</a>
<a href="{% url 'circuits:circuittype_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import circuit types
</a>
{% endif %}
</div>
<h1>{% block title %}Circuit Types{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a device role
</a>
<a href="{% url 'dcim:devicerole_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import device roles
</a>
{% endif %}
</div>
<h1>{% block title %}Device Roles{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a platform
</a>
<a href="{% url 'dcim:platform_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import platforms
</a>
{% endif %}
</div>
<h1>{% block title %}Platforms{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a rack role
</a>
<a href="{% url 'dcim:rackrole_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import rack roles
</a>
{% endif %}
</div>
<h1>{% block title %}Rack Roles{% endblock %}</h1>

View File

@ -379,7 +379,9 @@
{% if request.user.is_authenticated %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" title="{{ request.user }}" role="button" aria-haspopup="true" aria-expanded="false">
{{ request.user|truncatechars:"30" }} <span class="caret"></span>
<i class="fa fa-user"></i>
<span id="navbar_user">{{ request.user|truncatechars:"30" }}</span>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{% url 'user:profile' %}"><i class="fa fa-user"></i> Profile</a></li>

View File

@ -23,7 +23,7 @@
</div>
<div class="pull-right">
{% if perms.ipam.add_ipaddress %}
<a href="{% url 'ipam:ipaddress_add' %}?address={{ prefix.prefix }}{% if prefix.vrf %}&vrf={{ prefix.vrf.pk }}{% endif %}{% if prefix.tenant %}&tenant={{ prefix.tenant.pk }}{% endif %}" class="btn btn-success">
<a href="{% url 'ipam:ipaddress_add' %}?address={{ prefix.get_first_available_ip }}{% if prefix.vrf %}&vrf={{ prefix.vrf.pk }}{% endif %}{% if prefix.tenant %}&tenant={{ prefix.tenant.pk }}{% endif %}" class="btn btn-success">
<span class="fa fa-plus" aria-hidden="true"></span>
Add an IP Address
</a>

View File

@ -20,6 +20,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a RIR
</a>
<a href="{% url 'ipam:rir_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import RIRs
</a>
{% endif %}
</div>
<h1>{% block title %}RIRs{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a role
</a>
<a href="{% url 'ipam:role_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import roles
</a>
{% endif %}
</div>
<h1>{% block title %}Prefix/VLAN Roles{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a VLAN group
</a>
<a href="{% url 'ipam:vlangroup_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import VLAN groups
</a>
{% endif %}
</div>
<h1>{% block title %}VLAN Groups{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a secret role
</a>
<a href="{% url 'secrets:secretrole_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import secret roles
</a>
{% endif %}
</div>
<h1>{% block title %}Secret Roles{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a tenant group
</a>
<a href="{% url 'tenancy:tenantgroup_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import tenant groups
</a>
{% endif %}
</div>
<h1>{% block title %}Tenant Groups{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a cluster group
</a>
<a href="{% url 'virtualization:clustergroup_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import cluster groups
</a>
{% endif %}
</div>
<h1>{% block title %}Cluster Groups{% endblock %}</h1>

View File

@ -8,6 +8,10 @@
<span class="fa fa-plus" aria-hidden="true"></span>
Add a cluster type
</a>
<a href="{% url 'virtualization:clustertype_import' %}" class="btn btn-info">
<span class="fa fa-download" aria-hidden="true"></span>
Import cluster types
</a>
{% endif %}
</div>
<h1>{% block title %}Cluster Types{% endblock %}</h1>