diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11125ae4df2..d794786f18f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,8 @@ jobs: NETBOX_CONFIGURATION: netbox.configuration_testing strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] - node-version: ['14.x'] + python-version: ['3.10', '3.11', '3.12'] + node-version: ['18.x'] services: redis: image: redis diff --git a/.readthedocs.yaml b/.readthedocs.yaml index bb42ca19fe7..c69c5174813 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,8 +1,8 @@ version: 2 build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: - python: "3.9" + python: "3.12" mkdocs: configuration: mkdocs.yml python: diff --git a/base_requirements.txt b/base_requirements.txt index 8971ebe1e1b..7c12e887168 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -1,10 +1,6 @@ -# HTML sanitizer -# https://github.com/mozilla/bleach/blob/main/CHANGES -bleach - # The Python web framework on which NetBox is built # https://docs.djangoproject.com/en/stable/releases/ -Django<5.0 +Django<5.1 # Django middleware which permits cross-domain API requests # https://github.com/adamchainz/django-cors-headers/blob/main/CHANGELOG.rst @@ -18,14 +14,13 @@ django-debug-toolbar # https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst django-filter -# Django debug toolbar extension with support for GraphiQL -# https://github.com/flavors/django-graphiql-debug-toolbar/blob/main/CHANGES.rst -django-graphiql-debug-toolbar +# HTMX utilities for Django +# https://django-htmx.readthedocs.io/en/latest/changelog.html +django-htmx # Modified Preorder Tree Traversal (recursive nesting of objects) -# Pinned to 0.14.0; 0.15.0 requires Python 3.9+ # https://github.com/django-mptt/django-mptt/blob/main/CHANGELOG.rst -django-mptt==0.14.0 +django-mptt # Context managers for PostgreSQL advisory locks # https://github.com/Xof/django-pglocks/blob/master/CHANGES.txt @@ -61,8 +56,7 @@ django-timezone-field # A REST API framework for Django projects # https://www.django-rest-framework.org/community/release-notes/ -# Pinned to 3.14 for NetBox v3.7 -djangorestframework<3.15 +djangorestframework # Sane and flexible OpenAPI 3 schema generation for Django REST framework. # https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst @@ -76,11 +70,6 @@ drf-spectacular-sidecar # https://github.com/kurtmckee/feedparser/blob/develop/CHANGELOG.rst feedparser -# Django wrapper for Graphene (GraphQL support) -# https://github.com/graphql-python/graphene-django/releases -# Pinned to v3.0.0 for GraphiQL UI issue (see #12762) -graphene_django==3.0.0 - # WSGI HTTP server # https://docs.gunicorn.org/en/latest/news.html gunicorn @@ -109,6 +98,10 @@ mkdocstrings[python-legacy] # https://github.com/netaddr/netaddr/blob/master/CHANGELOG.rst netaddr +# Python bindings to the ammonia HTML sanitization library. +# https://github.com/messense/nh3 +nh3 + # Fork of PIL (Python Imaging Library) for image processing # https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst Pillow @@ -133,8 +126,17 @@ social-auth-core # https://github.com/python-social-auth/social-app-django/blob/master/CHANGELOG.md social-auth-app-django +# Strawberry GraphQL +# https://github.com/strawberry-graphql/strawberry/blob/main/CHANGELOG.md +strawberry-graphql + +# Strawberry GraphQL Django extension +# https://github.com/strawberry-graphql/strawberry-django/blob/main/CHANGELOG.md +# Pinned per #15574 +strawberry-graphql-django==0.34.0 + # SVG image rendering (used for rack elevations) -# hhttps://github.com/mozman/svgwrite/blob/master/NEWS.rst +# https://github.com/mozman/svgwrite/blob/master/NEWS.rst svgwrite # Tabular dataset library (for table-based exports) diff --git a/contrib/netbox.service b/contrib/netbox.service index 3cd02d98834..8c602fa5ba4 100644 --- a/contrib/netbox.service +++ b/contrib/netbox.service @@ -12,8 +12,12 @@ Group=netbox PIDFile=/var/tmp/netbox.pid WorkingDirectory=/opt/netbox +# Remove the following line if using uWSGI instead of Gunicorn ExecStart=/opt/netbox/venv/bin/gunicorn --pid /var/tmp/netbox.pid --pythonpath /opt/netbox/netbox --config /opt/netbox/gunicorn.py netbox.wsgi +# Uncomment the following line if using uWSGI instead of Gunicorn +#ExecStart=/opt/netbox/venv/bin/uwsgi --ini /opt/netbox/uwsgi.ini + Restart=on-failure RestartSec=30 PrivateTmp=true diff --git a/contrib/nginx.conf b/contrib/nginx.conf index 34821cd52c3..31d026e0d3a 100644 --- a/contrib/nginx.conf +++ b/contrib/nginx.conf @@ -14,10 +14,20 @@ server { } location / { + # Remove these lines if using uWSGI instead of Gunicorn proxy_pass http://127.0.0.1:8001; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; + + # Uncomment these lines if using uWSGI instead of Gunicorn + # include uwsgi_params; + # uwsgi_pass 127.0.0.1:8001; + # uwsgi_param Host $host; + # uwsgi_param X-Real-IP $remote_addr; + # uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + # uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto; + } } diff --git a/contrib/uwsgi.ini b/contrib/uwsgi.ini new file mode 100644 index 00000000000..d6480315857 --- /dev/null +++ b/contrib/uwsgi.ini @@ -0,0 +1,18 @@ +[uwsgi] +; bind to the specified UNIX/TCP socket and port (usually localhost) +socket = 127.0.0.1:8001 + +; fail to start if any parameter in the configuration file isn’t explicitly understood by uWSGI. +strict = true + +; re-spawn and pre-fork workers +master = true + +; clear environment on exit +vacuum = true + +; exit if no app can be loaded +need-app = true + +; do not use multiple interpreters +single-interpreter = true diff --git a/docs/administration/authentication/microsoft-azure-ad.md b/docs/administration/authentication/microsoft-azure-ad.md index a5e24b0c9e6..17b13081896 100644 --- a/docs/administration/authentication/microsoft-azure-ad.md +++ b/docs/administration/authentication/microsoft-azure-ad.md @@ -73,7 +73,7 @@ You should be redirected to Microsoft's authentication portal. Enter the usernam If successful, you will be redirected back to the NetBox UI, and will be logged in as the AD 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 by navigating to Admin > Permissions. +This user account has been replicated locally to NetBox, and can now be assigned groups and permissions. ## Troubleshooting diff --git a/docs/administration/authentication/okta.md b/docs/administration/authentication/okta.md index 67c0ea41bd1..2cab186ee90 100644 --- a/docs/administration/authentication/okta.md +++ b/docs/administration/authentication/okta.md @@ -67,4 +67,4 @@ You should be redirected to Okta's authentication portal. Enter the username/ema 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 by navigating to Admin > Permissions. +This user account has been replicated locally to NetBox, and can now be assigned groups and permissions. diff --git a/docs/administration/authentication/overview.md b/docs/administration/authentication/overview.md index 0c8858b2ff5..a6c3a315976 100644 --- a/docs/administration/authentication/overview.md +++ b/docs/administration/authentication/overview.md @@ -4,7 +4,7 @@ Local user accounts and groups can be created in NetBox under the "Authentication" section in the "Admin" menu. This section is available only to users with the "staff" permission enabled. -At a minimum, each user account must have a username and password set. User accounts may also denote a first name, last name, and email address. [Permissions](../permissions.md) may also be assigned to users and/or groups under Admin > Permissions. +At a minimum, each user account must have a username and password set. User accounts may also denote a first name, last name, and email address. [Permissions](../permissions.md) may also be assigned to individual users and/or groups as needed. ## Remote Authentication diff --git a/docs/administration/permissions.md b/docs/administration/permissions.md index 95f0f0c0517..d16d599d947 100644 --- a/docs/administration/permissions.md +++ b/docs/administration/permissions.md @@ -70,8 +70,6 @@ The `$user` token can be used only as a constraint value, or as an item within a ### Default Permissions -!!! info "This feature was introduced in NetBox v3.6." - While permissions are typically assigned to specific groups and/or users, it is also possible to define a set of default permissions that are applied to _all_ authenticated users. This is done using the [`DEFAULT_PERMISSIONS`](../configuration/security.md#default_permissions) configuration parameter. Note that statically configuring permissions for specific users or groups is **not** supported. ### Example Constraint Definitions diff --git a/docs/configuration/date-time.md b/docs/configuration/date-time.md deleted file mode 100644 index a23053e0804..00000000000 --- a/docs/configuration/date-time.md +++ /dev/null @@ -1,23 +0,0 @@ -# Date & Time Parameters - -## TIME_ZONE - -Default: UTC - -The time zone NetBox will use when dealing with dates and times. It is recommended to use UTC time unless you have a specific need to use a local time zone. Please see the [list of available time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). - -## Date and Time Formatting - -You may define custom formatting for date and times. For detailed instructions on writing format strings, please see [the Django documentation](https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date). Default formats are listed below. - -!!! note - These system defaults will be overridden by a user's selected language/locale when [localization](./system.md#enable_localization) is enabled. - -```python -DATE_FORMAT = 'N j, Y' # June 26, 2016 -SHORT_DATE_FORMAT = 'Y-m-d' # 2016-06-26 -TIME_FORMAT = 'g:i a' # 1:23 p.m. -SHORT_TIME_FORMAT = 'H:i:s' # 13:23:00 -DATETIME_FORMAT = 'N j, Y g:i a' # June 26, 2016 1:23 p.m. -SHORT_DATETIME_FORMAT = 'Y-m-d H:i' # 2016-06-26 13:23 -``` diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index 4d4ca189ea9..1f0a2781bca 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -33,9 +33,6 @@ This defines custom content to be displayed on the login page above the login fo !!! tip "Dynamic Configuration Parameter" -!!! note - This parameter was added in NetBox v3.5. - This adds a banner to the top of every page when maintenance mode is enabled. HTML is allowed. --- @@ -99,6 +96,14 @@ The maximum size (in bytes) of an incoming HTTP request (i.e. `GET` or `POST` da --- +## DJANGO_ADMIN_ENABLED + +Default: False + +Setting this to True installs the `django.contrib.admin` app and enables the [Django admin UI](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/). This may be necessary to support older plugins which do not integrate with the native NetBox interface. + +--- + ## ENFORCE_GLOBAL_UNIQUE !!! tip "Dynamic Configuration Parameter" @@ -107,9 +112,6 @@ Default: True By default, NetBox will prevent the creation of duplicate prefixes and IP addresses in the global table (that is, those which are not assigned to any VRF). This validation can be disabled by setting `ENFORCE_GLOBAL_UNIQUE` to False. -!!! info "Changed in v3.7" - The default value for this parameter was changed from False to True in NetBox v3.7. - --- ## FILE_UPLOAD_MAX_MEMORY_SIZE @@ -134,9 +136,6 @@ Setting this to False will disable the GraphQL API. !!! tip "Dynamic Configuration Parameter" -!!! note - This parameter was renamed from `JOBRESULT_RETENTION` in NetBox v3.5. - Default: 90 The number of days to retain job results (scripts and reports). Set this to `0` to retain job results in the database indefinitely. @@ -231,9 +230,6 @@ The maximum execution time of a background task (such as running a custom script ## RQ_RETRY_INTERVAL -!!! note - This parameter was added in NetBox v3.5. - Default: `60` This parameter controls how frequently a failed job is retried, up to the maximum number of times specified by `RQ_RETRY_MAX`. This must be either an integer specifying the number of seconds to wait between successive attempts, or a list of such values. For example, `[60, 300, 3600]` will retry the task after 1 minute, 5 minutes, and 1 hour. @@ -242,9 +238,6 @@ This parameter controls how frequently a failed job is retried, up to the maximu ## RQ_RETRY_MAX -!!! note - This parameter was added in NetBox v3.5. - Default: `0` (retries disabled) The maximum number of times a background task will be retried before being marked as failed. diff --git a/docs/configuration/security.md b/docs/configuration/security.md index 9de09cedad0..45d5bed3f39 100644 --- a/docs/configuration/security.md +++ b/docs/configuration/security.md @@ -92,8 +92,6 @@ CSRF_TRUSTED_ORIGINS = ( ## DEFAULT_PERMISSIONS -!!! info "This parameter was introduced in NetBox v3.6." - Default: ```python diff --git a/docs/configuration/system.md b/docs/configuration/system.md index 28c09444bd6..d0814bca6c2 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -62,14 +62,6 @@ Email is sent from NetBox only for critical events or if configured for [logging --- -## ENABLE_LOCALIZATION - -Default: False - -Determines if localization features are enabled or not. This should only be enabled for development or testing purposes as netbox is not yet fully localized. Turning this on will localize numeric and date formats (overriding any configured [system defaults](./date-time.md#date-and-time-formatting)) based on the browser locale as well as translate certain strings from third party modules. - ---- - ## HTTP_PROXIES Default: None @@ -200,3 +192,9 @@ A dictionary of configuration parameters for the storage backend configured as ` If `STORAGE_BACKEND` is not defined, this setting will be ignored. --- + +## TIME_ZONE + +Default: UTC + +The time zone NetBox will use when dealing with dates and times. It is recommended to use UTC time unless you have a specific need to use a local time zone. Please see the [list of available time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). diff --git a/docs/customization/custom-fields.md b/docs/customization/custom-fields.md index e9ff7bd9f60..1f9a4a8bfd9 100644 --- a/docs/customization/custom-fields.md +++ b/docs/customization/custom-fields.md @@ -42,8 +42,6 @@ This parameter has no effect on the API representation of custom field data. ### Visibility & Editing -!!! info "This feature was improved in NetBox v3.7." - When creating a custom field, users can control the conditions under which it may be displayed and edited within the NetBox user interface. The following choices are available for controlling the display of a custom field on an object: * **Always** (default): The custom field is included when viewing an object. diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 76ca7130fb7..21ae20f0558 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -5,8 +5,17 @@ Custom scripting was introduced to provide a way for users to execute custom log * Automatically populate new devices and cables in preparation for a new site deployment * Create a range of new reserved prefixes or IP addresses * Fetch data from an external source and import it to NetBox +* Update objects with invalid or incomplete data -Custom scripts are Python code and exist outside of the official NetBox code base, so they can be updated and changed without interfering with the core NetBox installation. And because they're completely custom, there is no inherent limitation on what a script can accomplish. +They can also be used as a mechanism for validating the integrity of data within NetBox. Script authors can define test to check object against specific rules and conditions. For example, you can write script to check that: + +* All top-of-rack switches have a console connection +* Every router has a loopback interface with an IP address assigned +* Each interface description conforms to a standard format +* Every site has a minimum set of VLANs defined +* All IP addresses have a parent prefix + +Custom scripts are Python code which exists outside the NetBox code base, so they can be updated and changed without interfering with the core NetBox installation. And because they're completely custom, there is no inherent limitation on what a script can accomplish. ## Writing Custom Scripts @@ -135,13 +144,73 @@ These two methods will load data in YAML or JSON format, respectively, from file The Script object provides a set of convenient functions for recording messages at different severity levels: -* `log_debug` -* `log_success` -* `log_info` -* `log_warning` -* `log_failure` +* `log_debug(message, object=None)` +* `log_success(message, object=None)` +* `log_info(message, object=None)` +* `log_warning(message, object=None)` +* `log_failure(message, object=None)` + +Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages. A message may optionally be associated with a particular object by passing it as the second argument to the logging method. + +## Test Methods + +A script can define one or more test methods to report on certain conditions. All test methods must have a name beginning with `test_` and accept no arguments beyond `self`. -Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages. +These methods are detected and run automatically when the script is executed, unless its `run()` method has been overridden. (When overriding `run()`, `run_tests()` can be called to run all test methods present in the script.) + +!!! info + This functionality was ported from [legacy reports](./reports.md) in NetBox v4.0. + +### Example + +``` +from dcim.choices import DeviceStatusChoices +from dcim.models import ConsolePort, Device, PowerPort +from extras.scripts import Script + + +class DeviceConnectionsReport(Script): + description = "Validate the minimum physical connections for each device" + + def test_console_connection(self): + + # Check that every console port for every active device has a connection defined. + active = DeviceStatusChoices.STATUS_ACTIVE + for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=active): + if not console_port.connected_endpoints: + self.log_failure( + f"No console connection defined for {console_port.name}", + console_port.device, + ) + elif not console_port.connection_status: + self.log_warning( + f"Console connection for {console_port.name} marked as planned", + console_port.device, + ) + else: + self.log_success("Passed", console_port.device) + + def test_power_connections(self): + + # Check that every active device has at least two connected power supplies. + for device in Device.objects.filter(status=DeviceStatusChoices.STATUS_ACTIVE): + connected_ports = 0 + for power_port in PowerPort.objects.filter(device=device): + if power_port.connected_endpoints: + connected_ports += 1 + if not power_port.path.is_active: + self.log_warning( + f"Power connection for {power_port.name} marked as planned", + device, + ) + if connected_ports < 2: + self.log_failure( + f"{connected_ports} connected power supplies found (2 needed)", + device, + ) + else: + self.log_success("Passed", device) +``` ## Change Logging @@ -235,6 +304,7 @@ A particular object within NetBox. Each ObjectVar must specify a particular mode * `model` - The model class * `query_params` - A dictionary of query parameters to use when retrieving available options (optional) +* `context` - A custom dictionary mapping template context variables to fields, used when rendering `