diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index ad72e0735..3af825d30 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.1.8 + placeholder: v3.1.9 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 68256471c..f5bf198b8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.1.8 + placeholder: v3.1.9 validations: required: true - type: dropdown diff --git a/README.md b/README.md index 8429cd4b3..42bf8b619 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ NetBox logo +:loudspeaker: The **[2022 NetBox community survey](https://forms.gle/KR8YbR8GiJ9EYXM28)** is now open! We collect this feedback and demographic data from NetBox users around the world to help shape the project's long-term development goals. Please take a few minutes to share your responses! + ![Master branch build status](https://github.com/netbox-community/netbox/workflows/CI/badge.svg?branch=master) NetBox is an infrastructure resource modeling (IRM) tool designed to empower diff --git a/docs/index.md b/docs/index.md index 81c899387..eadb2088f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,7 @@ ![NetBox](netbox_logo.svg "NetBox logo"){style="height: 100px; margin-bottom: 3em"} +:loudspeaker: The **[2022 NetBox community survey](https://forms.gle/KR8YbR8GiJ9EYXM28)** is now open! We collect this feedback and demographic data from NetBox users around the world to help shape the project's long-term development goals. Please take a few minutes to share your responses! + # What is NetBox? NetBox is an infrastructure resource modeling (IRM) application designed to empower network automation. Initially conceived by the network engineering team at [DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically to address the needs of network and infrastructure engineers. NetBox is made available as open source under the Apache 2 license. It encompasses the following aspects of network management: diff --git a/docs/release-notes/version-3.1.md b/docs/release-notes/version-3.1.md index 08a9ab337..4f00434d7 100644 --- a/docs/release-notes/version-3.1.md +++ b/docs/release-notes/version-3.1.md @@ -1,11 +1,20 @@ # NetBox v3.1 -## v3.1.9 (FUTURE) +## v3.1.10 (FUTURE) + +--- + +## v3.1.9 (2022-03-07) ### Enhancements * [#8594](https://github.com/netbox-community/netbox/issues/8594) - Enable filtering by exact description match for all applicable models * [#8629](https://github.com/netbox-community/netbox/issues/8629) - Add description to tag table search function +* [#8664](https://github.com/netbox-community/netbox/issues/8664) - Show assigned ASNs/sites under list views +* [#8736](https://github.com/netbox-community/netbox/issues/8736) - Add PC and UPC fiber end faces for LC/SC/LSH port types +* [#8758](https://github.com/netbox-community/netbox/issues/8758) - Allow empty string substitution when renaming objects in bulk +* [#8762](https://github.com/netbox-community/netbox/issues/8762) - Link to rack elevations list from site view +* [#8766](https://github.com/netbox-community/netbox/issues/8766) - Add SCTP to service protocols list ### Bug Fixes @@ -14,7 +23,11 @@ * [#8674](https://github.com/netbox-community/netbox/issues/8674) - Fix rendering of tabbed content in documentation * [#8710](https://github.com/netbox-community/netbox/issues/8710) - Fix dynamic scope selection form fields when creating a VLAN group * [#8713](https://github.com/netbox-community/netbox/issues/8713) - Restore missing "add" button on services list view +* [#8715](https://github.com/netbox-community/netbox/issues/8715) - Avoid returning multiple objects when restricting querysets using multiple tags in permissions * [#8717](https://github.com/netbox-community/netbox/issues/8717) - Fix redirection after bulk edit/delete of prefixes from aggregate view +* [#8724](https://github.com/netbox-community/netbox/issues/8724) - Fix exception during device import with invalid device type +* [#8807](https://github.com/netbox-community/netbox/issues/8807) - Correct REST API URL for FHRP group assignments +* [#8808](https://github.com/netbox-community/netbox/issues/8808) - Fix members count under FHRP group list --- diff --git a/mkdocs.yml b/mkdocs.yml index 886b9159d..87ca4a8c9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,11 +8,13 @@ theme: icon: repo: fontawesome/brands/github palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default toggle: icon: material/lightbulb-outline name: Switch to Dark Mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate toggle: icon: material/lightbulb name: Switch to Light Mode diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index f8000d53d..c5f70c1b6 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -1003,13 +1003,19 @@ class PortTypeChoices(ChoiceSet): TYPE_MRJ21 = 'mrj21' TYPE_ST = 'st' TYPE_SC = 'sc' + TYPE_SC_PC = 'sc-pc' + TYPE_SC_UPC = 'sc-upc' TYPE_SC_APC = 'sc-apc' TYPE_FC = 'fc' TYPE_LC = 'lc' + TYPE_LC_PC = 'lc-pc' + TYPE_LC_UPC = 'lc-upc' TYPE_LC_APC = 'lc-apc' TYPE_MTRJ = 'mtrj' TYPE_MPO = 'mpo' TYPE_LSH = 'lsh' + TYPE_LSH_PC = 'lsh-pc' + TYPE_LSH_UPC = 'lsh-upc' TYPE_LSH_APC = 'lsh-apc' TYPE_SPLICE = 'splice' TYPE_CS = 'cs' @@ -1049,12 +1055,18 @@ class PortTypeChoices(ChoiceSet): ( (TYPE_FC, 'FC'), (TYPE_LC, 'LC'), + (TYPE_LC_PC, 'LC/PC'), + (TYPE_LC_UPC, 'LC/UPC'), (TYPE_LC_APC, 'LC/APC'), (TYPE_LSH, 'LSH'), + (TYPE_LSH_PC, 'LSH/PC'), + (TYPE_LSH_UPC, 'LSH/UPC'), (TYPE_LSH_APC, 'LSH/APC'), (TYPE_MPO, 'MPO'), (TYPE_MTRJ, 'MTRJ'), (TYPE_SC, 'SC'), + (TYPE_SC_PC, 'SC/PC'), + (TYPE_SC_UPC, 'SC/UPC'), (TYPE_SC_APC, 'SC/APC'), (TYPE_ST, 'ST'), (TYPE_CS, 'CS'), diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 4ee0dec0e..6fb8014b5 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -804,10 +804,11 @@ class Device(NetBoxModel, ConfigContextModel): }) # Prevent 0U devices from being assigned to a specific position - if self.position and self.device_type.u_height == 0: - raise ValidationError({ - 'position': f"A U0 device type ({self.device_type}) cannot be assigned to a rack position." - }) + if hasattr(self, 'device_type'): + if self.position and self.device_type.u_height == 0: + raise ValidationError({ + 'position': f"A U0 device type ({self.device_type}) cannot be assigned to a rack position." + }) if self.rack: diff --git a/netbox/dcim/tables/sites.py b/netbox/dcim/tables/sites.py index 2f6d36191..8e158a38f 100644 --- a/netbox/dcim/tables/sites.py +++ b/netbox/dcim/tables/sites.py @@ -82,6 +82,10 @@ class SiteTable(NetBoxTable): accessor=tables.A('asns__count'), viewname='ipam:asn_list', url_params={'site_id': 'pk'}, + verbose_name='ASN Count' + ) + asns = tables.ManyToManyColumn( + linkify_item=True, verbose_name='ASNs' ) tenant = TenantColumn() @@ -93,9 +97,9 @@ class SiteTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Site fields = ( - 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asn_count', 'time_zone', - 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags', - 'created', 'last_updated', 'actions', + 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asns', 'asn_count', + 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', + 'tags', 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'name', 'status', 'facility', 'region', 'group', 'tenant', 'description') diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index f71d3958a..8fb3bdea5 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -126,7 +126,7 @@ class FHRPGroupSerializer(PrimaryModelSerializer): class FHRPGroupAssignmentSerializer(PrimaryModelSerializer): - url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactassignment-detail') + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail') group = NestedFHRPGroupSerializer() interface_type = ContentTypeField( queryset=ContentType.objects.all() diff --git a/netbox/ipam/choices.py b/netbox/ipam/choices.py index 9d6e5e1e3..f76237ec9 100644 --- a/netbox/ipam/choices.py +++ b/netbox/ipam/choices.py @@ -155,8 +155,10 @@ class ServiceProtocolChoices(ChoiceSet): PROTOCOL_TCP = 'tcp' PROTOCOL_UDP = 'udp' + PROTOCOL_SCTP = 'sctp' CHOICES = ( (PROTOCOL_TCP, 'TCP'), (PROTOCOL_UDP, 'UDP'), + (PROTOCOL_SCTP, 'SCTP'), ) diff --git a/netbox/ipam/tables/fhrp.py b/netbox/ipam/tables/fhrp.py index 24b4f4e1a..55a07b1c7 100644 --- a/netbox/ipam/tables/fhrp.py +++ b/netbox/ipam/tables/fhrp.py @@ -26,8 +26,8 @@ class FHRPGroupTable(NetBoxTable): orderable=False, verbose_name='IP Addresses' ) - interface_count = tables.Column( - verbose_name='Interfaces' + member_count = tables.Column( + verbose_name='Members' ) tags = columns.TagColumn( url_name='ipam:fhrpgroup_list' @@ -36,10 +36,10 @@ class FHRPGroupTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = FHRPGroup fields = ( - 'pk', 'group_id', 'protocol', 'auth_type', 'auth_key', 'description', 'ip_addresses', 'interface_count', + 'pk', 'group_id', 'protocol', 'auth_type', 'auth_key', 'description', 'ip_addresses', 'member_count', 'tags', 'created', 'last_updated', ) - default_columns = ('pk', 'group_id', 'protocol', 'auth_type', 'description', 'ip_addresses', 'interface_count') + default_columns = ('pk', 'group_id', 'protocol', 'auth_type', 'description', 'ip_addresses', 'member_count') class FHRPGroupAssignmentTable(NetBoxTable): diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index a67feda6c..50f2db8e7 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -112,6 +112,10 @@ class ASNTable(NetBoxTable): site_count = columns.LinkedCountColumn( viewname='dcim:site_list', url_params={'asn_id': 'pk'}, + verbose_name='Site Count' + ) + sites = tables.ManyToManyColumn( + linkify_item=True, verbose_name='Sites' ) tenant = TenantColumn() @@ -122,8 +126,8 @@ class ASNTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ASN fields = ( - 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'tenant', 'description', 'created', 'last_updated', - 'actions', + 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'tenant', 'description', 'sites', 'tags', 'created', + 'last_updated', 'actions', ) default_columns = ('pk', 'asn', 'rir', 'site_count', 'sites', 'description', 'tenant') diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index 083d0347f..ef7015008 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -116,52 +116,54 @@ Blocks: {# Page footer #} diff --git a/netbox/templates/dcim/site.html b/netbox/templates/dcim/site.html index 5ab3510c7..236c8e1c7 100644 --- a/netbox/templates/dcim/site.html +++ b/netbox/templates/dcim/site.html @@ -131,42 +131,98 @@
-
Stats
+
Related Objects
-
-
-

{{ stats.location_count }}

-

Locations

-
- -
-

{{ stats.device_count }}

-

Devices

-
-
-

{{ stats.prefix_count }}

-

Prefixes

-
- -
-

{{ stats.circuit_count }}

-

Circuits

-
-
-

{{ stats.vm_count }}

-

Virtual Machines

-
- -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Locations + {% if stats.location_count %} + {{ stats.location_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
Racks + {% if stats.rack_count %} + + {% else %} + {{ ''|placeholder }} + {% endif %} +
Devices + {% if stats.device_count %} + {{ stats.device_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
Virtual Machines + {% if stats.vm_count %} + {{ stats.vm_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
Prefixes + {% if stats.prefix_count %} + {{ stats.prefix_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
VLANs + {% if stats.vlan_count %} + {{ stats.vlan_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
ASNs + {% if stats.asn_count %} + {{ stats.asn_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
Circuits + {% if stats.circuit_count %} + {{ stats.circuit_count }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
{% include 'inc/panels/contacts.html' %} diff --git a/netbox/templates/search.html b/netbox/templates/search.html index 187b76c59..a47b48b09 100644 --- a/netbox/templates/search.html +++ b/netbox/templates/search.html @@ -5,7 +5,18 @@ {% block title %}Search{% endblock %} -{% block content %} +{% block tabs %} + +{% endblock tabs %} + +{% block content-wrapper %} +
{% if request.GET.q %} {% if results %}
@@ -73,4 +84,5 @@
{% endif %} -{% endblock content %} +
+{% endblock content-wrapper %} diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py index 05138df70..3b5cd8308 100644 --- a/netbox/utilities/forms/forms.py +++ b/netbox/utilities/forms/forms.py @@ -94,7 +94,9 @@ class BulkRenameForm(BootstrapMixin, forms.Form): An extendable form to be used for renaming objects in bulk. """ find = forms.CharField() - replace = forms.CharField() + replace = forms.CharField( + required=False + ) use_regex = forms.BooleanField( required=False, initial=True, diff --git a/netbox/utilities/querysets.py b/netbox/utilities/querysets.py index 738b72dc3..97d2e8779 100644 --- a/netbox/utilities/querysets.py +++ b/netbox/utilities/querysets.py @@ -39,6 +39,12 @@ class RestrictedQuerySet(QuerySet): # Any permission with null constraints grants access to _all_ instances attrs = Q() break + else: + # for else, when no break + # avoid duplicates when JOIN on many-to-many fields without using DISTINCT. + # DISTINCT acts globally on the entire request, which may not be desirable. + allowed_objects = self.model.objects.filter(attrs) + attrs = Q(pk__in=allowed_objects) qs = self.filter(attrs) return qs diff --git a/requirements.txt b/requirements.txt index 0c4ed3db1..8775a4a8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ gunicorn==20.1.0 Jinja2==3.0.3 Markdown==3.3.6 markdown-include==0.6.0 -mkdocs-material==8.1.11 +mkdocs-material==8.2.5 mkdocstrings==0.17.0 netaddr==0.8.0 Pillow==9.0.1