Merge branch 'develop' into feature

This commit is contained in:
jeremystretch 2022-04-29 09:05:52 -04:00
commit 9ae25e9449
29 changed files with 122 additions and 74 deletions

View File

@ -14,7 +14,7 @@ body:
attributes: attributes:
label: NetBox version label: NetBox version
description: What version of NetBox are you currently running? description: What version of NetBox are you currently running?
placeholder: v3.2.1 placeholder: v3.2.2
validations: validations:
required: true required: true
- type: dropdown - type: dropdown

View File

@ -14,7 +14,7 @@ body:
attributes: attributes:
label: NetBox version label: NetBox version
description: What version of NetBox are you currently running? description: What version of NetBox are you currently running?
placeholder: v3.2.1 placeholder: v3.2.2
validations: validations:
required: true required: true
- type: dropdown - type: dropdown

View File

@ -68,8 +68,7 @@ gunicorn
# Platform-agnostic template rendering engine # Platform-agnostic template rendering engine
# https://github.com/pallets/jinja # https://github.com/pallets/jinja
# Pin to v3.0 for mkdocstrings Jinja2
Jinja2<3.1
# Simple markup language for rendering HTML # Simple markup language for rendering HTML
# https://github.com/Python-Markdown/markdown # https://github.com/Python-Markdown/markdown
@ -85,7 +84,7 @@ mkdocs-material
# Introspection for embedded code # Introspection for embedded code
# https://github.com/mkdocstrings/mkdocstrings # https://github.com/mkdocstrings/mkdocstrings
mkdocstrings<=0.17.0 mkdocstrings[python-legacy]
# Library for manipulating IP prefixes and addresses # Library for manipulating IP prefixes and addresses
# https://github.com/netaddr/netaddr # https://github.com/netaddr/netaddr

View File

@ -1,6 +1,10 @@
# NetBox v3.2 # NetBox v3.2
## v3.2.2 (FUTURE) ## v3.2.3 (FUTURE)
---
## v3.2.2 (2022-04-28)
### Enhancements ### Enhancements
@ -11,15 +15,19 @@
### Bug Fixes ### Bug Fixes
* [#4264](https://github.com/netbox-community/netbox/issues/4264) - Treat 0th IP as unusable for IPv6 prefixes (excluding /127s)
* [#8941](https://github.com/netbox-community/netbox/issues/8941) - Fix dynamic dropdown behavior when browser is zoomed * [#8941](https://github.com/netbox-community/netbox/issues/8941) - Fix dynamic dropdown behavior when browser is zoomed
* [#8959](https://github.com/netbox-community/netbox/issues/8959) - Prevent exception when refreshing scripts list (avoid race condition) * [#8959](https://github.com/netbox-community/netbox/issues/8959) - Prevent exception when refreshing scripts list (avoid race condition)
* [#9132](https://github.com/netbox-community/netbox/issues/9132) - Limit location options by selected site when creating a wireless link * [#9132](https://github.com/netbox-community/netbox/issues/9132) - Limit location options by selected site when creating a wireless link
* [#9133](https://github.com/netbox-community/netbox/issues/9133) - Upgrade script should require Python 3.8 or later * [#9133](https://github.com/netbox-community/netbox/issues/9133) - Upgrade script should require Python 3.8 or later
* [#9138](https://github.com/netbox-community/netbox/issues/9138) - Avoid inadvertent form submission when utilizing quick search field on object lists
* [#9151](https://github.com/netbox-community/netbox/issues/9151) - Child prefix counts not annotated on aggregates list under RIR view * [#9151](https://github.com/netbox-community/netbox/issues/9151) - Child prefix counts not annotated on aggregates list under RIR view
* [#9156](https://github.com/netbox-community/netbox/issues/9156) - Fix loading UserConfig data from fixtures * [#9156](https://github.com/netbox-community/netbox/issues/9156) - Fix loading UserConfig data from fixtures
* [#9158](https://github.com/netbox-community/netbox/issues/9158) - Do not list tags field for CSV forms which do not support tag assignment * [#9158](https://github.com/netbox-community/netbox/issues/9158) - Do not list tags field for CSV forms which do not support tag assignment
* [#9194](https://github.com/netbox-community/netbox/issues/9194) - Support position assignment when add module bays to multiple devices * [#9194](https://github.com/netbox-community/netbox/issues/9194) - Support position assignment when add module bays to multiple devices
* [#9206](https://github.com/netbox-community/netbox/issues/9206) - Show header for comments field under module & module type creation views * [#9206](https://github.com/netbox-community/netbox/issues/9206) - Show header for comments field under module & module type creation views
* [#9222](https://github.com/netbox-community/netbox/issues/9222) - Fix circuit ID display under cable view
* [#9227](https://github.com/netbox-community/netbox/issues/9227) - Fix related object assignment when recording change record for interfaces
--- ---

View File

@ -77,7 +77,7 @@ class ComponentModel(NetBoxModel):
def to_objectchange(self, action): def to_objectchange(self, action):
objectchange = super().to_objectchange(action) objectchange = super().to_objectchange(action)
objectchange.related_object = self.device objectchange.related_object = self.device
return super().to_objectchange(action) return objectchange
@property @property
def parent_object(self): def parent_object(self):

View File

@ -507,16 +507,20 @@ class Prefix(GetAvailablePrefixesMixin, NetBoxModel):
child_ranges.add(iprange.range) child_ranges.add(iprange.range)
available_ips = prefix - child_ips - child_ranges available_ips = prefix - child_ips - child_ranges
# IPv6, pool, or IPv4 /31-/32 sets are fully usable # IPv6 /127's, pool, or IPv4 /31-/32 sets are fully usable
if self.family == 6 or self.is_pool or (self.family == 4 and self.prefix.prefixlen >= 31): if (self.family == 6 and self.prefix.prefixlen >= 127) or self.is_pool or (self.family == 4 and self.prefix.prefixlen >= 31):
return available_ips return available_ips
# For "normal" IPv4 prefixes, omit first and last addresses if self.family == 4:
available_ips -= netaddr.IPSet([ # For "normal" IPv4 prefixes, omit first and last addresses
netaddr.IPAddress(self.prefix.first), available_ips -= netaddr.IPSet([
netaddr.IPAddress(self.prefix.last), netaddr.IPAddress(self.prefix.first),
]) netaddr.IPAddress(self.prefix.last),
])
else:
# For IPv6 prefixes, omit the Subnet-Router anycast address
# per RFC 4291
available_ips -= netaddr.IPSet([netaddr.IPAddress(self.prefix.first)])
return available_ips return available_ips
def get_first_available_ip(self): def get_first_available_ip(self):

View File

@ -185,6 +185,18 @@ class TestPrefix(TestCase):
IPAddress.objects.create(address=IPNetwork('10.0.0.4/24')) IPAddress.objects.create(address=IPNetwork('10.0.0.4/24'))
self.assertEqual(parent_prefix.get_first_available_ip(), '10.0.0.5/24') self.assertEqual(parent_prefix.get_first_available_ip(), '10.0.0.5/24')
def test_get_first_available_ip_ipv6(self):
parent_prefix = Prefix.objects.create(prefix=IPNetwork('2001:db8:500::/64'))
self.assertEqual(parent_prefix.get_first_available_ip(), '2001:db8:500::1/64')
def test_get_first_available_ip_ipv6_rfc3627(self):
parent_prefix = Prefix.objects.create(prefix=IPNetwork('2001:db8:500:4::/126'))
self.assertEqual(parent_prefix.get_first_available_ip(), '2001:db8:500:4::1/126')
def test_get_first_available_ip_ipv6_rfc6164(self):
parent_prefix = Prefix.objects.create(prefix=IPNetwork('2001:db8:500:5::/127'))
self.assertEqual(parent_prefix.get_first_available_ip(), '2001:db8:500:5::/127')
def test_get_utilization_container(self): def test_get_utilization_container(self):
prefixes = ( prefixes = (
Prefix(prefix=IPNetwork('10.0.0.0/24'), status=PrefixStatusChoices.STATUS_CONTAINER), Prefix(prefix=IPNetwork('10.0.0.0/24'), status=PrefixStatusChoices.STATUS_CONTAINER),

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsolePortTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsolePortTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsoleServerPortTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsoleServerPortTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceDeviceBayTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceDeviceBayTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceFrontPortTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceFrontPortTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,44 +4,46 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
<form method="post"> <div class="row mb-3 justify-content-between">
{% csrf_token %} <div class="col col-12 col-lg-4 my-3 my-lg-0 d-flex noprint table-controls">
<div class="row mb-3 justify-content-between"> <div class="input-group input-group-sm">
<div class="col col-12 col-lg-4 my-3 my-lg-0 d-flex noprint table-controls"> <input
<div class="input-group input-group-sm"> type="text"
<input name="q"
type="text" class="form-control"
name="q" placeholder="Quick search"
class="form-control" hx-get="{{ request.full_path }}"
placeholder="Quick search" hx-target="#object_list"
hx-get="{{ request.full_path }}" hx-trigger="keyup changed delay:500ms"
hx-target="#object_list" />
hx-trigger="keyup changed delay:500ms"
/>
</div>
</div>
<div class="col col-md-3 mb-0 d-flex noprint table-controls">
<div class="input-group input-group-sm justify-content-end">
{% if request.user.is_authenticated %}
<button
type="button"
class="btn btn-sm btn-outline-dark"
data-bs-toggle="modal"
data-bs-target="#DeviceInterfaceTable_config"
title="Configure Table">
<i class="mdi mdi-cog"></i> Configure Table
</button>
{% endif %}
<button class="btn btn-sm btn-outline-dark dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="mdi mdi-eye"></i>
</button>
<ul class="dropdown-menu">
<button type="button" class="dropdown-item toggle-enabled" data-state="show">Hide Enabled</button>
<button type="button" class="dropdown-item toggle-disabled" data-state="show">Hide Disabled</button>
</ul>
</div>
</div> </div>
</div> </div>
<div class="col col-md-3 mb-0 d-flex noprint table-controls">
<div class="input-group input-group-sm justify-content-end">
{% if request.user.is_authenticated %}
<button
type="button"
class="btn btn-sm btn-outline-dark"
data-bs-toggle="modal"
data-bs-target="#DeviceInterfaceTable_config"
title="Configure Table">
<i class="mdi mdi-cog"></i> Configure Table
</button>
{% endif %}
<button class="btn btn-sm btn-outline-dark dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="mdi mdi-eye"></i>
</button>
<ul class="dropdown-menu">
<button type="button" class="dropdown-item toggle-enabled" data-state="show">Hide Enabled</button>
<button type="button" class="dropdown-item toggle-disabled" data-state="show">Hide Disabled</button>
</ul>
</div>
</div>
</div>
<form method="post">
{% csrf_token %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceInventoryItemTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceInventoryItemTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceModuleBayTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceModuleBayTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerOutletTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerOutletTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load static %} {% load static %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerPortTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerPortTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -4,9 +4,10 @@
{% load helpers %} {% load helpers %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceRearPortTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceRearPortTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -32,7 +32,11 @@
</tr> </tr>
<tr> <tr>
<td>Circuit</td> <td>Circuit</td>
<td>{{ termination.|linkify }} ({{ termination }})</td> <td>{{ termination.circuit|linkify }}</td>
</tr>
<tr>
<td>Termination</td>
<td>{{ termination }}</td>
</tr> </tr>
{% endif %} {% endif %}
</table> </table>

View File

@ -12,9 +12,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -10,9 +10,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -10,9 +10,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -10,9 +10,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPRangeTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="IPRangeTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -12,9 +12,10 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -2,9 +2,10 @@
{% load helpers %} {% load helpers %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="VLANDevicesTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="VLANDevicesTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">
{% include 'htmx/table.html' %} {% include 'htmx/table.html' %}

View File

@ -2,9 +2,10 @@
{% load helpers %} {% load helpers %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="VLANVirtualMachinesTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="VLANVirtualMachinesTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">
{% include 'htmx/table.html' %} {% include 'htmx/table.html' %}

View File

@ -3,9 +3,10 @@
{% load render_table from django_tables2 %} {% load render_table from django_tables2 %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceTable_config" %}
<form action="{% url 'virtualization:cluster_remove_devices' pk=object.pk %}" method="post"> <form action="{% url 'virtualization:cluster_remove_devices' pk=object.pk %}" method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">
{% include 'htmx/table.html' %} {% include 'htmx/table.html' %}

View File

@ -3,9 +3,10 @@
{% load render_table from django_tables2 %} {% load render_table from django_tables2 %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">
{% include 'htmx/table.html' %} {% include 'htmx/table.html' %}

View File

@ -3,9 +3,10 @@
{% load helpers %} {% load helpers %}
{% block content %} {% block content %}
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineVMInterfaceTable_config" %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineVMInterfaceTable_config" %}
<div class="card"> <div class="card">
<div class="card-body" id="object_list"> <div class="card-body" id="object_list">

View File

@ -15,11 +15,11 @@ djangorestframework==3.13.1
drf-yasg[validation]==1.20.0 drf-yasg[validation]==1.20.0
graphene-django==2.15.0 graphene-django==2.15.0
gunicorn==20.1.0 gunicorn==20.1.0
Jinja2==3.0.3 Jinja2==3.1.2
Markdown==3.3.6 Markdown==3.3.6
markdown-include==0.6.0 markdown-include==0.6.0
mkdocs-material==8.2.9 mkdocs-material==8.2.11
mkdocstrings==0.17.0 mkdocstrings[python-legacy]==0.18.1
netaddr==0.8.0 netaddr==0.8.0
Pillow==9.1.0 Pillow==9.1.0
psycopg2-binary==2.9.3 psycopg2-binary==2.9.3