diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index 614e90eac..4eb090554 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -141,6 +141,22 @@ When determining the primary IP address for a device, IPv6 is preferred over IPv --- +## QUEUE_MAPPINGS + +Allows changing which queues are used internally for background tasks. + +```python +QUEUE_MAPPINGS = { + 'webhook': 'low', + 'report': 'high', + 'script': 'high', +} +``` + +If no queue is defined the queue named `default` will be used. + +--- + ## RELEASE_CHECK_URL Default: None (disabled) diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 205822efe..68a582e7f 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -225,6 +225,9 @@ Once NetBox has been configured, we're ready to proceed with the actual installa * Builds the documentation locally (for offline use) * Aggregate static resource files on disk +!!! warning + If you still have a Python virtual environment active from a previous installation step, disable it now by running the `deactivate` command. This will avoid errors on systems where `sudo` has been configured to preserve the user's current environment. + ```no-highlight sudo /opt/netbox/upgrade.sh ``` diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 2d62fb5bd..4dd717f9b 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -2,6 +2,18 @@ ## v3.3.10 (FUTURE) +### Enhancements + +* [#10748](https://github.com/netbox-community/netbox/issues/10748) - Add provider selection field for provider networks to circuit termination edit view +* [#11119](https://github.com/netbox-community/netbox/issues/11119) - Enable filtering L2VPNs by slug + +### Bug Fixes + +* [#11041](https://github.com/netbox-community/netbox/issues/11041) - Correct power utilization percentage precision +* [#11087](https://github.com/netbox-community/netbox/issues/11087) - Fix background color of bottom banner content +* [#11101](https://github.com/netbox-community/netbox/issues/11101) - Correct circuits count under site view +* [#11128](https://github.com/netbox-community/netbox/issues/11128) - Disable ordering changelog table by object to avoid exception + --- ## v3.3.9 (2022-11-30) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index e52df0ef1..f1d4f2cdf 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -6,6 +6,7 @@ * [#815](https://github.com/netbox-community/netbox/issues/815) - Enable specifying terminations when bulk importing circuits * [#11090](https://github.com/netbox-community/netbox/issues/11090) - Add regular expression support to global search engine +* [#11022](https://github.com/netbox-community/netbox/issues/11022) - Introduce `QUEUE_MAPPINGS` configuration parameter to allow customization of background task prioritization ### Bug Fixes diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index 890462aaa..cd73780fa 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -145,16 +145,28 @@ class CircuitTerminationForm(NetBoxModelForm): }, required=False ) + provider_network_provider = DynamicModelChoiceField( + queryset=Provider.objects.all(), + required=False, + label='Provider', + initial_params={ + 'networks': 'provider_network' + } + ) provider_network = DynamicModelChoiceField( queryset=ProviderNetwork.objects.all(), + query_params={ + 'provider_id': '$provider_network_provider', + }, required=False ) class Meta: model = CircuitTermination fields = [ - 'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected', - 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags', + 'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network_provider', + 'provider_network', 'mark_connected', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', + 'description', 'tags', ] help_texts = { 'port_speed': _("Physical circuit speed"), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 9edf5b152..f52de7ee4 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -391,7 +391,7 @@ class SiteView(generic.ObjectView): scope_id=instance.pk ).count(), 'vlan_count': VLAN.objects.restrict(request.user, 'view').filter(site=instance).count(), - 'circuit_count': Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).count(), + 'circuit_count': Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct().count(), 'vm_count': VirtualMachine.objects.restrict(request.user, 'view').filter(cluster__site=instance).count(), } locations = Location.objects.add_related_count( diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 59954c4e8..4054c4ae4 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -21,6 +21,8 @@ from extras.choices import * from extras.constants import * from extras.conditions import ConditionSet from extras.utils import FeatureQuery, image_upload +from netbox.config import get_config +from netbox.constants import RQ_QUEUE_DEFAULT from netbox.models import ChangeLoggedModel from netbox.models.features import ( CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, TagsMixin, WebhooksMixin, @@ -679,7 +681,8 @@ class JobResult(models.Model): schedule_at: Schedule the job to be executed at the passed date and time interval: Recurrence interval (in minutes) """ - queue = django_rq.get_queue('default') + rq_queue_name = get_config().QUEUE_MAPPINGS.get(obj_type.name, RQ_QUEUE_DEFAULT) + queue = django_rq.get_queue(rq_queue_name) status = JobResultStatusChoices.STATUS_SCHEDULED if schedule_at else JobResultStatusChoices.STATUS_PENDING job_result: JobResult = JobResult.objects.create( name=name, diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index 498a61b69..eb4d6899b 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -216,7 +216,8 @@ class ObjectChangeTable(NetBoxTable): object_repr = tables.TemplateColumn( accessor=tables.A('changed_object'), template_code=OBJECTCHANGE_OBJECT, - verbose_name='Object' + verbose_name='Object', + orderable=False ) request_id = tables.TemplateColumn( template_code=OBJECTCHANGE_REQUEST_ID, diff --git a/netbox/extras/webhooks.py b/netbox/extras/webhooks.py index a93be7934..23702949a 100644 --- a/netbox/extras/webhooks.py +++ b/netbox/extras/webhooks.py @@ -5,6 +5,8 @@ from django.contrib.contenttypes.models import ContentType from django.utils import timezone from django_rq import get_queue +from netbox.config import get_config +from netbox.constants import RQ_QUEUE_DEFAULT from netbox.registry import registry from utilities.api import get_serializer_for_model from utilities.utils import serialize_object @@ -78,7 +80,8 @@ def flush_webhooks(queue): """ Flush a list of object representation to RQ for webhook processing. """ - rq_queue = get_queue('default') + rq_queue_name = get_config().QUEUE_MAPPINGS.get('webhook', RQ_QUEUE_DEFAULT) + rq_queue = get_queue(rq_queue_name) webhooks_cache = { 'type_create': {}, 'type_update': {}, diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index b5478b7a0..d5d589dc6 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -962,7 +962,7 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class Meta: model = L2VPN - fields = ['id', 'identifier', 'name', 'type', 'description'] + fields = ['id', 'identifier', 'name', 'slug', 'type', 'description'] def search(self, queryset, name, value): if not value.strip(): diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index abb5a3cc3..a2b06080a 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -1505,6 +1505,10 @@ class L2VPNTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'name': ['L2VPN 1', 'L2VPN 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_slug(self): + params = {'slug': ['l2vpn-1', 'l2vpn-2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_identifier(self): params = {'identifier': ['65001', '65002']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index c8054b3b0..0889f6a5c 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -1,2 +1,7 @@ # Prefix for nested serializers NESTED_SERIALIZER_PREFIX = 'Nested' + +# RQ queue names +RQ_QUEUE_DEFAULT = 'default' +RQ_QUEUE_HIGH = 'high' +RQ_QUEUE_LOW = 'low' diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 4dbf48c36..a43e16ab3 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -17,6 +17,7 @@ from extras.plugins import PluginConfig from sentry_sdk.integrations.django import DjangoIntegration from netbox.config import PARAMS +from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # @@ -101,6 +102,7 @@ MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media' METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False) PLUGINS = getattr(configuration, 'PLUGINS', []) PLUGINS_CONFIG = getattr(configuration, 'PLUGINS_CONFIG', {}) +QUEUE_MAPPINGS = getattr(configuration, 'QUEUE_MAPPINGS', {}) RELEASE_CHECK_URL = getattr(configuration, 'RELEASE_CHECK_URL', None) REMOTE_AUTH_AUTO_CREATE_USER = getattr(configuration, 'REMOTE_AUTH_AUTO_CREATE_USER', False) REMOTE_AUTH_BACKEND = getattr(configuration, 'REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend') @@ -639,11 +641,16 @@ else: } RQ_QUEUES = { - 'high': RQ_PARAMS, - 'default': RQ_PARAMS, - 'low': RQ_PARAMS, + RQ_QUEUE_HIGH: RQ_PARAMS, + RQ_QUEUE_DEFAULT: RQ_PARAMS, + RQ_QUEUE_LOW: RQ_PARAMS, } +# Add any queues defined in QUEUE_MAPPINGS +RQ_QUEUES.update({ + queue: RQ_PARAMS for queue in set(QUEUE_MAPPINGS.values()) if queue not in RQ_QUEUES +}) + # # Plugins diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index 2835e1ef2..e060110fb 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -102,14 +102,14 @@ Blocks: {% block content %}{% endblock %} {% endblock %} + {# Bottom banner #} + {% if config.BANNER_BOTTOM %} +