Просмотр исходного кода

Merge branch 'develop' into feature

jeremystretch 3 лет назад
Родитель
Сommit
e2b32757d8
42 измененных файлов с 219 добавлено и 43 удалено
  1. 1 1
      CHANGELOG.md
  2. 2 2
      CONTRIBUTING.md
  3. 2 2
      README.md
  4. 1 1
      contrib/netbox-rq.service
  5. 1 1
      contrib/netbox.service
  6. 11 2
      docs/administration/authentication/microsoft-azure-ad.md
  7. 70 0
      docs/administration/authentication/okta.md
  8. 3 3
      docs/customization/custom-validation.md
  9. 1 1
      docs/installation/4-gunicorn.md
  10. 1 1
      docs/installation/migrating-to-systemd.md
  11. BIN
      docs/media/authentication/netbox_okta_login.png
  12. BIN
      docs/media/authentication/okta_create_app_registration.png
  13. BIN
      docs/media/authentication/okta_integration_parameters.png
  14. BIN
      docs/media/authentication/okta_login_portal.png
  15. BIN
      docs/media/authentication/okta_web_app_integration.png
  16. 1 1
      docs/release-notes/version-2.1.md
  17. 1 1
      docs/release-notes/version-2.2.md
  18. 1 1
      docs/release-notes/version-2.5.md
  19. 1 1
      docs/release-notes/version-2.6.md
  20. 2 2
      docs/release-notes/version-2.7.md
  21. 2 2
      docs/release-notes/version-2.8.md
  22. 15 0
      docs/release-notes/version-3.2.md
  23. 2 1
      mkdocs.yml
  24. 2 0
      netbox/dcim/choices.py
  25. 7 0
      netbox/dcim/filtersets.py
  26. 8 2
      netbox/dcim/forms/bulk_create.py
  27. 22 1
      netbox/dcim/forms/filtersets.py
  28. 15 0
      netbox/dcim/forms/models.py
  29. 9 0
      netbox/dcim/tests/test_filtersets.py
  30. 10 6
      netbox/extras/scripts.py
  31. 2 2
      netbox/ipam/views.py
  32. 1 0
      netbox/netbox/authentication.py
  33. 2 0
      netbox/netbox/forms/base.py
  34. 0 0
      netbox/project-static/dist/netbox.js
  35. 0 0
      netbox/project-static/dist/netbox.js.map
  36. 2 1
      netbox/project-static/src/select/api/apiSelect.ts
  37. 4 1
      netbox/templates/extras/customfield.html
  38. 1 1
      netbox/templates/home.html
  39. 1 1
      netbox/templates/media_failure.html
  40. 3 3
      netbox/users/models.py
  41. 6 2
      netbox/virtualization/tables/clusters.py
  42. 6 0
      netbox/wireless/forms/models.py

+ 1 - 1
CHANGELOG.md

@@ -1 +1 @@
-The changelog has been moved to the [project release notes](https://netbox.readthedocs.io/en/stable/release-notes/).
+The changelog has been moved to the [project release notes](https://docs.netbox.dev/en/stable/release-notes/).

+ 2 - 2
CONTRIBUTING.md

@@ -99,7 +99,7 @@ appropriate labels will be applied for categorization.
 ## Submitting Pull Requests
 
 * If you're interested in contributing to NetBox, be sure to check out our
-[getting started](https://netbox.readthedocs.io/en/stable/development/getting-started/)
+[getting started](https://docs.netbox.dev/en/stable/development/getting-started/)
 documentation for tips on setting up your development environment.
 
 * Be sure to open an issue **before** starting work on a pull request, and
@@ -171,7 +171,7 @@ an effort to circumvent the bot: Doing so will not remove the stale label.
   the understanding that all contributions are submitted under the Apache 2.0
   license and that your employer may not make claim to any contributions.
   Contributions include code work, issue management, and community support. All
-  development must be in accordance with our [development guidance](https://netbox.readthedocs.io/en/stable/development/).
+  development must be in accordance with our [development guidance](https://docs.netbox.dev/en/stable/development/).
 
 * Maintainers are expected to attend (where feasible) our biweekly ~30-minute
   sync to review agenda items. This meeting provides opportunity to present and

+ 2 - 2
README.md

@@ -49,7 +49,7 @@ NetBox runs as a web application atop the [Django](https://www.djangoproject.com
 Python framework with a [PostgreSQL](https://www.postgresql.org/) database. For a
 complete list of requirements, see `requirements.txt`. The code is available [on GitHub](https://github.com/netbox-community/netbox).
 
-The complete documentation for NetBox can be found at [Read the Docs](https://netbox.readthedocs.io/en/stable/). A public demo instance is available at https://demo.netbox.dev.
+The complete documentation for NetBox can be found at [docs.netbox.dev](https://docs.netbox.dev/). A public demo instance is available at https://demo.netbox.dev.
 
 <div align="center">
   <h4>Thank you to our sponsors!</h4>
@@ -71,7 +71,7 @@ The complete documentation for NetBox can be found at [Read the Docs](https://ne
 
 ### Installation
 
-Please see [the documentation](https://netbox.readthedocs.io/en/stable/) for
+Please see [the documentation](https://docs.netbox.dev/) for
 instructions on installing NetBox. To upgrade NetBox, please download the
 [latest release](https://github.com/netbox-community/netbox/releases) and
 run `upgrade.sh`.

+ 1 - 1
contrib/netbox-rq.service

@@ -1,6 +1,6 @@
 [Unit]
 Description=NetBox Request Queue Worker
-Documentation=https://netbox.readthedocs.io/en/stable/
+Documentation=https://docs.netbox.dev/
 After=network-online.target
 Wants=network-online.target
 

+ 1 - 1
contrib/netbox.service

@@ -1,6 +1,6 @@
 [Unit]
 Description=NetBox WSGI Service
-Documentation=https://netbox.readthedocs.io/en/stable/
+Documentation=https://docs.netbox.dev/
 After=network-online.target
 Wants=network-online.target
 

+ 11 - 2
docs/administration/authentication/microsoft-azure-ad.md

@@ -75,5 +75,14 @@ If successful, you will be redirected back to the NetBox UI, and will be logged
 
 This user account has been replicated locally to NetBox, and can now be assigned groups and permissions within the NetBox admin UI.
 
-!!! note "Troubleshooting"
-    If you are redirected to the NetBox UI after authenticating, but are _not_ logged in, double-check the configured backend and app registration. The instructions in this guide pertain only to the `azuread.AzureADOAuth2` backend using a single-tenant app registration.
+## Troubleshooting
+
+### Redirect URI does not Match
+
+Azure requires that the authenticating client request a redirect URI that matches what you've configured for the app in step two. This URI **must** begin with `https://` (unless using `localhost` for the domain).
+
+If Azure complains that the requested URI starts with `http://` (not HTTPS), it's likely that your HTTP server is misconfigured or sitting behind a load balancer, so NetBox is not aware that HTTPS is being use. To force the use of an HTTPS redirect URI, set `SOCIAL_AUTH_REDIRECT_IS_HTTPS = True` in `configuration.py` per the [python-social-auth docs](https://python-social-auth.readthedocs.io/en/latest/configuration/settings.html#processing-redirects-and-urlopen).
+
+### Not Logged in After Authenticating
+
+If you are redirected to the NetBox UI after authenticating successfully, but are _not_ logged in, double-check the configured backend and app registration. The instructions in this guide pertain only to the `azuread.AzureADOAuth2` backend using a single-tenant app registration.

+ 70 - 0
docs/administration/authentication/okta.md

@@ -0,0 +1,70 @@
+# Okta
+
+This guide explains how to configure single sign-on (SSO) support for NetBox using [Okta](https://www.okta.com/) as an authentication backend.
+
+## Okta Configuration
+
+!!! tip "Okta developer account"
+    Okta offers free developer accounts at <https://developer.okta.com/>.
+
+### 1. Create a test user (optional)
+
+Create a new user in the Okta admin portal to be used for testing. You can skip this step if you already have a suitable account created.
+
+### 2. Create an app registration
+
+Within the Okta administration dashboard, navigate to  **Applications > Applications**, and click the "Create App Integration" button. Select "OIDC" as the sign-in method, and "Web application" for the application type.
+
+![Create an app registration](../../media/authentication/okta_create_app_registration.png)
+
+On the next page, give the app integration a name (e.g. "NetBox") and specify the sign-in and sign-out URIs. These URIs should follow the formats below:
+
+* Sign-in URI: `https://{netbox}/oauth/complete/okta-openidconnect/`
+* Sign-out URI: `https://{netbox}/oauth/disconnect/okta-openidconnect/`
+
+![Web app integration](../../media/authentication/okta_web_app_integration.png)
+
+Under "Assignments," select the controlled access setting most appropriate for your organization. Click "Save" to complete the creation.
+
+Once finished, note the following parameters. These will be used to configured NetBox.
+
+* Client ID
+* Client secret
+* Okta domain
+
+![Okta integration parameters](../../media/authentication/okta_integration_parameters.png)
+
+## NetBox Configuration
+
+### 1. Enter configuration parameters
+
+Enter the following configuration parameters in `configuration.py`, substituting your own values:
+
+```python
+REMOTE_AUTH_BACKEND = 'social_core.backends.okta_openidconnect.OktaOpenIdConnect'
+SOCIAL_AUTH_OKTA_OPENIDCONNECT_KEY = '{Client ID}'
+SOCIAL_AUTH_OKTA_OPENIDCONNECT_SECRET = '{Client secret}'
+SOCIAL_AUTH_OKTA_OPENIDCONNECT_API_URL = 'https://{Okta domain}/oauth2/'
+```
+
+### 2. Restart NetBox
+
+Restart the NetBox services so that the new configuration takes effect. This is typically done with the command below:
+
+```no-highlight
+sudo systemctl restart netbox
+```
+
+## Testing
+
+Log out of NetBox if already authenticated, and click the "Log In" button at top right. You should see the normal login form as well as an option to authenticate using Okta. Click that link.
+
+![NetBox Okta login form](../../media/authentication/netbox_okta_login.png)
+
+You should be redirected to Okta's authentication portal. Enter the username/email and password of your test account to continue. You may also be prompted to grant this application access to your account.
+
+![Okta login portal](../../media/authentication/okta_login_portal.png)
+
+If successful, you will be redirected back to the NetBox UI, and will be logged in as the Okta user. You can verify this by navigating to your profile (using the button at top right).
+
+This user account has been replicated locally to NetBox, and can now be assigned groups and permissions within the NetBox admin UI.

+ 3 - 3
docs/customization/custom-validation.md

@@ -105,11 +105,11 @@ from my_validators import Validator1, Validator2, Validator3
 
 CUSTOM_VALIDATORS = {
     'dcim.site': (
-        Validator1,
-        Validator2,
+        Validator1(),
+        Validator2(),
     ),
     'dcim.device': (
-        Validator3,
+        Validator3(),
     )
 }
 ```

+ 1 - 1
docs/installation/4-gunicorn.md

@@ -40,7 +40,7 @@ You should see output similar to the following:
 ● netbox.service - NetBox WSGI Service
      Loaded: loaded (/etc/systemd/system/netbox.service; enabled; vendor preset: enabled)
      Active: active (running) since Mon 2021-08-30 04:02:36 UTC; 14h ago
-       Docs: https://netbox.readthedocs.io/en/stable/
+       Docs: https://docs.netbox.dev/
    Main PID: 1140492 (gunicorn)
       Tasks: 19 (limit: 4683)
      Memory: 666.2M

+ 1 - 1
docs/installation/migrating-to-systemd.md

@@ -39,7 +39,7 @@ You can use the command `systemctl status netbox` to verify that the WSGI servic
 ● netbox.service - NetBox WSGI Service
    Loaded: loaded (/etc/systemd/system/netbox.service; enabled; vendor preset: enabled)
    Active: active (running) since Sat 2020-10-24 19:23:40 UTC; 25s ago
-     Docs: https://netbox.readthedocs.io/en/stable/
+     Docs: https://docs.netbox.dev/
  Main PID: 11993 (gunicorn)
     Tasks: 6 (limit: 2362)
    CGroup: /system.slice/netbox.service

BIN
docs/media/authentication/netbox_okta_login.png


BIN
docs/media/authentication/okta_create_app_registration.png


BIN
docs/media/authentication/okta_integration_parameters.png


BIN
docs/media/authentication/okta_login_portal.png


BIN
docs/media/authentication/okta_web_app_integration.png


+ 1 - 1
docs/release-notes/version-2.1.md

@@ -121,7 +121,7 @@ A new API endpoint has been added at `/api/ipam/prefixes/<pk>/available-ips/`. A
 
 #### NAPALM Integration ([#1348](https://github.com/netbox-community/netbox/issues/1348))
 
-The [NAPALM automation](https://github.com/napalm-automation/napalm) library provides an abstracted interface for pulling live data (e.g. uptime, software version, running config, LLDP neighbors, etc.) from network devices. The NetBox API has been extended to support executing read-only NAPALM methods on devices defined in NetBox. To enable this functionality, ensure that NAPALM has been installed (`pip install napalm`) and the `NETBOX_USERNAME` and `NETBOX_PASSWORD` [configuration parameters](https://netbox.readthedocs.io/en/stable/configuration/optional-settings/#netbox_username) have been set in configuration.py.
+The [NAPALM automation](https://github.com/napalm-automation/napalm) library provides an abstracted interface for pulling live data (e.g. uptime, software version, running config, LLDP neighbors, etc.) from network devices. The NetBox API has been extended to support executing read-only NAPALM methods on devices defined in NetBox. To enable this functionality, ensure that NAPALM has been installed (`pip install napalm`) and the `NETBOX_USERNAME` and `NETBOX_PASSWORD` [configuration parameters](https://docs.netbox.dev/en/stable/configuration/optional-settings/#netbox_username) have been set in configuration.py.
 
 ### Enhancements
 

+ 1 - 1
docs/release-notes/version-2.2.md

@@ -196,7 +196,7 @@ Our second-most popular feature request has arrived! NetBox now supports the cre
 
 #### Custom Validation Reports ([#1511](https://github.com/netbox-community/netbox/issues/1511))
 
-Users can now create custom reports which are run to validate data in NetBox. Reports work very similar to Python unit tests: Each report inherits from NetBox's Report class and contains one or more test method. Reports can be run and retrieved via the web UI, API, or CLI. See [the docs](https://netbox.readthedocs.io/en/stable/miscellaneous/reports/) for more info.
+Users can now create custom reports which are run to validate data in NetBox. Reports work very similar to Python unit tests: Each report inherits from NetBox's Report class and contains one or more test method. Reports can be run and retrieved via the web UI, API, or CLI. See [the docs](https://docs.netbox.dev/en/stable/miscellaneous/reports/) for more info.
 
 ### Enhancements
 

+ 1 - 1
docs/release-notes/version-2.5.md

@@ -295,7 +295,7 @@ This release upgrades the Django framework to version 2.2.
 
 #### Python 3 Required
 
-As promised, Python 2 support has been completed removed. Python 3.5 or higher is now required to run NetBox. Please see [our Python 3 migration guide](https://netbox.readthedocs.io/en/stable/installation/migrating-to-python3/) for assistance with upgrading.
+As promised, Python 2 support has been completed removed. Python 3.5 or higher is now required to run NetBox. Please see [our Python 3 migration guide](https://docs.netbox.dev/en/stable/installation/migrating-to-python3/) for assistance with upgrading.
 
 #### Removed Deprecated User Activity Log
 

+ 1 - 1
docs/release-notes/version-2.6.md

@@ -218,7 +218,7 @@
 
 #### Custom Scripts ([#3415](https://github.com/netbox-community/netbox/issues/3415))
 
-Custom scripts allow for the execution of arbitrary code via the NetBox UI. They can be used to automatically create, manipulate, or clean up objects or perform other tasks within NetBox. Scripts are defined as Python files which contain one or more subclasses of `extras.scripts.Script`. Variable fields can be defined within scripts, which render as form fields within the web UI to prompt the user for input data. Scripts are executed and information is logged via the web UI. Please see [the docs](https://netbox.readthedocs.io/en/stable/customization/custom-scripts/) for more detail.
+Custom scripts allow for the execution of arbitrary code via the NetBox UI. They can be used to automatically create, manipulate, or clean up objects or perform other tasks within NetBox. Scripts are defined as Python files which contain one or more subclasses of `extras.scripts.Script`. Variable fields can be defined within scripts, which render as form fields within the web UI to prompt the user for input data. Scripts are executed and information is logged via the web UI. Please see [the docs](https://docs.netbox.dev/en/stable/customization/custom-scripts/) for more detail.
 
 Note: There are currently no API endpoints for this feature. These are planned for the upcoming v2.7 release.
 

+ 2 - 2
docs/release-notes/version-2.7.md

@@ -67,7 +67,7 @@
 
 ## v2.7.9 (2020-03-06)
 
-**Note:** This release will deploy a Python virtual environment on upgrade in the `venv/` directory. This will require modifying the paths to your Python and gunicorn executables in the systemd service files. For more detail, please see the [upgrade instructions](https://netbox.readthedocs.io/en/stable/installation/upgrading/).
+**Note:** This release will deploy a Python virtual environment on upgrade in the `venv/` directory. This will require modifying the paths to your Python and gunicorn executables in the systemd service files. For more detail, please see the [upgrade instructions](https://docs.netbox.dev/en/stable/installation/upgrading/).
 
 ### Enhancements
 
@@ -418,7 +418,7 @@ to another source before upgrading NetBox to v2.7, as any existing topology maps
 
 #### Supervisor Replaced with systemd ([#2902](https://github.com/netbox-community/netbox/issues/2902))
 
-The NetBox [installation documentation](https://netbox.readthedocs.io/en/stable/installation/) has been updated to
+The NetBox [installation documentation](https://docs.netbox.dev/en/stable/installation/) has been updated to
 provide instructions for managing the WSGI and RQ services using systemd instead of supervisor. This removes the need to
 install supervisor and simplifies administration of the processes.
 

+ 2 - 2
docs/release-notes/version-2.8.md

@@ -235,14 +235,14 @@ This release introduces support for custom plugins, which can be used to extend
 * Introduce new API endpoints
 * Add custom request/response middleware
 
-For NetBox plugins to be recognized, they must be installed and added by name to the `PLUGINS` configuration parameter. (Plugin support is disabled by default.) Plugins can be configured under the `PLUGINS_CONFIG` parameter. More information can be found the in the [plugins documentation](https://netbox.readthedocs.io/en/stable/plugins/).
+For NetBox plugins to be recognized, they must be installed and added by name to the `PLUGINS` configuration parameter. (Plugin support is disabled by default.) Plugins can be configured under the `PLUGINS_CONFIG` parameter. More information can be found the in the [plugins documentation](https://docs.netbox.dev/en/stable/plugins/).
 
 ### Enhancements
 
 * [#1754](https://github.com/netbox-community/netbox/issues/1754) - Added support for nested rack groups
 * [#3939](https://github.com/netbox-community/netbox/issues/3939) - Added support for nested tenant groups
 * [#4078](https://github.com/netbox-community/netbox/issues/4078) - Standardized description fields across all models
-* [#4195](https://github.com/netbox-community/netbox/issues/4195) - Enabled application logging (see [logging configuration](https://netbox.readthedocs.io/en/stable/configuration/optional-settings/#logging))
+* [#4195](https://github.com/netbox-community/netbox/issues/4195) - Enabled application logging (see [logging configuration](https://docs.netbox.dev/en/stable/configuration/optional-settings/#logging))
 
 ### Bug Fixes
 

+ 15 - 0
docs/release-notes/version-3.2.md

@@ -2,9 +2,24 @@
 
 ## v3.2.2 (FUTURE)
 
+### Enhancements
+
+* [#9060](https://github.com/netbox-community/netbox/issues/9060) - Add device type filters for device bays, module bays, and inventory items
+* [#9152](https://github.com/netbox-community/netbox/issues/9152) - Annotate related object type under custom field view
+* [#9192](https://github.com/netbox-community/netbox/issues/9192) - Add Ubiquiti SmartPower connector type
+* [#9214](https://github.com/netbox-community/netbox/issues/9214) - Linkify cluster counts in cluster type & group tables
+
 ### Bug Fixes
 
+* [#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)
+* [#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
+* [#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
+* [#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
+* [#9206](https://github.com/netbox-community/netbox/issues/9206) - Show header for comments field under module & module type creation views
 
 ---
 

+ 2 - 1
mkdocs.yml

@@ -1,6 +1,6 @@
 site_name: NetBox Documentation
 site_dir: netbox/project-static/docs
-site_url: https://netbox.readthedocs.io/
+site_url: https://docs.netbox.dev/
 repo_name: netbox-community/netbox
 repo_url: https://github.com/netbox-community/netbox
 theme:
@@ -121,6 +121,7 @@ nav:
         - Authentication:
             - Overview: 'administration/authentication/overview.md'
             - Microsoft Azure AD: 'administration/authentication/microsoft-azure-ad.md'
+            - Okta: 'administration/authentication/okta.md'
         - Permissions: 'administration/permissions.md'
         - Housekeeping: 'administration/housekeeping.md'
         - Replicating NetBox: 'administration/replicating-netbox.md'

+ 2 - 0
netbox/dcim/choices.py

@@ -349,6 +349,7 @@ class PowerPortTypeChoices(ChoiceSet):
     TYPE_NEUTRIK_POWERCON_32A = 'neutrik-powercon-32'
     TYPE_NEUTRIK_POWERCON_TRUE1 = 'neutrik-powercon-true1'
     TYPE_NEUTRIK_POWERCON_TRUE1_TOP = 'neutrik-powercon-true1-top'
+    TYPE_UBIQUITI_SMARTPOWER = 'ubiquiti-smartpower'
     # Other
     TYPE_HARDWIRED = 'hardwired'
 
@@ -464,6 +465,7 @@ class PowerPortTypeChoices(ChoiceSet):
             (TYPE_NEUTRIK_POWERCON_32A, 'Neutrik powerCON (32A)'),
             (TYPE_NEUTRIK_POWERCON_TRUE1, 'Neutrik powerCON TRUE1'),
             (TYPE_NEUTRIK_POWERCON_TRUE1_TOP, 'Neutrik powerCON TRUE1 TOP'),
+            (TYPE_UBIQUITI_SMARTPOWER, 'Ubiquiti SmartPower'),
         )),
         ('Other', (
             (TYPE_HARDWIRED, 'Hardwired'),

+ 7 - 0
netbox/dcim/filtersets.py

@@ -435,6 +435,10 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
         method='_device_bays',
         label='Has device bays',
     )
+    inventory_items = django_filters.BooleanFilter(
+        method='_inventory_items',
+        label='Has inventory items',
+    )
 
     class Meta:
         model = DeviceType
@@ -479,6 +483,9 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
     def _device_bays(self, queryset, name, value):
         return queryset.exclude(devicebaytemplates__isnull=value)
 
+    def _inventory_items(self, queryset, name, value):
+        return queryset.exclude(inventoryitemtemplates__isnull=value)
+
 
 class ModuleTypeFilterSet(NetBoxModelFilterSet):
     manufacturer_id = django_filters.ModelMultipleChoiceFilter(

+ 8 - 2
netbox/dcim/forms/bulk_create.py

@@ -3,7 +3,7 @@ from django import forms
 from dcim.models import *
 from extras.forms import CustomFieldsMixin
 from extras.models import Tag
-from utilities.forms import DynamicModelMultipleChoiceField, form_from_model
+from utilities.forms import DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model
 from .object_create import ComponentCreateForm
 
 __all__ = (
@@ -98,7 +98,13 @@ class RearPortBulkCreateForm(
 
 class ModuleBayBulkCreateForm(DeviceBulkAddComponentForm):
     model = ModuleBay
-    field_order = ('name_pattern', 'label_pattern', 'description', 'tags')
+    field_order = ('name_pattern', 'label_pattern', 'position_pattern', 'description', 'tags')
+
+    position_pattern = ExpandableNameField(
+        label='Position',
+        required=False,
+        help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
+    )
 
 
 class DeviceBayBulkCreateForm(DeviceBulkAddComponentForm):

+ 22 - 1
netbox/dcim/forms/filtersets.py

@@ -331,7 +331,7 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
         ('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
         ('Components', (
             'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
-            'pass_through_ports',
+            'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items',
         )),
     )
     manufacturer_id = DynamicModelMultipleChoiceField(
@@ -392,6 +392,27 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
     )
+    device_bays = forms.NullBooleanField(
+        required=False,
+        label='Has device bays',
+        widget=StaticSelect(
+            choices=BOOLEAN_WITH_BLANK_CHOICES
+        )
+    )
+    module_bays = forms.NullBooleanField(
+        required=False,
+        label='Has module bays',
+        widget=StaticSelect(
+            choices=BOOLEAN_WITH_BLANK_CHOICES
+        )
+    )
+    inventory_items = forms.NullBooleanField(
+        required=False,
+        label='Has inventory items',
+        widget=StaticSelect(
+            choices=BOOLEAN_WITH_BLANK_CHOICES
+        )
+    )
     tag = TagFilterField(model)
 
 

+ 15 - 0
netbox/dcim/forms/models.py

@@ -385,6 +385,12 @@ class ModuleTypeForm(NetBoxModelForm):
     )
     comments = CommentField()
 
+    fieldsets = (
+        ('Module Type', (
+            'manufacturer', 'model', 'part_number', 'tags',
+        )),
+    )
+
     class Meta:
         model = ModuleType
         fields = [
@@ -627,6 +633,15 @@ class ModuleForm(NetBoxModelForm):
         help_text="Automatically populate components associated with this module type"
     )
 
+    fieldsets = (
+        ('Module', (
+            'device', 'module_bay', 'manufacturer', 'module_type', 'tags',
+        )),
+        ('Hardware', (
+            'serial', 'asset_tag', 'replicate_components',
+        )),
+    )
+
     class Meta:
         model = Module
         fields = [

+ 9 - 0
netbox/dcim/tests/test_filtersets.py

@@ -698,6 +698,9 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
             DeviceBayTemplate(device_type=device_types[0], name='Device Bay 1'),
             DeviceBayTemplate(device_type=device_types[1], name='Device Bay 2'),
         ))
+        # Assigned DeviceType must have parent subdevice_role
+        inventory_item = InventoryItemTemplate(device_type=device_types[1], name='Inventory Item 1')
+        inventory_item.save()
 
     def test_model(self):
         params = {'model': ['Model 1', 'Model 2']}
@@ -784,6 +787,12 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
         params = {'module_bays': 'false'}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
 
+    def test_inventory_items(self):
+        params = {'inventory_items': 'true'}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
+        params = {'inventory_items': 'false'}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
 
 class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
     queryset = ModuleType.objects.all()

+ 10 - 6
netbox/extras/scripts.py

@@ -5,6 +5,7 @@ import os
 import pkgutil
 import sys
 import traceback
+import threading
 from collections import OrderedDict
 
 import yaml
@@ -13,11 +14,9 @@ from django.conf import settings
 from django.core.validators import RegexValidator
 from django.db import transaction
 from django.utils.functional import classproperty
-from django_rq import job
 
 from extras.api.serializers import ScriptOutputSerializer
 from extras.choices import JobResultStatusChoices, LogLevelChoices
-from extras.models import JobResult
 from ipam.formfields import IPAddressFormField, IPNetworkFormField
 from ipam.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator, prefix_validator
 from utilities.exceptions import AbortTransaction
@@ -42,6 +41,8 @@ __all__ = [
     'TextVar',
 ]
 
+lock = threading.Lock()
+
 
 #
 # Script variables
@@ -491,11 +492,14 @@ def get_scripts(use_names=False):
     # Iterate through all modules within the scripts path. These are the user-created files in which reports are
     # defined.
     for importer, module_name, _ in pkgutil.iter_modules([settings.SCRIPTS_ROOT]):
-        # Remove cached module to ensure consistency with filesystem
-        if module_name in sys.modules:
-            del sys.modules[module_name]
+        # Use a lock as removing and loading modules is not thread safe
+        with lock:
+            # Remove cached module to ensure consistency with filesystem
+            if module_name in sys.modules:
+                del sys.modules[module_name]
+
+            module = importer.find_module(module_name).load_module(module_name)
 
-        module = importer.find_module(module_name).load_module(module_name)
         if use_names and hasattr(module, 'name'):
             module_name = module.name
         module_scripts = OrderedDict()

+ 2 - 2
netbox/ipam/views.py

@@ -158,8 +158,8 @@ class RIRView(generic.ObjectView):
     queryset = RIR.objects.all()
 
     def get_extra_context(self, request, instance):
-        aggregates = Aggregate.objects.restrict(request.user, 'view').filter(
-            rir=instance
+        aggregates = Aggregate.objects.restrict(request.user, 'view').filter(rir=instance).annotate(
+            child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
         )
         aggregates_table = tables.AggregateTable(aggregates, exclude=('rir', 'utilization'))
         aggregates_table.configure(request)

+ 1 - 0
netbox/netbox/authentication.py

@@ -39,6 +39,7 @@ AUTH_BACKEND_ATTRS = {
     'keycloak': ('Keycloak', None),
     'microsoft-graph': ('Microsoft Graph', 'microsoft'),
     'okta': ('Okta', None),
+    'okta-openidconnect': ('Okta (OIDC)', None),
     'salesforce-oauth2': ('Salesforce', 'salesforce'),
 }
 

+ 2 - 0
netbox/netbox/forms/base.py

@@ -61,6 +61,8 @@ class NetBoxModelCSVForm(CSVModelForm, NetBoxModelForm):
     """
     Base form for creating a NetBox objects from CSV data. Used for bulk importing.
     """
+    tags = None  # Temporary fix in lieu of tag import support (see #9158)
+
     def _get_form_field(self, customfield):
         return customfield.to_form_field(for_csv_import=True)
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 2 - 1
netbox/project-static/src/select/api/apiSelect.ts

@@ -570,8 +570,9 @@ export class APISelect {
    * additional paginated options.
    */
   private handleScroll(): void {
+    // Floor scrollTop as chrome can return fractions on some zoom levels.
     const atBottom =
-      this.slim.slim.list.scrollTop + this.slim.slim.list.offsetHeight ===
+      Math.floor(this.slim.slim.list.scrollTop) + this.slim.slim.list.offsetHeight ===
       this.slim.slim.list.scrollHeight;
 
     if (this.atBottom && !atBottom) {

+ 4 - 1
netbox/templates/extras/customfield.html

@@ -25,7 +25,10 @@
           </tr>
           <tr>
             <th scope="row">Type</th>
-            <td>{{ object.get_type_display }}</td>
+            <td>
+              {{ object.get_type_display }}
+              {% if object.object_type %}({{ object.object_type.model|bettertitle }}){% endif %}
+            </td>
           </tr>
           <tr>
             <th scope="row">Description</th>

+ 1 - 1
netbox/templates/home.html

@@ -13,7 +13,7 @@
             <small><a href="{{ new_release.url }}">NetBox v{{ new_release.version }}</a> is available.</small>
             <hr class="my-2" />
             <small class="mb-0">
-              <a href="https://netbox.readthedocs.io/en/stable/installation/upgrading/">Upgrade Instructions</a>
+              <a href="https://docs.netbox.dev/en/stable/installation/upgrading/">Upgrade Instructions</a>
             </small>
           </div>
         </div>

+ 1 - 1
netbox/templates/media_failure.html

@@ -29,7 +29,7 @@
             </li>
             <li class="tip">
                 The HTTP service (e.g. nginx or Apache) is configured to serve files from the <code>STATIC_ROOT</code> path.
-                Refer to <a href="https://netbox.readthedocs.io/en/stable/installation/">the installation
+                Refer to <a href="https://docs.netbox.dev/en/stable/installation/">the installation
                 documentation</a> for further guidance.
                     <ul>
                         {% if request.user.is_staff or request.user.is_superuser %}

+ 3 - 3
netbox/users/models.py

@@ -173,11 +173,11 @@ class UserConfig(models.Model):
 
 
 @receiver(post_save, sender=User)
-def create_userconfig(instance, created, **kwargs):
+def create_userconfig(instance, created, raw=False, **kwargs):
     """
-    Automatically create a new UserConfig when a new User is created.
+    Automatically create a new UserConfig when a new User is created. Skip this if importing a user from a fixture.
     """
-    if created:
+    if created and not raw:
         config = get_config()
         UserConfig(user=instance, data=config.DEFAULT_USER_PREFERENCES).save()
 

+ 6 - 2
netbox/virtualization/tables/clusters.py

@@ -14,7 +14,9 @@ class ClusterTypeTable(NetBoxTable):
     name = tables.Column(
         linkify=True
     )
-    cluster_count = tables.Column(
+    cluster_count = columns.LinkedCountColumn(
+        viewname='virtualization:cluster_list',
+        url_params={'type_id': 'pk'},
         verbose_name='Clusters'
     )
     tags = columns.TagColumn(
@@ -33,7 +35,9 @@ class ClusterGroupTable(NetBoxTable):
     name = tables.Column(
         linkify=True
     )
-    cluster_count = tables.Column(
+    cluster_count = columns.LinkedCountColumn(
+        viewname='virtualization:cluster_list',
+        url_params={'group_id': 'pk'},
         verbose_name='Clusters'
     )
     contacts = tables.ManyToManyColumn(

+ 6 - 0
netbox/wireless/forms/models.py

@@ -105,6 +105,9 @@ class WirelessLinkForm(NetBoxModelForm):
     )
     location_a = DynamicModelChoiceField(
         queryset=Location.objects.all(),
+        query_params={
+            'site_id': '$site_a',
+        },
         required=False,
         label='Location',
         initial_params={
@@ -142,6 +145,9 @@ class WirelessLinkForm(NetBoxModelForm):
     )
     location_b = DynamicModelChoiceField(
         queryset=Location.objects.all(),
+        query_params={
+            'site_id': '$site_b',
+        },
         required=False,
         label='Location',
         initial_params={

Некоторые файлы не были показаны из-за большого количества измененных файлов