mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 19:47:20 -06:00
commit
50a451eddc
@ -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:
|
||||
|
@ -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')
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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__)))
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user