Prefetch the Tenant Group in views which allows its table to be configured
by the user. This decreases the amount of database queries that are required
to fetch the data.
Configure the prefetch to also include the Tenant Group, avoids additional
database queries when the Tenant Group column is to be rendered.
NOTE: If no personalisation of the global search tables should be done,
this commit can be reverted.
Replaces all usages of the TenantColumn with the new TenancyColumnsMixin.
This enables the user to add a column for Tenant Group on all tables which
also has a column for Tenant.
Works the same as the existing TenantColumn, but displats the Tenant Group of
the Tenant.
Views should prefetch the Tenants Group for this to be efficient in large
tables.
* Closes#9396 - Added ability to query modules by module bay & installed_modules for module bay REST API endpoint
* Closes#9396 - Added ability to query modules by module bay & installed_modules for module bay REST API endpoint
* Closes#9396 - Added ability to query modules by module bay & installed_modules for module bay REST API endpoint
Fixes#8920
Limits the amount of non-racked devices on Site and Location view to 10 and provides a link to the device list this is pre-filtered to the relevant site or location.
When using permissions that use tags, a user may receive multiple permissions
of the same type if multiple tags are assigned to the device. This causes the
RestrictedQuerySet class to generate a query similar to this:
>>> dcim.models.Device.objects.filter(Q(tags__name='tag1')|Q(tags__name='tag2'))
<ConfigContextModelQuerySet [<Device: device1>, <Device: device1>]>
This query returns the same object twice if both tags are assigned to it. This
is due to the use of the django-taggit library. The library's documentation
describes this behavior as expected and suggests using an explicit distinct()
call in queries to avoid duplicates.
However, the use of DISTINCT in queries has a global side effect -
deduplication of responses, which may or may not be acceptable behavior
(depending on further use). Since it is not known how RestrictedQuerySet will
be used in the rest of the code, it was decided to dedupe using a subquery.
In the current documentation we have two seemingly conflicting sentences:
* REMOTE_AUTH_DEFAULT_GROUPS: (Requires REMOTE_AUTH_ENABLED.)
* REMOTE_AUTH_ENABLED: (REMOTE_AUTH_DEFAULT_GROUPS will not function if REMOTE_AUTH_ENABLED is enabled)
* Fixes#8398: Add ConfigParam.size to enlarge specific config fields
* Revert "Fixes #8398: Add ConfigParam.size to enlarge specific config fields"
This reverts commit 05e8fff458.
* Use forms.Textarea for the banner config fields
created & last_updated fields are missing from some REST API calls. Added missing fields to the following API calls
/api/dcim/virtual-chassis/
/api/dcim/cables/
/api/dcim/power-panels/
/api/dcim/rack-reservations/
/api/circuits/circuit-terminations/
/api/extras/webhooks/
/api/extras/custom-fields/
/api/extras/custom-links/
/api/extras/export-templates/
/api/extras/tags/
Adds two fields to all relevant tables to allow the addition of Created & Last Updated columns.
All tables with a Configure Table option were updated.
Some sections reformatted to comply with E501 line length as a result of changes
* Updating asdot computation to use an fstring
* Cleaning code. Custom property now returns either the ASN with ASDOT notation or just the ASN. asn_with_asdot can now be referenced in ASNTable & objet template.
Adds custom property to asn model to compute asdot notation if required.
Updates asn view to show asdot notation if one exists in the format xxxxx (yyy.yyy)
Adds a custom column renderer to asn table to display asdot notation if one exists
A device that is part of a VC that has no name should display [virtual-chassis name]:[virtual-chassis position] as opposed to [device_type] in the rack rendering.
Adds a custom column class to format the commit rate in the circuits table view using humanize_speed template helper. Export still exports the raw number.
Updating site location list to visually match the /dcim/locations list where child locations are "indtended" with mdi-circle-small.
Also removes the padding-left attribute on each row as it is no longer functional.
* Re-instates ASN field on Site model
* Re-instates ASN field on Site view
* Re-instates ASN field on edit form and API, except for where forms instances are new (add site) or instance does not have any existing AS data
* Does not re-instate asn field on SiteBulkEditForm
* Does not re-instate ASN field on SiteTable
* Does not re-instate filter for filterset, but does allow filtering by query (q=34342)
* Does not include tests for ASN field on Site model due to planned deprecation
fix incorrect assumption about when to run the group sync
Add documentation for new Settings
format to autopep8 compliance
add first set of basic testcases
format test to comply with pep8
rename SEPERATOR to SEPARATOR
remove accidentally carried over parameter
* Fixes#7035: Refactor APISelect query_param logic
* Add filter_fields to extras.ObjectVar & fix default value handling
* Update ObjectVar docs to reflect new filter_fields attribute
* Revert changes from 89b7f3f
* Maintain current `query_params` API for form fields, transform data structure in widget
* Revert changes from d0208d4
* Split object list and filters into tabs
* Use object_list template for connections, rack elevations
* Include custom field filters in grouped filter form
* Annotate number of applied filters on tab
* Rearrange table controls
* Incorporate local documentation build in upgrade script
* Add docs build to CI
* Include docs build path in revision control
* Update footer dcos link
* Changelog for #6328
* Clean up errant links
When users are authenticated with an API token not all permissions where
assigned to the session because the LDAP group memberships where not
available.
Now the information is loaded from the directory if the user is found.
If not the local group memberships are used.
This prevents a crash when the current user has authenticated himself
with an API token. In this case the user will not have the permissions
given to his LDAP groups.
When AUTH_LDAP_FIND_GROUP_PERMS is set to true the filter to find the
users permissions is extended to search for all permissions assigned to
groups in which the LDAP user is.
@jeremystretch:
> It'd be better to have the custom field return a date object than to
> accommodate string values in the template filter. Let's just omit custom
> field dates for now to keep this from getting any more complex.
This changes the text from: Updated 5 months, 1 week ago
to: Updated 2021-01-24 00:33 (5 months, 1 week ago)
Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
With this commit all dates in the UI are now consistently displayed.
I changed the long date format as suggested by @xkilian and confirmed by my own
research.
* DATETIME_FORMAT
* Before July 20, 2020 4:52 p.m.
* Now 20th July, 2020 16:52
"20th July, 2020" would be spoken as "the 20th of July, 2020" but the "the" and
"of" are never written.
The only exception is `object_list.html`. I tried it but there it does not
work so easily because the dates are passed to Jinja as SafeString.
* Clean up & comment base templates
* Clean up login template & form
* Use SVG file for NetBox logo
* Simplify breadcrumbs
* Merge changelog.html into home.html
* Rename title_container block to header
* Move breadcrumbs block to object.html
* Attach names to endblock template tags
* Reorganize root-level templates into base/ and inc/
* Remove obsolete reference to Bootstrap 3.4.1
New validate_form method on ComponentCreateView handles validation generically, which any post() method on ComponentCreateView can use to validate the form but handle the response differently as needed.
There are situations in which it is convenient to be able to modify the name of the cookie that the application uses for storing the session token (conflicts with other cookies on the same domain, for example).
At present, a mix of link types are used in the Netbox
documentation from markdown file links to relative and
absolute anchor links.
Of the three types, linking to markdown files is the
most ideal because it allows navigation locally on disk,
as well as being translated into working links at render
time.
While not obvious, mkdocs handles converting markdown
links to valid URLs.
Signed-Off-by: Marcus Crane <marcu.crane@daimler.com>
* Initial work on #5892
* Add site group selection to object edit forms
* Add documentation for site groups
* Changelog for #5892
* Finish application of site groups to config context
* Initial work on #5913
* Provide per-line diff highlighting
* BulkDeteView should delete objects individually to secure a pre-change snapshot
* Add changelog tests for bulk operations
At least on ubuntu 20.04, the python3 package is now 3.8, but the package 'python3' points to the current best version of python available without needing to specialize a minor version and should require fewer changes to the document.
* Use HTTPS everywhere (mechanical edit using util from https-everywhere)
```Shell
node ~/src/EFForg/https-everywhere/utils/rewriter/rewriter.js .
git checkout netbox/project-static/
```
A few additional changes where reset manually before the commit.
* Use HTTPS everywhere (mechanical edit using util from opening_hours.js)
```Shell
make -f ~/src/opening-hours/opening_hours.js/Makefile qa-https-everywhere
git checkout netbox/project-static/
git checkout netbox/*/tests
```
* Convert circuits to use subqueries
* Convert dcim to use subqueries
* Convert extras to use subqueries
* Convert ipam to use subqueries
* Convert secrets to use subqueries
* Convert virtualization to use subqueries
* Update global search view to use subqueries where appropriate
* Remove extraneous order_by() calls
Since the CONNECTION_STATUS_PLANNED constant is gone from dcim.constants, the DeviceConnectionsReport script is no longer correct.
The suggested fix is based on the fact that console_port.connection_status and power_port.connection_status currently have the following set of values:
* None = A cable is not connected to a Console Server Port or it's connected to a Rear/Front Port;
* False = A cable is connected to a Console Server Port and marked as Planned;
* True = A cable is connected to a Console Server Port and marked as Installed.
Update the LDAP troubleshooting steps so that they are consistent with the rest of the documentaiton, which nowadays expects us to be running netbox via systemd instead of supervisord. Fixes#4504.
**The [2020 NetBox user survey](https://docs.google.com/forms/d/1OVZuC4kQ-6kJbVf0bDB6vgkL9H96xF6phvYzby23elk/edit) is open!** Your feedback helps guide the project's long-term development.
NetBox is an IP address management (IPAM) and data center infrastructure
management (DCIM) tool. Initially conceived by the network engineering team at
NetBox is an infrastructure resource modeling (IRM) tool designed to empower
network automation, used by thousands of organizations around the world.
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. It is intended to
function as a domain-specific source of truth for network operations.
Myriad infrastructure components can be modeled in NetBox, including:
* Hierarchical regions, site groups, sites, and locations
* Racks, devices, and device components
* Cables and wireless connections
* Power distribution
* Data circuits and providers
* Virtual machines and clusters
* IP prefixes, ranges, and addresses
* VRFs and route targets
* FHRP groups (VRRP, HSRP, etc.)
* AS numbers
* VLANs and scoped VLAN groups
* Organizational tenants and contacts
In addition to its extensive built-in models and functionality, NetBox can be
customized and extended through the use of:
* Custom fields
* Custom links
* Configuration contexts
* Custom model validation rules
* Reports
* Custom scripts
* Export templates
* Conditional webhooks
* Plugins
* Single sign-on (SSO) authentication
* NAPALM integration
* Detailed change logging
NetBox also features a complete REST API as well as a GraphQL API for easily
integrating with other tools and systems.
NetBox runs as a web application atop the [Django](https://www.djangoproject.com/)
Python framework with a [PostgreSQL](http://www.postgresql.org/) database. For a
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](http://netbox.readthedocs.io/en/stable/).
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.
Questions? Comments? Please subscribe to [the netbox-discuss mailing list](https://groups.google.com/forum/#!forum/netbox-discuss),
or join us in the #netbox Slack channel on [NetworkToCode](https://networktocode.slack.com/)!

* [GitHub Discussions](https://github.com/netbox-community/netbox/discussions) - Discussion forum hosted by GitHub; ideal for Q&A and other structured discussions
* [Slack](https://netdev.chat/) - Real-time chat hosted by the NetDev Community; best for unstructured discussion or just hanging out
---
### Installation

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`.
---
### Providing Feedback

## Installation
Please see [the documentation](http://netbox.readthedocs.io/en/stable/) for
instructions on installing NetBox. To upgrade NetBox, please download the [latest release](https://github.com/netbox-community/netbox/releases)
and run `upgrade.sh`.
## Providing Feedback
Feature requests and bug reports must be submitted as GiHub issues. (Please be
sure to use the [appropriate template](https://github.com/netbox-community/netbox/issues/new/choose).)
For general discussion, please consider joining our [mailing list](https://groups.google.com/forum/#!forum/netbox-discuss).
The best platform for general feedback, assistance, and other discussion is our
Per the terms of the Apache 2 license, NetBox is offered "as is" and without any guarantee or warranty pertaining to its operation. While every reasonable effort is made by its maintainers to ensure the product remains free of security vulnerabilities, users are ultimately responsible for conducting their own evaluations of each software release.
## Recommendations
Administrators are encouraged to adhere to industry best practices concerning the secure operation of software, such as:
* Do not expose your NetBox installation to the public Internet
* Do not permit multiple users to share an account
* Enforce minimum password complexity requirements for local accounts
* Prohibit access to your database from clients other than the NetBox application
* Keep your deployment updated to the most recent stable release
## Reporting a Suspected Vulnerability
If you believe you've uncovered a security vulnerability and wish to report it confidentially, you may do so via email. Please note that any reported vulnerabilities **MUST** meet all the following conditions:
* Affects the most recent stable release of NetBox, or a current beta release
* Affects a NetBox instance installed and configured per the official documentation
* Is reproducible following a prescribed set of instructions
Please note that we **DO NOT** accept reports generated by automated tooling which merely suggest that a file or file(s) _may_ be vulnerable under certain conditions, as these are most often innocuous.
If you believe that you've found a vulnerability which meets all of these conditions, please email a brief description of the suspected bug and instructions for reproduction to **security@netbox.dev**. For any security concerns regarding NetBox deployed via Docker, please see the [netbox-docker](https://github.com/netbox-community/netbox-docker) project.
### Bug Bounties
As NetBox is provided as free open source software, we do not offer any monetary compensation for vulnerability or bug reports, however your contributions are greatly appreciated.
Every time an object in NetBox is created, updated, or deleted, a serialized copy of that object is saved to the database, along with meta data including the current time and the user associated with the change. These records form a running changelog both for each individual object as well as NetBox as a whole (Organization > Changelog).
Every time an object in NetBox is created, updated, or deleted, a serialized copy of that object taken both before and after the change is saved to the database, along with meta data including the current time and the user associated with the change. These records form a persistent record of changes both for each individual object as well as NetBox as a whole. The global change log can be viewed by navigating to Other > Change Log.
A serialized representation is included for each object in JSON format. This is similar to how objects are conveyed within the REST API, but does not include any nested representations. For instance, the `tenant` field of a site will record only the tenant's ID, not a representation of the tenant.
A serialized representation of the instance being modified is included in JSON format. This is similar to how objects are conveyed within the REST API, but does not include any nested representations. For instance, the `tenant` field of a site will record only the tenant's ID, not a representation of the tenant.
When a request is made, a random request ID is generated and attached to any change records resulting from the request. For example, editing multiple objects in bulk will create a change record for each object, and each of those objects will be assigned the same request ID. This makes it easy to identify all the change records associated with a particular request.
When a request is made, a UUID is generated and attached to any change records resulting from that request. For example, editing three objects in bulk will create a separate change record for each (three in total), and each of those objects will be associated with the same UUID. This makes it easy to identify all the change records resulting from a particular request.
Change records are exposed in the API via the read-only endpoint `/api/extras/object-changes/`. They may also be exported in CSV format.
Change records are exposed in the API via the read-only endpoint `/api/extras/object-changes/`. They may also be exported via the web UI in CSV format.
Each object in NetBox is represented in the database as a discrete table, and each attribute of an object exists as a column within its table. For example, sites are stored in the `dcim_site` table, which has columns named `name`, `facility`, `physical_address`, and so on. As new attributes are added to objects throughout the development of NetBox, tables are expanded to include new rows.
However, some users might want to associate with objects attributes that are somewhat esoteric in nature, and that would not make sense to include in the core NetBox database schema. For instance, suppose your organization needs to associate each device with a ticket number pointing to the support ticket that was opened to have it installed. This is certainly a legitimate use for NetBox, but it's perhaps not a common enough need to warrant expanding the internal data schema. Instead, you can create a custom field to hold this data.
Custom fields must be created through the admin UI under Extras > Custom Fields. To create a new custom field, select the object(s) to which you want it to apply, and the type of field it will be. NetBox supports six field types:
* Free-form text (up to 255 characters)
* Integer
* Boolean (true/false)
* Date
* URL
* Selection
Assign the field a name. This should be a simple database-friendly string, e.g. `tps_report`. You may optionally assign the field a human-friendly label (e.g. "TPS report") as well; the label will be displayed on forms. If a description is provided, it will appear beneath the field in a form.
Marking the field as required will require the user to provide a value for the field when creating a new object or when saving an existing object. A default value for the field may also be provided. Use "true" or "false" for boolean fields. (The default value has no effect for selection fields.)
When creating a selection field, you should create at least two choices. These choices will be arranged first by weight, with lower weights appearing higher in the list, and then alphabetically.
## Using Custom Fields
When a single object is edited, the form will include any custom fields which have been defined for the object type. These fields are included in the "Custom Fields" panel. On the backend, each custom field value is saved separately from the core object as an independent database call, so it's best to avoid adding too many custom fields per object.
When editing multiple objects, custom field values are saved in bulk. There is no significant difference in overhead when saving a custom field value for 100 objects versus one object. However, the bulk operation must be performed separately for each custom field.
Custom links allow users to place arbitrary hyperlinks within NetBox views. These are helpful for cross-referencing related records in external systems. For example, you might create a custom link on the device view which links to the current device in a network monitoring system.
Custom links are created under the admin UI. Each link is associated with a particular NetBox object type (site, device, prefix, etc.) and will be displayed on relevant views. Each link is assigned text and a URL, both of which support Jinja2 templating. The text and URL are rendered with the context variable `obj` representing the current object.
Custom links appear as buttons at the top right corner of the page. Numeric weighting can be used to influence the ordering of links.
## Conditional Rendering
Only links which render with non-empty text are included on the page. You can employ conditional Jinja2 logic to control the conditions under which a link gets rendered.
For example, if you only want to display a link for active devices, you could set the link text to
```
{% if obj.status == 1 %}View NMS{% endif %}
```
The link will not appear when viewing a device with any status other than "active."
Another example, if you want to only show an object of a certain manufacturer, you could set the link text to:
```
{% if obj.device_type.manufacturer.name == 'Cisco' %}View NMS {% endif %}
```
The link will only appear when viewing a device with a manufacturer name of "Cisco."
## Link Groups
You can specify a group name to organize links into related sets. Grouped links will render as a dropdown menu beneath a
NetBox allows users to define custom templates that can be used when exporting objects. To create an export template, navigate to Extras > Export Templates under the admin interface.
Each export template is associated with a certain type of object. For instance, if you create an export template for VLANs, your custom template will appear under the "Export" button on the VLANs list.
Export templates are written in [Django's template language](https://docs.djangoproject.com/en/stable/ref/templates/language/), which is very similar to Jinja2. The list of objects returned from the database is stored in the `queryset` variable, which you'll typically want to iterate through using a `for` loop. Object properties can be access by name. For example:
```
{% for rack in queryset %}
Rack: {{ rack.name }}
Site: {{ rack.site.name }}
Height: {{ rack.u_height }}U
{% endfor %}
```
To access custom fields of an object within a template, use the `cf` attribute. For example, `{{ obj.cf.color }}` will return the value (if any) for a custom field named `color` on `obj`.
A MIME type and file extension can optionally be defined for each export template. The default MIME type is `text/plain`.
## Example
Here's an example device export template that will generate a simple Nagios configuration from a list of devices.
```
{% for device in queryset %}{% if device.status and device.primary_ip %}define host{
use generic-switch
host_name {{ device.name }}
address {{ device.primary_ip.address.ip }}
}
{% endif %}{% endfor %}
```
The generated output will look something like this:
NetBox does not have the ability to generate graphs natively, but this feature allows you to embed contextual graphs from an external resources (such as a monitoring system) inside the site, provider, and interface views. Each embedded graph must be defined with the following parameters:
* **Type:** Site, device, provider, or interface. This determines in which view the graph will be displayed.
* **Weight:** Determines the order in which graphs are displayed (lower weights are displayed first). Graphs with equal weights will be ordered alphabetically by name.
* **Name:** The title to display above the graph.
* **Source URL:** The source of the image to be embedded. The associated object will be available as a template variable named `obj`.
* **Link URL (optional):** A URL to which the graph will be linked. The associated object will be available as a template variable named `obj`.
Graph names and links can be rendered using the Django or Jinja2 template languages.
!!! warning
Support for the Django templating language will be removed in NetBox v2.8. Jinja2 is recommended.
## Examples
You only need to define one graph object for each graph you want to include when viewing an object. For example, if you want to include a graph of traffic through an interface over the past five minutes, your graph source might looks like this:
All primary objects in NetBox support journaling. A journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after a configurable period of time, journal entries persist for the life of their associated object.
Each journal entry has a selectable kind (info, success, warning, or danger) and a user-populated `comments` field. Each entry automatically records the date, time, and associated user upon being created.
NetBox supports integration with the [NAPALM automation](https://napalm-automation.net/) library. NAPALM allows NetBox to fetch live data from devices and return it to a requester via its REST API.
NetBox supports integration with the [NAPALM automation](https://github.com/napalm-automation/napalm) library. NAPALM allows NetBox to serve a proxy for operational data, fetching live data from network devices and returning it to a requester via its REST API. Note that NetBox does not store any NAPALM data locally.
!!! info
To enable the integration, the NAPALM library must be installed. See [installation steps](../../installation/3-netbox/#napalm-automation-optional) for more information.
The NetBox UI will display tabs for status, LLDP neighbors, and configuration under the device view if the following conditions are met:
```
* Device status is "Active"
* A primary IP has been assigned to the device
* A platform with a NAPALM driver has been assigned
* The authenticated user has the `dcim.napalm_read_device` permission
!!! note
To enable this integration, the NAPALM library must be installed. See [installation steps](../../installation/3-netbox/#napalm) for more information.
Below is an example REST API request and response:
```no-highlight
GET /api/dcim/devices/1/napalm/?method=get_environment
{
@@ -15,13 +24,16 @@ GET /api/dcim/devices/1/napalm/?method=get_environment
}
```
!!! note
To make NAPALM requests via the NetBox REST API, a NetBox user must have assigned a permission granting the `napalm_read` action for the device object type.
## Authentication
By default, the [`NAPALM_USERNAME`](../../configuration/optional-settings/#napalm_username) and [`NAPALM_PASSWORD`](../../configuration/optional-settings/#napalm_password) are used for NAPALM authentication. They can be overridden for an individual API call through the `X-NAPALM-Username` and `X-NAPALM-Password` headers.
By default, the [`NAPALM_USERNAME`](../configuration/dynamic-settings.md#napalm_username) and [`NAPALM_PASSWORD`](../configuration/dynamic-settings.md#napalm_password) configuration parameters are used for NAPALM authentication. They can be overridden for an individual API call by specifying the `X-NAPALM-Username` and `X-NAPALM-Password` headers.
The list of supported NAPALM methods depends on the [NAPALM driver](https://napalm.readthedocs.io/en/latest/support/index.html#general-support-matrix) configured for the platform of a device. NetBox only supports [get](https://napalm.readthedocs.io/en/latest/support/index.html#getters-support-matrix) methods.
The list of supported NAPALM methods depends on the [NAPALM driver](https://napalm.readthedocs.io/en/latest/support/index.html#general-support-matrix) configured for the platform of a device. Because there is no granular mechanism in place for limiting potentially disruptive requests, NetBox supports only read-only [get](https://napalm.readthedocs.io/en/latest/support/index.html#getters-support-matrix) methods.
## Multiple Methods
More than one method in an API call can be invoked by adding multiple `method` parameters. For example:
It is possible to request the output of multiple NAPALM methods in a single API request by passing multiple `method` parameters. For example:
```
```no-highlight
GET /api/dcim/devices/1/napalm/?method=get_ntp_servers&method=get_ntp_peers
{
@@ -51,14 +63,11 @@ GET /api/dcim/devices/1/napalm/?method=get_ntp_servers&method=get_ntp_peers
## Optional Arguments
The behavior of NAPALM drivers can be adjusted according to the [optional arguments](https://napalm.readthedocs.io/en/latest/support/index.html#optional-arguments). NetBox exposes those arguments using headers prefixed with `X-NAPALM-`.
For instance, the SSH port is changed to 2222 in this API call:
The behavior of NAPALM drivers can be adjusted according to the [optional arguments](https://napalm.readthedocs.io/en/latest/support/index.html#optional-arguments). NetBox exposes those arguments using headers prefixed with `X-NAPALM-`. For example, the SSH port is changed to 2222 in this API call:
@@ -23,12 +23,7 @@ For the exhaustive list of exposed metrics, visit the `/metrics` endpoint on you
## Multi Processing Notes
When deploying NetBox in a multiprocess mannor--such as using Gunicorn as recomented in the installation docs--the Prometheus client library requires the use of a shared directory
to collect metrics from all the worker processes. This can be any arbitrary directory to which the processes have read/write access. This directory is then made available by use of the
`prometheus_multiproc_dir` environment variable.
When deploying NetBox in a multiprocess manner (e.g. running multiple Gunicorn workers) the Prometheus client library requires the use of a shared directory to collect metrics from all worker processes. To configure this, first create or designate a local directory to which the worker processes have read and write access, and then configure your WSGI service (e.g. Gunicorn) to define this path as the `prometheus_multiproc_dir` environment variable.
This can be setup by first creating a shared directory and then adding this line (with the appropriate directory) to the `[program:netbox]` section of the supervisor config file.
If having accurate long-term metrics in a multiprocess environment is crucial to your deployment, it's recommended you use the `uwsgi` library instead of `gunicorn`. The issue lies in the way `gunicorn` tracks worker processes (vs `uwsgi`) which helps manage the metrics files created by the above configurations. If you're using NetBox with gunicorn in a containerized environment following the one-process-per-container methodology, then you will likely not need to change to `uwsgi`. More details can be found in [issue #3779](https://github.com/netbox-community/netbox/issues/3779#issuecomment-590547562).
A webhook is a mechanism for conveying to some external system a change that took place in NetBox. For example, you may want to notify a monitoring system whenever a device status is changed in NetBox. This can be done by creating a webhook for the device model in NetBox. When NetBox detects a change to a device, an HTTP request containing the details of the change and who made it be sent to the specified receiver. Webhooks are configured in the admin UI under Extras > Webhooks.
## Conditional Webhooks
## Configuration
A webhook may include a set of conditional logic expressed in JSON used to control whether a webhook triggers for a specific object. For example, you may wish to trigger a webhook for devices only when the `status` field of an object is "active":
* **Name** - A unique name for the webhook. The name is not included with outbound messages.
* **Object type(s)** - The type or types of NetBox object that will trigger the webhook.
* **Enabled** - If unchecked, the webhook will be inactive.
* **Events** - A webhook may trigger on any combination of create, update, and delete events. At least one event type must be selected.
* **HTTP method** - The type of HTTP request to send. Options include GET, POST, PUT, PATCH, and DELETE.
* **URL** - The fuly-qualified URL of the request to be sent. This may specify a destination port number if needed.
* **HTTP content type** - The value of the request's `Content-Type` header. (Defaults to `application/json`)
* **Additional headers** - Any additional headers to include with the request (optional). Add one header per line in the format `Name: Value`. Jinja2 templating is supported for this field (see below).
* **Body template** - The content of the request being sent (optional). Jinja2 templating is supported for this field (see below). If blank, NetBox will populate the request body with a raw dump of the webhook context. (If the HTTP cotent type is set to `application/json`, this will be formatted as a JSON object.)
* **Secret** - A secret string used to prove authenticity of the request (optional). This will append a `X-Hook-Signature` header to the request, consisting of a HMAC (SHA-512) hex digest of the request body using the secret as the key.
* **SSL verification** - Uncheck this option to disable validation of the receiver's SSL certificate. (Disable with caution!)
* **CA file path** - The file path to a particular certificate authority (CA) file to use when validating the receiver's SSL certificate (optional).
## Jinja2 Template Support
[Jinja2 templating](https://jinja.palletsprojects.com/) is supported for the `additional_headers` and `body_template` fields. This enables the user to convey change data in the request headers as well as to craft a customized request body. Request content can be crafted to enable the direct interaction with external systems by ensuring the outgoing message is in a format the receiver expects and understands.
For example, you might create a NetBox webhook to [trigger a Slack message](https://api.slack.com/messaging/webhooks) any time an IP address is created. You can accomplish this using the following configuration:
* Object type: IPAM > IP address
* HTTP method: POST
* URL: <Slack incoming webhook URL>
* HTTP content type: `application/json`
* Body template: `{"text": "IP address {{ data['address'] }} was created by {{ username }}!"}`
### Available Context
The following data is available as context for Jinja2 templates:
*`event` - The type of event which triggered the webhook: created, updated, or deleted.
*`model` - The NetBox model which triggered the change.
*`timestamp` - The time at which the event occurred (in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format).
*`username` - The name of the user account associated with the change.
*`request_id` - The unique request ID. This may be used to correlate multiple changes associated with a single request.
*`data` - A serialized representation of the object _after_ the change was made. This is typically equivalent to the model's representation in NetBox's REST API.
### Default Request Body
If no body template is specified, the request body will be populated with a JSON object containing the context data. For example, a newly created site might appear as follows:
For more detail, see the reference documentation for NetBox's [conditional logic](../reference/conditions.md).
## Webhook Processing
When a change is detected, any resulting webhooks are placed into a Redis queue for processing. This allows the user's request to complete without needing to wait for the outgoing webhook(s) to be processed. The webhooks are then extracted from the queue by the `rqworker` process and HTTP requests are sent to their respective destinations. The current webhook queue and any failed webhooks can be inspected in the admin UI under Django RQ > Queues.
When a change is detected, any resulting webhooks are placed into a Redis queue for processing. This allows the user's request to complete without needing to wait for the outgoing webhook(s) to be processed. The webhooks are then extracted from the queue by the `rqworker` process and HTTP requests are sent to their respective destinations. The current webhook queue and any failed webhooks can be inspected in the admin UI under System > Background Tasks.
A request is considered successful if the response has a 2XX status code; otherwise, the request is marked as having failed. Failed requests may be retried manually via the admin UI.
## Troubleshooting
To assist with verifying that the content of outgoing webhooks is rendered correctly, NetBox provides a simple HTTP listener that can be run locally to receive and display webhook requests. First, modify the target URL of the desired webhook to `http://localhost:9000/`. This will instruct NetBox to send the request to the local server on TCP port 9000. Then, start the webhook receiver service from the NetBox root directory:
```no-highlight
$ python netbox/manage.py webhook_receiver
Listening on port http://localhost:9000. Stop with CONTROL-C.
```
You can test the receiver itself by sending any HTTP request to it. For example:
```no-highlight
$ curl -X POST http://localhost:9000 --data '{"foo": "bar"}'
```
The server will print output similar to the following:
Note that `webhook_receiver` does not actually _do_ anything with the information received: It merely prints the request headers and body for inspection.
Now, when the NetBox webhook is triggered and processed, you should see its headers and content appear in the terminal where the webhook receiver is listening. If you don't, check that the `rqworker` process is running and that webhook events are being placed into the queue (visible under the NetBox admin UI).
This guide explains how to configure single sign-on (SSO) support for NetBox using [Microsoft Azure Active Directory (AD)](https://azure.microsoft.com/en-us/services/active-directory/) as an authentication backend.
## Azure AD Configuration
### 1. Create a test user (optional)
Create a new user in AD to be used for testing. You can skip this step if you already have a suitable account created.
### 2. Create an app registration
Under the Azure Active Directory dashboard, navigate to **Add > App registration**.

Enter a name for the registration (e.g. "NetBox") and ensure that the "single tenant" option is selected.
Under "Redirect URI", select "Web" for the platform and enter the path to your NetBox installation, ending with `/oauth/complete/azuread-oauth2/`. Note that this URI **must** begin with `https://` unless you are referencing localhost (for development purposes).
NetBox also supports multitenant authentication via Azure AD, however it requires a different backend and an additional configuration parameter. Please see the [`python-social-auth` documentation](https://python-social-auth.readthedocs.io/en/latest/backends/azuread.html#tenant-support) for details concerning multitenant authentication.
### 3. Create a secret
When viewing the newly-created app registration, click the "Add a certificate or secret" link under "Client credentials". Under the "Client secrets" tab, click the "New client secret" button.

You can optionally specify a description and select a lifetime for the secret.
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 Azure AD. Click that link.

You should be redirected to Microsoft'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.

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 within the NetBox admin UI.
## 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.
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.

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:
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.
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.
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.
Local user accounts and groups can be created in NetBox under the "Authentication and Authorization" section of the administrative user interface. This interface 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 within the admin UI.
## Remote Authentication
NetBox may be configured to provide user authenticate via a remote backend in addition to local authentication. This is done by setting the `REMOTE_AUTH_BACKEND` configuration parameter to a suitable backend class. NetBox provides several options for remote authentication.
NetBox includes an authentication backend which supports LDAP. See the [LDAP installation docs](../../installation/6-ldap.md) for more detail about this backend.
Another option for remote authentication in NetBox is to enable HTTP header-based user assignment. The front end HTTP server (e.g. nginx or Apache) performs client authentication as a process external to NetBox, and passes information about the authenticated user via HTTP headers. By default, the user is assigned via the `REMOTE_USER` header, but this can be customized via the `REMOTE_AUTH_HEADER` configuration parameter.
NetBox supports single sign-on authentication via the [python-social-auth](https://github.com/python-social-auth) library. To enable SSO, specify the path to the desired authentication backend within the `social_core` Python package. Please see the complete list of [supported authentication backends](https://github.com/python-social-auth/social-core/tree/master/social_core/backends) for the available options.
Most remote authentication backends require some additional configuration through settings prefixed with `SOCIAL_AUTH_`. These will be automatically imported from NetBox's `configuration.py` file. Additionally, the [authentication pipeline](https://python-social-auth.readthedocs.io/en/latest/pipeline.html) can be customized via the `SOCIAL_AUTH_PIPELINE` parameter.
NetBox v3.2.3 and later support native integration with [Sentry](https://sentry.io/) for automatic error reporting. To enable this functionality, simply set `SENTRY_ENABLED` to True in `configuration.py`. Errors will be sent to a Sentry ingestor maintained by the NetBox team for analysis.
```python
SENTRY_ENABLED=True
```
### Using a Custom DSN
If you prefer instead to use your own Sentry ingestor, you'll need to first create a new project under your Sentry account to represent your NetBox deployment and obtain its corresponding data source name (DSN). This looks like a URL similar to the example below:
```
https://examplePublicKey@o0.ingest.sentry.io/0
```
Once you have obtained a DSN, configure Sentry in NetBox's `configuration.py` file with the following parameters:
You can optionally attach one or more arbitrary tags to the outgoing error reports if desired by setting the `SENTRY_TAGS` parameter:
```python
SENTRY_TAGS={
"custom.foo":"123",
"custom.bar":"abc",
}
```
!!! warning "Reserved tag prefixes"
Avoid using any tag names which begin with `netbox.`, as this prefix is reserved by the NetBox application.
### Testing
Once the configuration has been saved, restart the NetBox service.
To test Sentry operation, try generating a 404 (page not found) error by navigating to an invalid URL, such as `https://netbox/404-error-testing`. (Be sure that debug mode has been disabled.) After receiving a 404 response from the NetBox server, you should see the issue appear shortly in Sentry.
NetBox includes a `housekeeping` management command that should be run nightly. This command handles:
* Clearing expired authentication sessions from the database
* Deleting changelog records older than the configured [retention time](../configuration/dynamic-settings.md#changelog_retention)
* Deleting job result records older than the configured [retention time](../configuration/dynamic-settings.md#jobresult_retention)
This command can be invoked directly, or by using the shell script provided at `/opt/netbox/contrib/netbox-housekeeping.sh`. This script can be linked from your cron scheduler's daily jobs directory (e.g. `/etc/cron.daily`) or referenced directly within the cron configuration file.
On Debian-based systems, be sure to omit the `.sh` file extension when linking to the script from within a cron directory. Otherwise, the task may not run.
The `housekeeping` command can also be run manually at any time: Running the command outside scheduled execution times will not interfere with its operation.
NetBox includes a Python shell within which objects can be directly queried, created, modified, and deleted. To enter the shell, run the following command:
NetBox includes a Python management shell within which objects can be directly queried, created, modified, and deleted. To enter the shell, run the following command:
```
./manage.py nbshell
```
This will launch a customized version of [the built-in Django shell](https://docs.djangoproject.com/en/stable/ref/django-admin/#shell) with all relevant NetBox models pre-loaded. (If desired, the stock Django shell is also available by executing `./manage.py shell`.)
This will launch a lightly customized version of [the built-in Django shell](https://docs.djangoproject.com/en/stable/ref/django-admin/#shell) with all relevant NetBox models pre-loaded. (If desired, the stock Django shell is also available by executing `./manage.py shell`.)
```
$ ./manage.py nbshell
### NetBox interactive shell (jstretch-laptop)
### Python 3.5.2 | Django 2.0.8 | NetBox 2.4.3
### NetBox interactive shell (localhost)
### Python 3.7.10 | Django 3.2.5 | NetBox 3.0
### lsmodels() will show available models. Use help(<model>) for more info.
```
@@ -28,13 +28,17 @@ DCIM:
...
```
!!! warning
The NetBox shell affords direct access to NetBox data and function with very little validation in place. As such, it is crucial to ensure that only authorized, knowledgeable users are ever granted access to it. Never perform any action in the management shell without having a full backup in place.
## Querying Objects
Objects are retrieved by forming a [Django queryset](https://docs.djangoproject.com/en/stable/topics/db/queries/#retrieving-objects). The base queryset for an object takes the form `<model>.objects.all()`, which will return a (truncated) list of all objects of that type.
Objects are retrieved from the database using a [Django queryset](https://docs.djangoproject.com/en/stable/topics/db/queries/#retrieving-objects). The base queryset for an object takes the form `<model>.objects.all()`, which will return a (truncated) list of all objects of that type.
<Device: TestDevice4>, <Device: TestDevice5>, '...(remaining elements truncated)...']>
```
Use a `for` loop to cycle through all objects in the list:
@@ -43,11 +47,11 @@ Use a `for` loop to cycle through all objects in the list:
>>> for device in Device.objects.all():
... print(device.name, device.device_type)
...
(u'TestDevice1', <DeviceType: PacketThingy 9000>)
(u'TestDevice2', <DeviceType: PacketThingy 9000>)
(u'TestDevice3', <DeviceType: PacketThingy 9000>)
(u'TestDevice4', <DeviceType: PacketThingy 9000>)
(u'TestDevice5', <DeviceType: PacketThingy 9000>)
('TestDevice1', <DeviceType: PacketThingy 9000>)
('TestDevice2', <DeviceType: PacketThingy 9000>)
('TestDevice3', <DeviceType: PacketThingy 9000>)
('TestDevice4', <DeviceType: PacketThingy 9000>)
('TestDevice5', <DeviceType: PacketThingy 9000>)
...
```
@@ -67,52 +71,53 @@ To retrieve a particular object (typically by its primary key or other unique fi
### Filtering Querysets
In most cases, you want to retrieve only a specific subset of objects. To filter a queryset, replace `all()` with `filter()` and pass one or more keyword arguments. For example:
In most cases, you will want to retrieve only a specific subset of objects. To filter a queryset, replace `all()` with `filter()` and pass one or more keyword arguments. For example:
Relationships with other models can be traversed by concatenating field names with a double-underscore. For example, the following will return all devices assigned to the tenant named "Pied Piper."
Relationships with other models can be traversed by concatenating attribute names with a double-underscore. For example, the following will return all devices assigned to the tenant named "Pied Piper."
While the above query is functional, it is very inefficient. There are ways to optimize such requests, however they are out of the scope of this document. For more information, see the [Django queryset method reference](https://docs.djangoproject.com/en/stable/ref/models/querysets/) documentation.
While the above query is functional, it's not very efficient. There are ways to optimize such requests, however they are out of scope for this document. For more information, see the [Django queryset method reference](https://docs.djangoproject.com/en/stable/ref/models/querysets/) documentation.
Reverse relationships can be traversed as well. For example, the following will find all devices with an interface named "em0":
```
>>> Device.objects.filter(interfaces__name='em0')
>>> Device.objects.filter(interfaces__name="em0")
```
Character fields can be filtered against partial matches using the `contains` or `icontains` field lookup (the later of which is case-insensitive).
The examples above are intended only to provide a cursory introduction to queryset filtering. For an exhaustive list of the available filters, please consult the [Django queryset API docs](https://docs.djangoproject.com/en/stable/ref/models/querysets/).
The examples above are intended only to provide a cursory introduction to queryset filtering. For an exhaustive list of the available filters, please consult the [Django queryset API documentation](https://docs.djangoproject.com/en/stable/ref/models/querysets/).
## Creating and Updating Objects
New objects can be created by instantiating the desired model, defining values for all required attributes, and calling `save()` on the instance.
New objects can be created by instantiating the desired model, defining values for all required attributes, and calling `save()` on the instance. For example, we can create a new VLAN by specifying its numeric ID, name, and assigned site:
```
>>> lab1 = Site.objects.get(pk=7)
@@ -151,22 +156,22 @@ New objects can be created by instantiating the desired model, defining values f
>>> myvlan.save()
```
Alternatively, the above can be performed as a single operation:
Alternatively, the above can be performed as a single operation. (Note, however, that `save()` does _not_ return the new instance for reuse.)
To delete multiple objects at once, call `delete()` on a filtered queryset. It's a good idea to always sanity-check the count of selected objects _before_ deleting them.
@@ -189,8 +194,10 @@ To delete multiple objects at once, call `delete()` on a filtered queryset. It's
Deletions are immediate and irreversible. Always think very carefully before calling `delete()` on an instance or queryset.
Deletions are immediate and irreversible. Always consider the impact of deleting objects carefully before calling `delete()` on an instance or queryset.
NetBox v2.9 introduced a new object-based permissions framework, which replaces Django's built-in permissions model. Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type. For example, it is possible to grant a user permission to view only sites within a particular region, or to modify only VLANs with a numeric ID within a certain range.
{!models/users/objectpermission.md!}
### Example Constraint Definitions
| Constraints | Description |
| ----------- | ----------- |
| `{"status": "active"}` | Status is active |
| `{"status__in": ["planned", "reserved"]}` | Status is active **OR** reserved |
| `{"status": "active", "role": "testing"}` | Status is active **AND** role is testing |
| `{"name__startswith": "Foo"}` | Name starts with "Foo" (case-sensitive) |
| `{"name__iendswith": "bar"}` | Name ends with "bar" (case-insensitive) |
| `{"vid__gte": 100, "vid__lt": 200}` | VLAN ID is greater than or equal to 100 **AND** less than 200 |
| `[{"vid__lt": 200}, {"status": "reserved"}]` | VLAN ID is less than 200 **OR** status is reserved |
## Permissions Enforcement
### Viewing Objects
Object-based permissions work by filtering the database query generated by a user's request to restrict the set of objects returned. When a request is received, NetBox first determines whether the user is authenticated and has been granted to perform the requested action. For example, if the requested URL is `/dcim/devices/`, NetBox will check for the `dcim.view_device` permission. If the user has not been assigned this permission (either directly or via a group assignment), NetBox will return a 403 (forbidden) HTTP response.
If the permission _has_ been granted, NetBox will compile any specified constraints for the model and action. For example, suppose two permissions have been assigned to the user granting view access to the device model, with the following constraints:
```json
[
{"site__name__in":["NYC1","NYC2"]},
{"status":"offline","tenant__isnull":true}
]
```
This grants the user access to view any device that is assigned to a site named NYC1 or NYC2, **or** which has a status of "offline" and has no tenant assigned. These constraints are equivalent to the following ORM query:
```no-highlight
Site.objects.filter(
Q(site__name__in=['NYC1', 'NYC2']),
Q(status='active', tenant__isnull=True)
)
```
### Creating and Modifying Objects
The same sort of logic is in play when a user attempts to create or modify an object in NetBox, with a twist. Once validation has completed, NetBox starts an atomic database transaction to facilitate the change, and the object is created or saved normally. Next, still within the transaction, NetBox issues a second query to retrieve the newly created/updated object, filtering the restricted queryset with the object's primary key. If this query fails to return the object, NetBox knows that the new revision does not match the constraints imposed by the permission. The transaction is then rolled back, leaving the database in its original state prior to the change, and the user is informed of the violation.
NetBox uses [PostgreSQL](https://www.postgresql.org/) for its database, so general PostgreSQL best practices will apply to NetBox. You can dump and restore the database using the `pg_dump` and `psql` utilities, respectively.
NetBox employs a [PostgreSQL](https://www.postgresql.org/) database, so general PostgreSQL best practices apply here. The database can be written to a file and restored using the `pg_dump` and `psql` utilities, respectively.
!!! note
The examples below assume that your database is named `netbox`.
@@ -12,19 +12,24 @@ NetBox uses [PostgreSQL](https://www.postgresql.org/) for its database, so gener
Use the `pg_dump` utility to export the entire database to a file:
You may need to change the username, host, and/or database in the command above to match your installation.
When replicating a production database for development purposes, you may find it convenient to exclude changelog data, which can easily account for the bulk of a database's size. To do this, exclude the `extras_objectchange` table data from the export. The table will still be included in the output file, but will not be populated with any data.
NetBox stored uploaded files (such as image attachments) in its media directory. To fully replicate an instance of NetBox, you'll need to copy both the database and the media files.
By default, NetBox stores uploaded files (such as image attachments) in its media directory. To fully replicate an instance of NetBox, you'll need to copy both the database and the media files.
!!! note
These operations are not necessary if your installation is utilizing a [remote storage backend](../../configuration/optional-settings/#storage_backend).
The NetBox API employs token-based authentication. For convenience, cookie authentication can also be used when navigating the browsable API.
## Tokens
A token is a unique identifier that identifies a user to the API. Each user in NetBox may have one or more tokens which he or she can use to authenticate to the API. To create a token, navigate to the API tokens page at `/user/api-tokens/`.
!!! note
The creation and modification of API tokens can be restricted per user by an administrator. If you don't see an option to create an API token, ask an administrator to grant you access.
Each token contains a 160-bit key represented as 40 hexadecimal characters. When creating a token, you'll typically leave the key field blank so that a random key will be automatically generated. However, NetBox allows you to specify a key in case you need to restore a previously deleted token to operation.
By default, a token can be used for all operations available via the API. Deselecting the "write enabled" option will restrict API requests made with the token to read operations (e.g. GET) only.
Additionally, a token can be set to expire at a specific time. This can be useful if an external client needs to be granted temporary access to NetBox.
## Authenticating to the API
By default, read operations will be available without authentication. In this case, a token may be included in the request, but is not necessary.
However, if the [`LOGIN_REQUIRED`](../../configuration/optional-settings/#login_required) configuration setting has been set to `True`, all requests must be authenticated.
Additionally, the browsable interface to the API (which can be seen by navigating to the API root `/api/` in a web browser) will attempt to authenticate requests using the same cookie that the normal NetBox front end uses. Thus, if you have logged into NetBox, you will be logged into the browsable API as well.
Send a `POST` request to the site list endpoint with token authentication and JSON-formatted data. Only mandatory fields are required. This example includes one non required field, "region."
```
$ curl -X POST -H "Authorization: Token d2f763479f703d80de0ec15254237bc651f9cdc0" -H "Content-Type: application/json" -H "Accept: application/json; indent=4" http://localhost:8000/api/dcim/sites/ --data '{"name": "My New Site", "slug": "my-new-site", "region": 5}'
{
"id": 16,
"name": "My New Site",
"slug": "my-new-site",
"region": 5,
"tenant": null,
"facility": "",
"asn": null,
"physical_address": "",
"shipping_address": "",
"contact_name": "",
"contact_phone": "",
"contact_email": "",
"comments": ""
}
```
Note that in this example we are creating a site bound to a region with the ID of 5. For write API actions (`POST`, `PUT`, and `PATCH`) the integer ID value is used for `ForeignKey` (related model) relationships, instead of the nested representation that is used in the `GET` (list) action.
## Modify an existing site
Make an authenticated `PUT` request to the site detail endpoint. As with a create (`POST`) request, all mandatory fields must be included.
Make an authenticated `PATCH` request to the device endpoint. With `PATCH`, unlike `POST` and `PUT`, we only specify the field that is being changed. In this example, we add a serial number to a device.
REST stands for [representational state transfer](https://en.wikipedia.org/wiki/Representational_state_transfer). It's a particular type of API which employs HTTP to create, retrieve, update, and delete objects from a database. (This set of operations is commonly referred to as CRUD.) Each type of operation is associated with a particular HTTP verb:
*`GET`: Retrieve an object or list of objects
*`POST`: Create an object
*`PUT` / `PATCH`: Modify an existing object. `PUT` requires all mandatory fields to be specified, while `PATCH` only expects the field that is being modified to be specified.
*`DELETE`: Delete an existing object
The NetBox API represents all objects in [JavaScript Object Notation (JSON)](http://www.json.org/). This makes it very easy to interact with NetBox data on the command line with common tools. For example, we can request an IP address from NetBox and output the JSON using `curl` and `jq`. (Piping the output through `jq` isn't strictly required but makes it much easier to read.)
Each attribute of the NetBox object is expressed as a field in the dictionary. Fields may include their own nested objects, as in the case of the `status` field above. Every object includes a primary key named `id` which uniquely identifies it in the database.
## Interactive Documentation
Comprehensive, interactive documentation of all API endpoints is available on a running NetBox instance at `/api/docs/`. This interface provides a convenient sandbox for researching and experimenting with NetBox's various API endpoints and different request types.
## URL Hierarchy
NetBox's entire API is housed under the API root at `https://<hostname>/api/`. The URL structure is divided at the root level by application: circuits, DCIM, extras, IPAM, secrets, and tenancy. Within each application, each model has its own path. For example, the provider and circuit objects are located under the "circuits" application:
* /api/circuits/providers/
* /api/circuits/circuits/
Likewise, the site, rack, and device objects are located under the "DCIM" application:
* /api/dcim/sites/
* /api/dcim/racks/
* /api/dcim/devices/
The full hierarchy of available endpoints can be viewed by navigating to the API root in a web browser.
Each model generally has two views associated with it: a list view and a detail view. The list view is used to request a list of multiple objects or to create a new object. The detail view is used to retrieve, update, or delete an existing object. All objects are referenced by their numeric primary key (`id`).
* /api/dcim/devices/ - List devices or create a new device
* /api/dcim/devices/123/ - Retrieve, update, or delete the device with ID 123
Lists of objects can be filtered using a set of query parameters. For example, to find all interfaces belonging to the device with ID 123:
```
GET /api/dcim/interfaces/?device_id=123
```
See [filtering](filtering.md) for more details.
## Serialization
The NetBox API employs three types of serializers to represent model data:
* Base serializer
* Nested serializer
* Writable serializer
The base serializer is used to represent the default view of a model. This includes all database table fields which comprise the model, and may include additional metadata. A base serializer includes relationships to parent objects, but **does not** include child objects. For example, the `VLANSerializer` includes a nested representation its parent VLANGroup (if any), but does not include any assigned Prefixes.
Related objects (e.g. `ForeignKey` fields) are represented using a nested serializer. A nested serializer provides a minimal representation of an object, including only its URL and enough information to display the object to a user. When performing write API actions (`POST`, `PUT`, and `PATCH`), related objects may be specified by either numeric ID (primary key), or by a set of attributes sufficiently unique to return the desired object.
For example, when creating a new device, its rack can be specified by NetBox ID (PK):
```
{
"name": "MyNewDevice",
"rack": 123,
...
}
```
Or by a set of nested attributes used to identify the rack:
```
{
"name": "MyNewDevice",
"rack": {
"site": {
"name": "Equinix DC6"
},
"name": "R204"
},
...
}
```
Note that if the provided parameters do not return exactly one object, a validation error is raised.
### Brief Format
Most API endpoints support an optional "brief" format, which returns only a minimal representation of each object in the response. This is useful when you need only a list of the objects themselves without any related data, such as when populating a drop-down list in a form.
For example, the default (complete) format of an IP address looks like this:
The brief format is much more terse, but includes a link to the object's full representation:
```
GET /api/ipam/prefixes/13980/?brief=1
{
"id": 13980,
"url": "https://netbox/api/ipam/prefixes/13980/",
"family": 4,
"prefix": "192.0.2.0/24"
}
```
The brief format is supported for both lists and individual objects.
### Static Choice Fields
Some model fields, such as the `status` field in the above example, utilize static integers corresponding to static choices. The available choices can be retrieved from the read-only `_choices` endpoint within each app. A specific `model:field` tuple may optionally be specified in the URL.
Each choice includes a human-friendly label and its corresponding numeric value. For example, `GET /api/ipam/_choices/prefix:status/` will return:
```
[
{
"value": 0,
"label": "Container"
},
{
"value": 1,
"label": "Active"
},
{
"value": 2,
"label": "Reserved"
},
{
"value": 3,
"label": "Deprecated"
}
]
```
Thus, to set a prefix's status to "Reserved," it would be assigned the integer `2`.
A request for `GET /api/ipam/_choices/` will return choices for _all_ fields belonging to models within the IPAM app.
## Pagination
API responses which contain a list of objects (for example, a request to `/api/dcim/devices/`) will be paginated to avoid unnecessary overhead. The root JSON object will contain the following attributes:
*`count`: The total count of all objects matching the query
*`next`: A hyperlink to the next page of results (if applicable)
*`previous`: A hyperlink to the previous page of results (if applicable)
The default page size derives from the [`PAGINATE_COUNT`](../../configuration/optional-settings/#paginate_count) configuration setting, which defaults to 50. However, this can be overridden per request by specifying the desired `offset` and `limit` query parameters. For example, if you wish to retrieve a hundred devices at a time, you would make a request for:
```
http://localhost:8000/api/dcim/devices/?limit=100
```
The response will return devices 1 through 100. The URL provided in the `next` attribute of the response will return devices 101 through 200:
The maximum number of objects that can be returned is limited by the [`MAX_PAGE_SIZE`](../../configuration/optional-settings/#max_page_size) setting, which is 1000 by default. Setting this to `0` or `None` will remove the maximum limit. An API consumer can then pass `?limit=0` to retrieve _all_ matching objects with a single request.
!!! warning
Disabling the page size limit introduces a potential for very resource-intensive requests, since one API request can effectively retrieve an entire table from the database.
## Filtering
A list of objects retrieved via the API can be filtered by passing one or more query parameters. The same parameters used by the web UI work for the API as well. For example, to return only prefixes with a status of "Active" (`1`):
```
GET /api/ipam/prefixes/?status=1
```
The choices available for fixed choice fields such as `status` are exposed in the API under a special `_choices` endpoint for each NetBox app. For example, the available choices for `Prefix.status` are listed at `/api/ipam/_choices/` under the key `prefix:status`:
```
"prefix:status": [
{
"label": "Container",
"value": 0
},
{
"label": "Active",
"value": 1
},
{
"label": "Reserved",
"value": 2
},
{
"label": "Deprecated",
"value": 3
}
],
```
For most fields, when a filter is passed multiple times, objects matching _any_ of the provided values will be returned. For example, `GET /api/dcim/sites/?name=Foo&name=Bar` will return all sites named "Foo" _or_ "Bar". The exception to this rule is ManyToManyFields which may have multiple values assigned. Tags are the most common example of a ManyToManyField. For example, `GET /api/dcim/sites/?tag=foo&tag=bar` will return only sites tagged with both "foo" _and_ "bar".
### Custom Fields
To filter on a custom field, prepend `cf_` to the field name. For example, the following query will return only sites where a custom field named `foo` is equal to 123:
```
GET /api/dcim/sites/?cf_foo=123
```
!!! note
Full versus partial matching when filtering is configurable per custom field. Filtering can be toggled (or disabled) for a custom field in the admin UI.
As with most other objects, the NetBox API can be used to create, modify, and delete secrets. However, additional steps are needed to encrypt or decrypt secret data.
## Generating a Session Key
In order to encrypt or decrypt secret data, a session key must be attached to the API request. To generate a session key, send an authenticated request to the `/api/secrets/get-session-key/` endpoint with the private RSA key which matches your [UserKey](../../core-functionality/secrets/#user-keys). The private key must be POSTed with the name `private_key`.
```
$ curl -X POST http://localhost:8000/api/secrets/get-session-key/ \
To read the private key from a file, use the convention above. Alternatively, the private key can be read from an environment variable using `--data-urlencode "private_key=$PRIVATE_KEY"`.
The request uses your private key to unlock your stored copy of the master key and generate a session key which can be attached in the `X-Session-Key` header of future API requests.
## Retrieving Secrets
A session key is not needed to retrieve unencrypted secrets: The secret is returned like any normal object with its `plaintext` field set to null.
These configuration parameters are primarily controlled via NetBox's admin interface (under Admin > Extras > Configuration Revisions). These setting may also be overridden in `configuration.py`; this will prevent them from being modified via the UI.
A list of permitted URL schemes referenced when rendering links within NetBox. Note that only the schemes specified in this list will be accepted: If adding your own, be sure to replicate all of the default values as well (excluding those schemes which are not desirable).
---
## BANNER_TOP
## BANNER_BOTTOM
Setting these variables will display custom content in a banner at the top and/or bottom of the page, respectively. HTML is allowed. To replicate the content of the top banner in the bottom banner, set:
```python
BANNER_TOP='Your banner text'
BANNER_BOTTOM=BANNER_TOP
```
---
## BANNER_LOGIN
This defines custom content to be displayed on the login page above the login form. HTML is allowed.
---
## CHANGELOG_RETENTION
Default: 90
The number of days to retain logged changes (object creations, updates, and deletions). Set this to `0` to retain
changes in the database indefinitely.
!!! warning
If enabling indefinite changelog retention, it is recommended to periodically delete old entries. Otherwise, the database may eventually exceed capacity.
---
## CUSTOM_VALIDATORS
This is a mapping of models to [custom validators](../customization/custom-validation.md) that have been defined locally to enforce custom validation logic. An example is provided below:
```python
CUSTOM_VALIDATORS={
"dcim.site":[
{
"name":{
"min_length":5,
"max_length":30
}
},
"my_plugin.validators.Validator1"
],
"dim.device":[
"my_plugin.validators.Validator1"
]
}
```
---
## DEFAULT_USER_PREFERENCES
This is a dictionary defining the default preferences to be set for newly-created user accounts. For example, to set the default page size for all users to 100, define the following:
```python
DEFAULT_USER_PREFERENCES={
"pagination":{
"per_page":100
}
}
```
For a complete list of available preferences, log into NetBox and navigate to `/user/preferences/`. A period in a preference name indicates a level of nesting in the JSON data. The example above maps to `pagination.per_page`.
---
## ENFORCE_GLOBAL_UNIQUE
Default: False
By default, NetBox will permit users to create duplicate prefixes and IP addresses in the global table (that is, those which are not assigned to any VRF). This behavior can be disabled by setting `ENFORCE_GLOBAL_UNIQUE` to True.
---
## GRAPHQL_ENABLED
Default: True
Setting this to False will disable the GraphQL API.
---
## JOBRESULT_RETENTION
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.
!!! warning
If enabling indefinite job results retention, it is recommended to periodically delete old entries. Otherwise, the database may eventually exceed capacity.
---
## MAINTENANCE_MODE
Default: False
Setting this to True will display a "maintenance mode" banner at the top of every page. Additionally, NetBox will no longer update a user's "last active" time upon login. This is to allow new logins when the database is in a read-only state. Recording of login times will resume when maintenance mode is disabled.
This specifies the URL to use when presenting a map of a physical location by street address or GPS coordinates. The URL must accept either a free-form street address or a comma-separated pair of numeric coordinates appended to it.
---
## MAX_PAGE_SIZE
Default: 1000
A web user or API consumer can request an arbitrary number of objects by appending the "limit" parameter to the URL (e.g. `?limit=1000`). This parameter defines the maximum acceptable limit. Setting this to `0` or `None` will allow a client to retrieve _all_ matching objects at once with no limit by specifying `?limit=0`.
---
## NAPALM_USERNAME
## NAPALM_PASSWORD
NetBox will use these credentials when authenticating to remote devices via the supported [NAPALM integration](../additional-features/napalm.md), if installed. Both parameters are optional.
!!! note
If SSH public key authentication has been set up on the remote device(s) for the system account under which NetBox runs, these parameters are not needed.
---
## NAPALM_ARGS
A dictionary of optional arguments to pass to NAPALM when instantiating a network driver. See the NAPALM documentation for a [complete list of optional arguments](https://napalm.readthedocs.io/en/latest/support/#optional-arguments). An example:
```python
NAPALM_ARGS={
'api_key':'472071a93b60a1bd1fafb401d9f8ef41',
'port':2222,
}
```
Some platforms (e.g. Cisco IOS) require an argument named `secret` to be passed in addition to the normal password. If desired, you can use the configured `NAPALM_PASSWORD` as the value for this argument:
```python
NAPALM_USERNAME='username'
NAPALM_PASSWORD='MySecretPassword'
NAPALM_ARGS={
'secret':NAPALM_PASSWORD,
# Include any additional args here
}
```
---
## NAPALM_TIMEOUT
Default: 30 seconds
The amount of time (in seconds) to wait for NAPALM to connect to a device.
---
## PAGINATE_COUNT
Default: 50
The default maximum number of objects to display per page within each list of objects.
---
## POWERFEED_DEFAULT_AMPERAGE
Default: 15
The default value for the `amperage` field when creating new power feeds.
---
## POWERFEED_DEFAULT_MAX_UTILIZATION
Default: 80
The default value (percentage) for the `max_utilization` field when creating new power feeds.
---
## POWERFEED_DEFAULT_VOLTAGE
Default: 120
The default value for the `voltage` field when creating new power feeds.
---
## PREFER_IPV4
Default: False
When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to prefer IPv4 instead.
---
## RACK_ELEVATION_DEFAULT_UNIT_HEIGHT
Default: 22
Default height (in pixels) of a unit within a rack elevation. For best results, this should be approximately one tenth of `RACK_ELEVATION_DEFAULT_UNIT_WIDTH`.
---
## RACK_ELEVATION_DEFAULT_UNIT_WIDTH
Default: 220
Default width (in pixels) of a unit within a rack elevation.
Set to True to enable automatic error reporting via [Sentry](https://sentry.io/).
---
## SENTRY_SAMPLE_RATE
Default: 1.0 (all)
The sampling rate for errors. Must be a value between 0 (disabled) and 1.0 (report on all errors).
---
## SENTRY_TAGS
An optional dictionary of tag names and values to apply to Sentry error reports.For example:
```
SENTRY_TAGS = {
"custom.foo": "123",
"custom.bar": "abc",
}
```
!!! warning "Reserved tag prefixes"
Avoid using any tag names which begin with `netbox.`, as this prefix is reserved by the NetBox application.
---
## SENTRY_TRACES_SAMPLE_RATE
Default: 0 (disabled)
The sampling rate for transactions. Must be a value between 0 (disabled) and 1.0 (report on all transactions).
!!! warning "Consider performance implications"
A high sampling rate for transactions can induce significant performance penalties. If transaction reporting is desired, it is recommended to use a relatively low sample rate of 10% to 20% (0.1 to 0.2).
NetBox's local configuration is stored in `netbox/netbox/configuration.py`. An example configuration is provided at`netbox/netbox/configuration.example.py`. You may copy or rename the example configuration and make changes as appropriate. NetBox will not run without a configuration file.
NetBox's local configuration is stored in `$INSTALL_ROOT/netbox/netbox/configuration.py` by default. An example configuration is provided as`configuration_example.py`. You may copy or rename the example configuration and make changes as appropriate. NetBox will not run without a configuration file. While NetBox has many configuration settings, only a few of them must be defined at the time of installation: these are defined under "required settings" below.
While NetBox has many configuration settings, only a few of them must be defined at the time of installation.
!!! info "Customizing the Configuration Module"
A custom configuration module may be specified by setting the `NETBOX_CONFIGURATION` environment variable. This must be a dotted path to the desired Python module. For example, a file named `my_config.py` in the same directory as `settings.py` would be referenced as `netbox.my_config`.
For the sake of brevity, the NetBox documentation refers to the configuration file simply as `configuration.py`.
Some configuration parameters may alternatively be defined either in `configuration.py` or within the administrative section of the user interface. Settings which are "hard-coded" in the configuration file take precedence over those defined via the UI.
NetBox will email details about critical errors to the administrators listed here. This should be a list of (name, email) tuples. For example:
```
```python
ADMINS=[
['Hank Hill','hhill@example.com'],
['Dale Gribble','dgribble@example.com'],
@@ -13,22 +13,20 @@ ADMINS = [
---
## BANNER_TOP
## AUTH_PASSWORD_VALIDATORS
## BANNER_BOTTOM
Setting these variables will display content in a banner at the top and/or bottom of the page, respectively. HTML is allowed. To replicate the content of the top banner in the bottom banner, set:
This parameter acts as a pass-through for configuring Django's built-in password validators for local user accounts. If configured, these will be applied whenever a user's password is updated to ensure that it meets minimum criteria such as length or complexity. An example is provided below. For more detail on the available options, please see [the Django documentation](https://docs.djangoproject.com/en/stable/topics/auth/passwords/#password-validation).
The value of this variable will be displayed on the login page above the login form. HTML is allowed.
---
@@ -36,30 +34,14 @@ The value of this variable will be displayed on the login page above the login f
Default: None
The base URL path to use when accessing NetBox. Do not include the scheme or domain name. For example, if installed at http://example.com/netbox/, set:
The base URL path to use when accessing NetBox. Do not include the scheme or domain name. For example, if installed at https://example.com/netbox/, set:
```
```python
BASE_PATH='netbox/'
```
---
## CACHE_TIMEOUT
Default: 900
The number of seconds to retain cache entries before automatically invalidating them.
---
## CHANGELOG_RETENTION
Default: 90
The number of days to retain logged changes (object creations, updates, and deletions). Set this to `0` to retain changes in the database indefinitely. (Warning: This will greatly increase database size over time.)
---
## CORS_ORIGIN_ALLOW_ALL
Default: False
@@ -72,9 +54,11 @@ If True, cross-origin resource sharing (CORS) requests will be accepted from all
## CORS_ORIGIN_REGEX_WHITELIST
These settings specify a list of origins that are authorized to make cross-site API requests. Use`CORS_ORIGIN_WHITELIST` to define a list of exact hostnames, or `CORS_ORIGIN_REGEX_WHITELIST` to define a set of regular expressions. (These settings have no effect if `CORS_ORIGIN_ALLOW_ALL` is True.) For example:
These settings specify a list of origins that are authorized to make cross-site API requests. Use
`CORS_ORIGIN_WHITELIST` to define a list of exact hostnames, or `CORS_ORIGIN_REGEX_WHITELIST` to define a set of regular
expressions. (These settings have no effect if `CORS_ORIGIN_ALLOW_ALL` is True.) For example:
```
```python
CORS_ORIGIN_WHITELIST=[
'https://example.com',
]
@@ -82,11 +66,40 @@ CORS_ORIGIN_WHITELIST = [
---
## CSRF_COOKIE_NAME
Default: `csrftoken`
The name of the cookie to use for the cross-site request forgery (CSRF) authentication token. See the [Django documentation](https://docs.djangoproject.com/en/stable/ref/settings/#csrf-cookie-name) for more detail.
---
## CSRF_TRUSTED_ORIGINS
Default: `[]`
Defines a list of trusted origins for unsafe (e.g. `POST`) requests. This is a pass-through to Django's [`CSRF_TRUSTED_ORIGINS`](https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS) setting. Note that each host listed must specify a scheme (e.g. `http://` or `https://).
```python
CSRF_TRUSTED_ORIGINS = (
'http://netbox.local',
'https://netbox.local',
)
```
---
## DEBUG
Default: False
This setting enables debugging. This should be done only during development or troubleshooting. Never enable debugging on a production system, as it can expose sensitive data to unauthenticated users.
This setting enables debugging. Debugging should be enabled only during development or troubleshooting. Note that only
clients which access NetBox from a recognized [internal IP address](#internal_ips) will see debugging tools in the user
interface.
!!! warning
Never enable debugging on a production system, as it can expose sensitive data to unauthenticated users and impose a
substantial performance penalty.
---
@@ -100,26 +113,33 @@ This parameter serves as a safeguard to prevent some potentially dangerous behav
## DOCS_ROOT
Default: `$INSTALL_DIR/docs/`
Default: `$INSTALL_ROOT/docs/`
The file path to NetBox's documentation. This is used when presenting context-sensitive documentation in the web UI. by default, this will be the `docs/` directory within the root NetBox installation path. (Set this to `None` to disable the embedded documentation.)
The filesystem path to NetBox's documentation. This is used when presenting context-sensitive documentation in the web UI. By default, this will be the `docs/` directory within the root NetBox installation path. (Set this to `None` to disable the embedded documentation.)
---
## EMAIL
In order to send email, NetBox needs an email server configured. The following items can be defined within the `EMAIL` setting:
In order to send email, NetBox needs an email server configured. The following items can be defined within the `EMAIL` configuration parameter:
*SERVER - Hostname or IP address of the email server (use `localhost` if running locally)
*PORT - TCP port to use for the connection (default: 25)
*USERNAME - Username with which to authenticate
*PASSSWORD - Password with which to authenticate
* TIMEOUT - Amount of time to wait for a connection (seconds)
* FROM_EMAIL - Sender address for emails sent by NetBox
* `SERVER` - Hostname or IP address of the email server (use `localhost` if running locally)
* `PORT` - TCP port to use for the connection (default: `25`)
* `USERNAME` - Username with which to authenticate
* `PASSSWORD` - Password with which to authenticate
* `USE_SSL` - Use SSL when connecting to the server (default: `False`)
* `USE_TLS` - Use TLS when connecting to the server (default: `False`)
* `SSL_CERTFILE` - Path to the PEM-formatted SSL certificate file (optional)
* `SSL_KEYFILE` - Path to the PEM-formatted SSL private key file (optional)
* `TIMEOUT` - Amount of time to wait for a connection, in seconds (default: `10`)
* `FROM_EMAIL` - Sender address for emails sent by NetBox
Email is sent from NetBox only for critical events. If you would like to test the email server configuration please use the django function [send_mail()](https://docs.djangoproject.com/en/stable/topics/email/#send-mail):
!!! note
The `USE_SSL` and `USE_TLS` parameters are mutually exclusive.
```
Email is sent from NetBox only for critical events or if configured for [logging](#logging). If you would like to test the email server configuration, Django provides a convenient [send_mail()](https://docs.djangoproject.com/en/stable/topics/email/#send-mail) function accessible within the NetBox shell:
```no-highlight
# python ./manage.py nbshell
>>> from django.core.mail import send_mail
>>> send_mail(
@@ -137,11 +157,11 @@ Email is sent from NetBox only for critical events. If you would like to test th
Default: Empty list
A list of models to exempt from the enforcement of view permissions. Models listed here will be viewable by all users and by anonymous users.
A list of NetBox models to exempt from the enforcement of view permissions. Models listed here will be viewable by all users, both authenticated and anonymous.
List models in the form `<app>.<model>`. For example:
To exempt _all_ models from view permission enforcement, set the following. (Note that `EXEMPT_VIEW_PERMISSIONS` must be an iterable.)
```
```python
EXEMPT_VIEW_PERMISSIONS = ['*']
```
!!! note
Using a wildcard will not affect certain potentially sensitive models, such as user permissions. If there is a need to exempt these models, they must be specified individually.
---
## FIELD_CHOICES
Some static choice fields on models can be configured with custom values. This is done by defining `FIELD_CHOICES` as a dictionary mapping model fields to their choices. Each choice in the list must have a database value and a human-friendly label, and may optionally specify a color. (A list of available colors is provided below.)
The choices provided can either replace the stock choices provided by NetBox, or append to them. To _replace_ the available choices, specify the app, model, and field name separated by dots. For example, the site model would be referenced as `dcim.Site.status`. To _extend_ the available choices, append a plus sign to the end of this string (e.g. `dcim.Site.status+`).
For example, the following configuration would replace the default site status choices with the options Foo, Bar, and Baz:
```python
FIELD_CHOICES = {
'dcim.Site.status': (
('foo', 'Foo', 'red'),
('bar', 'Bar', 'green'),
('baz', 'Baz', 'blue'),
)
}
```
Appending a plus sign to the field identifier would instead _add_ these choices to the ones already offered:
```python
FIELD_CHOICES = {
'dcim.Site.status+': (
...
)
}
```
The following model fields support configurable choices:
* `circuits.Circuit.status`
* `dcim.Device.status`
* `dcim.PowerFeed.status`
* `dcim.Rack.status`
* `dcim.Site.status`
* `extras.JournalEntry.kind`
* `ipam.IPAddress.status`
* `ipam.IPRange.status`
* `ipam.Prefix.status`
* `ipam.VLAN.status`
* `virtualization.VirtualMachine.status`
The following colors are supported:
* `blue`
* `indigo`
* `purple`
* `pink`
* `red`
* `orange`
* `yellow`
* `green`
* `teal`
* `cyan`
* `gray`
* `black`
* `white`
---
## HTTP_PROXIES
Default: None
A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://2.python-requests.org/en/master/user/advanced/). For example:
```python
HTTP_PROXIES = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
```
---
## ENFORCE_GLOBAL_UNIQUE
## JINJA2_FILTERS
Default: False
Default: `{}`
Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table (all prefixes and IP addresses not assigned to a VRF), set `ENFORCE_GLOBAL_UNIQUE` to True.
A dictionary of custom jinja2 filters with the key being the filter name and the value being a callable. For more information see the [Jinja2 documentation](https://jinja.palletsprojects.com/en/3.1.x/api/#custom-filters). For example:
```python
def uppercase(x):
return str(x).upper()
JINJA2_FILTERS = {
'uppercase': uppercase,
}
```
---
## INTERNAL_IPS
Default: `('127.0.0.1', '::1')`
A list of IP addresses recognized as internal to the system, used to control the display of debugging output. For
example, the debugging toolbar will be viewable only when a client is accessing NetBox from one of the listed IP
addresses (and [`DEBUG`](#debug) is true).
---
## LOGGING
By default, all messages of INFO severity or higher will be logged to the console. Additionally, if `DEBUG` is False and email access has been configured, ERROR and CRITICAL messages will be emailed to the users defined in `ADMINS`.
By default, all messages of INFO severity or higher will be logged to the console. Additionally, if [`DEBUG`](#debug) is False and email access has been configured, ERROR and CRITICAL messages will be emailed to the users defined in [`ADMINS`](#admins).
The Django framework on which NetBox runs allows for the customization of logging, e.g. to write logs to file. Please consult the [Django logging documentation](https://docs.djangoproject.com/en/stable/topics/logging/) for more information on configuring this setting. Below is an example which will write all INFO and higher messages to a file:
The Django framework on which NetBox runs allows for the customization of logging format and destination. Please consult the [Django logging documentation](https://docs.djangoproject.com/en/stable/topics/logging/) for more information on configuring this setting. Below is an example which will write all INFO and higher messages to a local file:
```
```python
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
@@ -191,13 +308,32 @@ LOGGING = {
}
```
### Available Loggers
* `netbox.<app>.<model>` - Generic form for model-specific log messages
* `netbox.auth.*` - Authentication events
* `netbox.api.views.*` - Views which handle business logic for the REST API
* `netbox.views.*` - Views which handle business logic for the web UI
---
## LOGIN_PERSISTENCE
Default: False
If true, the lifetime of a user's authentication session will be automatically reset upon each valid request. For example, if [`LOGIN_TIMEOUT`](#login_timeout) is configured to 14 days (the default), and a user whose session is due to expire in five days makes a NetBox request (with a valid session cookie), the session's lifetime will be reset to 14 days.
Note that enabling this setting causes NetBox to update a user's session in the database (or file, as configured per [`SESSION_FILE_PATH`](#session_file_path)) with each request, which may introduce significant overhead in very active environments. It also permits an active user to remain authenticated to NetBox indefinitely.
---
## LOGIN_REQUIRED
Default: False
Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users are permitted to access most data in NetBox (excluding secrets) but not make any changes.
Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users are permitted to access most data in NetBox but not make any changes.
---
@@ -205,29 +341,13 @@ Setting this to True will permit only authenticated users to access any part of
Default: 1209600 seconds (14 days)
The liftetime (in seconds) of the authentication cookie issued to a NetBox user upon login.
---
## MAINTENANCE_MODE
Default: False
Setting this to True will display a "maintenance mode" banner at the top of every page.
---
## MAX_PAGE_SIZE
Default: 1000
An API consumer can request an arbitrary number of objects by appending the "limit" parameter to the URL (e.g. `?limit=1000`). This setting defines the maximum limit. Setting it to `0` or `None` will allow an API consumer to request all objects by specifying `?limit=0`.
The lifetime (in seconds) of the authentication cookie issued to a NetBox user upon login.
---
## MEDIA_ROOT
Default: $BASE_DIR/netbox/media/
Default: $INSTALL_ROOT/netbox/media/
The file path to the location where media files (such as image attachments) are stored. By default, this is the `netbox/media/` directory within the base NetBox installation path.
@@ -237,81 +357,83 @@ The file path to the location where media files (such as image attachments) are
Default: False
Toggle exposing Prometheus metrics at `/metrics`. See the [Prometheus Metrics](../../additional-features/prometheus-metrics/) documentation for more details.
Toggle the availability Prometheus-compatible metrics at `/metrics`. See the [Prometheus Metrics](../additional-features/prometheus-metrics.md) documentation for more details.
---
## NAPALM_USERNAME
## PLUGINS
## NAPALM_PASSWORD
Default: Empty
NetBox will use these credentials when authenticating to remote devices via the [NAPALM library](https://napalm-automation.net/), if installed. Both parameters are optional.
A list of installed [NetBox plugins](../../plugins/) to enable. Plugins will not take effect unless they are listed here.
Note: If SSH public key authentication has been set up for the system account under which NetBox runs, these parameters are not needed.
!!! warning
Plugins extend NetBox by allowing external code to run with the same access and privileges as NetBox itself. Only install plugins from trusted sources. The NetBox maintainers make absolutely no guarantees about the integrity or security of your installation with plugins enabled.
---
## NAPALM_ARGS
## PLUGINS_CONFIG
A dictionary of optional arguments to pass to NAPALM when instantiating a network driver. See the NAPALM documentation for a [complete list of optional arguments](http://napalm.readthedocs.io/en/latest/support/#optional-arguments). An example:
Default: Empty
```
NAPALM_ARGS = {
'api_key': '472071a93b60a1bd1fafb401d9f8ef41',
'port': 2222,
This parameter holds configuration settings for individual NetBox plugins. It is defined as a dictionary, with each key using the name of an installed plugin. The specific parameters supported are unique to each plugin: Reference the plugin's documentation to determine the supported parameters. An example configuration is shown below:
```python
PLUGINS_CONFIG = {
'plugin1': {
'foo': 123,
'bar': True
},
'plugin2': {
'foo': 456,
},
}
```
Note: Some platforms (e.g. Cisco IOS) require an argument named `secret` to be passed in addition to the normal password. If desired, you can use the configured `NAPALM_PASSWORD` as the value for this argument:
```
NAPALM_USERNAME = 'username'
NAPALM_PASSWORD = 'MySecretPassword'
NAPALM_ARGS = {
'secret': NAPALM_PASSWORD,
# Include any additional args here
}
```
Note that a plugin must be listed in `PLUGINS` for its configuration to take effect.
---
## NAPALM_TIMEOUT
## RELEASE_CHECK_URL
Default: 30 seconds
Default: None (disabled)
The amount of time (in seconds) to wait for NAPALM to connect to a device.
This parameter defines the URL of the repository that will be checked for new NetBox releases. When a new release is detected, a message will be displayed to administrative users on the home page. This can be set to the official repository (`'https://api.github.com/repos/netbox-community/netbox/releases'`) or a custom fork. Set this to `None` to disable automatic update checks.
---
## PAGINATE_COUNT
Default: 50
Determine how many objects to display per page within each list of objects.
---
## PREFER_IPV4
Default: False
When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to prefer IPv4 instead.
!!! note
The URL provided **must** be compatible with the [GitHub REST API](https://docs.github.com/en/rest).
---
## REPORTS_ROOT
Default: $BASE_DIR/netbox/reports/
Default: `$INSTALL_ROOT/netbox/reports/`
The file path to the location where custom reports will be kept. By default, this is the `netbox/reports/` directory within the base NetBox installation path.
The file path to the location where [custom reports](../customization/reports.md) will be kept. By default, this is the `netbox/reports/` directory within the base NetBox installation path.
---
## RQ_DEFAULT_TIMEOUT
Default: `300`
The maximum execution time of a background task (such as running a custom script), in seconds.
---
## SCRIPTS_ROOT
Default: $BASE_DIR/netbox/scripts/
Default: `$INSTALL_ROOT/netbox/scripts/`
The file path to the location where custom scripts will be kept. By default, this is the `netbox/scripts/` directory within the base NetBox installation path.
The file path to the location where [custom scripts](../customization/custom-scripts.md) will be kept. By default, this is the `netbox/scripts/` directory within the base NetBox installation path.
---
## SESSION_COOKIE_NAME
Default: `sessionid`
The name used for the session cookie. See the [Django documentation](https://docs.djangoproject.com/en/stable/ref/settings/#session-cookie-name) for more detail.
---
@@ -319,7 +441,7 @@ The file path to the location where custom scripts will be kept. By default, thi
Default: None
Session data is used to track authenticated users when they access NetBox. By default, NetBox stores session data in the PostgreSQL database. However, this inhibits authentication to a standby instance of NetBox without write access to the database. Alternatively, a local file path may be specified here and NetBox will store session data as files instead of using the database. Note that the user as which NetBox runs must have read and write permissions to this path.
HTTP session data is used to track authenticated users when they access NetBox. By default, NetBox stores session data in its PostgreSQL database. However, this inhibits authentication to a standby instance of NetBox without write access to the database. Alternatively, a local file path may be specified here and NetBox will store session data as files instead of using the database. Note that the NetBox system user must have read and write permissions to this path.
---
@@ -347,21 +469,19 @@ If `STORAGE_BACKEND` is not defined, this setting will be ignored.
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. [List of available time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
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).
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.
Defaults:
```
```python
DATE_FORMAT = 'N j, Y' # June 26, 2016
SHORT_DATE_FORMAT = 'Y-m-d' # 2016-06-27
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.
The configuration parameters listed here control remote authentication for NetBox. Note that `REMOTE_AUTH_ENABLED` must be true in order for these settings to take effect.
---
## REMOTE_AUTH_AUTO_CREATE_USER
Default: `False`
If true, NetBox will automatically create local accounts for users authenticated via a remote service. (Requires `REMOTE_AUTH_ENABLED`.)
This is the Python path to the custom [Django authentication backend](https://docs.djangoproject.com/en/stable/topics/auth/customizing/) to use for external user authentication. NetBox provides two built-in backends (listed below), though custom authentication backends may also be provided by other packages or plugins.
*`netbox.authentication.RemoteUserBackend`
*`netbox.authentication.LDAPBackend`
---
## REMOTE_AUTH_DEFAULT_GROUPS
Default: `[]` (Empty list)
The list of groups to assign a new user account when created using remote authentication. (Requires `REMOTE_AUTH_ENABLED`.)
---
## REMOTE_AUTH_DEFAULT_PERMISSIONS
Default: `{}` (Empty dictionary)
A mapping of permissions to assign a new user account when created using remote authentication. Each key in the dictionary should be set to a dictionary of the attributes to be applied to the permission, or `None` to allow all objects. (Requires `REMOTE_AUTH_ENABLED` as True and `REMOTE_AUTH_GROUP_SYNC_ENABLED` as False.)
---
## REMOTE_AUTH_ENABLED
Default: `False`
NetBox can be configured to support remote user authentication by inferring user authentication from an HTTP header set by the HTTP reverse proxy (e.g. nginx or Apache). Set this to `True` to enable this functionality. (Local authentication will still take effect as a fallback.) (`REMOTE_AUTH_DEFAULT_GROUPS` will not function if `REMOTE_AUTH_ENABLED` is disabled)
---
## REMOTE_AUTH_GROUP_SYNC_ENABLED
Default: `False`
NetBox can be configured to sync remote user groups by inferring user authentication from an HTTP header set by the HTTP reverse proxy (e.g. nginx or Apache). Set this to `True` to enable this functionality. (Local authentication will still take effect as a fallback.) (Requires `REMOTE_AUTH_ENABLED`.)
---
## REMOTE_AUTH_HEADER
Default: `'HTTP_REMOTE_USER'`
When remote user authentication is in use, this is the name of the HTTP header which informs NetBox of the currently authenticated user. For example, to use the request header `X-Remote-User` it needs to be set to `HTTP_X_REMOTE_USER`. (Requires `REMOTE_AUTH_ENABLED`.)
---
## REMOTE_AUTH_GROUP_HEADER
Default: `'HTTP_REMOTE_USER_GROUP'`
When remote user authentication is in use, this is the name of the HTTP header which informs NetBox of the currently authenticated user. For example, to use the request header `X-Remote-User-Groups` it needs to be set to `HTTP_X_REMOTE_USER_GROUPS`. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
---
## REMOTE_AUTH_SUPERUSER_GROUPS
Default: `[]` (Empty list)
The list of groups that promote an remote User to Superuser on Login. If group isn't present on next Login, the Role gets revoked. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
---
## REMOTE_AUTH_SUPERUSERS
Default: `[]` (Empty list)
The list of users that get promoted to Superuser on Login. If user isn't present in list on next Login, the Role gets revoked. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
---
## REMOTE_AUTH_STAFF_GROUPS
Default: `[]` (Empty list)
The list of groups that promote an remote User to Staff on Login. If group isn't present on next Login, the Role gets revoked. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
---
## REMOTE_AUTH_STAFF_USERS
Default: `[]` (Empty list)
The list of users that get promoted to Staff on Login. If user isn't present in list on next Login, the Role gets revoked. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
---
## REMOTE_AUTH_GROUP_SEPARATOR
Default: `|` (Pipe)
The Seperator upon which `REMOTE_AUTH_GROUP_HEADER` gets split into individual Groups. This needs to be coordinated with your authentication Proxy. (Requires `REMOTE_AUTH_ENABLED` and `REMOTE_AUTH_GROUP_SYNC_ENABLED` )
This is a list of valid fully-qualified domain names (FQDNs) that is used to reach the NetBox service. Usually this is the same as the hostname for the NetBox server, but can also be different (e.g. when using a reverse proxy serving the NetBox website under a different FQDN than the hostname of the NetBox server). NetBox will not permit access to the server via any other hostnames (or IPs). The value of this option is also used to set `CSRF_TRUSTED_ORIGINS`, which restricts `HTTP POST` to the same set of hosts (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS)). Keep in mind that NetBox, by default, has `USE_X_FORWARDED_HOST = True` (in `netbox/netbox/settings.py`) which means that if you're using a reverse proxy, it's the FQDN used to reach that reverse proxy which needs to be in this list (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#allowed-hosts)).
This is a list of valid fully-qualified domain names (FQDNs) and/or IP addresses that can be used to reach the NetBox service. Usually this is the same as the hostname for the NetBox server, but can also be different; for example, when using a reverse proxy serving the NetBox website under a different FQDN than the hostname of the NetBox server. To help guard against [HTTP Host header attackes](https://docs.djangoproject.com/en/3.0/topics/security/#host-headers-virtual-hosting), NetBox will not permit access to the server via any other hostnames (or IPs).
!!! note
This parameter must always be defined as a list or tuple, even if only a single value is provided.
The value of this option is also used to set `CSRF_TRUSTED_ORIGINS`, which restricts POST requests to the same set of hosts (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS)). Keep in mind that NetBox, by default, sets `USE_X_FORWARDED_HOST` to true, which means that if you're using a reverse proxy, it's the FQDN used to reach that reverse proxy which needs to be in this list (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#allowed-hosts)).
If you are not yet sure what the domain name and/or IP address of the NetBox installation will be, and are comfortable accepting the risks in doing so, you can set this to a wildcard (asterisk) to allow all host values:
```
ALLOWED_HOSTS = ['*']
```
---
## DATABASE
NetBox requires access to a PostgreSQL database service to store data. This service can run locally or on a remote system. The following parameters must be defined within the `DATABASE` dictionary:
NetBox requires access to a PostgreSQL 10 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary:
*`NAME` - Database name
*`USER` - PostgreSQL username
*`PASSWORD` - PostgreSQL password
*`HOST` - Name or IP address of the database server (use `localhost` if running locally)
*`PORT` - TCP port of the PostgreSQL service; leave blank for default port (5432)
*`CONN_MAX_AGE` - Lifetime of a [persistent database connection](https://docs.djangoproject.com/en/stable/ref/databases/#persistent-connections), in seconds (150-300 is recommended)
*`PORT` - TCP port of the PostgreSQL service; leave blank for default port (TCP/5432)
*`CONN_MAX_AGE` - Lifetime of a [persistent database connection](https://docs.djangoproject.com/en/stable/ref/databases/#persistent-connections), in seconds (300 is the default)
Example:
@@ -46,27 +57,26 @@ DATABASE = {
[Redis](https://redis.io/) is an in-memory data store similar to memcached. While Redis has been an optional component of
NetBox since the introduction of webhooks in version 2.4, it is required starting in 2.6 to support NetBox's caching
functionality (as well as other planned features). In 2.7, the connection settings were broken down into two sections for
webhooks and caching, allowing the user to connect to different Redis instances/databases per feature.
task queuing and caching, allowing the user to connect to different Redis instances/databases per feature.
Redis is configured using a configuration setting similar to `DATABASE` and these settings are the same for both of the `webhooks` and `caching` subsections:
Redis is configured using a configuration setting similar to `DATABASE` and these settings are the same for both of the `tasks` and `caching` subsections:
*`HOST` - Name or IP address of the Redis server (use `localhost` if running locally)
*`PORT` - TCP port of the Redis service; leave blank for default port (6379)
*`PASSWORD` - Redis password (if set)
*`DATABASE` - Numeric database ID
*`DEFAULT_TIMEOUT` - Connection timeout in seconds
*`SSL` - Use SSL connection to Redis
*`INSECURE_SKIP_TLS_VERIFY` - Set to `True` to **disable** TLS certificate verification (not recommended)
Example:
An example configuration is provided below:
```python
REDIS={
'webhooks':{
'tasks':{
'HOST':'redis.example.com',
'PORT':1234,
'PASSWORD':'foobar',
'DATABASE':0,
'DEFAULT_TIMEOUT':300,
'SSL':False,
},
'caching':{
@@ -74,40 +84,41 @@ REDIS = {
'PORT':6379,
'PASSWORD':'',
'DATABASE':1,
'DEFAULT_TIMEOUT':300,
'SSL':False,
}
}
```
!!! note
If you are upgrading from a version prior to v2.7, please note that the Redis connection configuration settings have
changed. Manual modification to bring the `REDIS` section inline with the above specification is necessary
If you are upgrading from a NetBox release older than v2.7.0, please note that the Redis connection configuration
settings have changed. Manual modification to bring the `REDIS` section inline with the above specification is
necessary
!!! note
It is highly recommended to keep the webhook and cache databases separate. Using the same database number on the
same Redis instance for both may result in webhook processing data being lost during cache flushing events.
!!! warning
It is highly recommended to keep the task and cache databases separate. Using the same database number on the
same Redis instance for both may result in queued background tasks being lost during cache flushing events.
### Using Redis Sentinel
If you are using [Redis Sentinel](https://redis.io/topics/sentinel) for high-availability purposes, there is minimal
configuration necessary to convert NetBox to recognize it. It requires the removal of the `HOST` and `PORT` keys from
above and the addition of two new keys.
above and the addition of three new keys.
*`SENTINELS`: List of tuples or tuple of tuples with each inner tuple containing the name or IP address
of the Redis server and port for each sentinel instance to connect to
*`SENTINEL_SERVICE`: Name of the master / service to connect to
*`SENTINEL_TIMEOUT`: Connection timeout, in seconds
It is possible to have only one or the other Redis configurations to use Sentinel functionality. It is possible
for example to have the webhook use sentinel via `HOST`/`PORT` and for caching to use Sentinel via
`SENTINELS`/`SENTINEL_SERVICE`.
It is permissible to use Sentinel for only one database and not the other.
---
## SECRET_KEY
This is a secret cryptographic key is used to improve the security of cookies and password resets. The key defined here should not be shared outside of the configuration file. `SECRET_KEY` can be changed at any time, however be aware that doing so will invalidate all existing sessions.
This is a secret, random string used to assist in the creation new cryptographic hashes for passwords and HTTP cookies. The key defined here should not be shared outside of the configuration file. `SECRET_KEY` can be changed at any time, however be aware that doing so will invalidate all existing sessions.
Please note that this key is **not** used for hashing user passwords or for the encrypted storage of secret data in NetBox.
Please note that this key is **not** used directly for hashing user passwords or for the encrypted storage of secret data in NetBox.
`SECRET_KEY` should be at least 50 characters in length and contain a random mix of letters, digits, and symbols. The script located at `netbox/generate_secret_key.py` may be used to generate a suitable key.
`SECRET_KEY` should be at least 50 characters in length and contain a random mix of letters, digits, and symbols. The script located at `$INSTALL_ROOT/netbox/generate_secret_key.py` may be used to generate a suitable key.
@@ -30,11 +30,12 @@ Once component templates have been created, every new device that you create as
!!! note
Assignment of components from templates occurs only at the time of device creation. If you modify the templates of a device type, it will not affect devices which have already been created. However, you always have the option of adding, modifying, or deleting components on existing devices.
Below is a simple diagram demonstrating how power is modeled in NetBox.
!!! note
The power feeds are connected to the same power panel for illustrative purposes; usually, you would have such feeds diversely connected to panels to avoid the single point of failure.
```
+---------------+
| Power panel 1 |
+---------------+
| |
| |
+--------------+ +--------------+
| Power feed 1 | | Power feed 2 |
+--------------+ +--------------+
| |
| |
| | <-- Power ports
+---------+ +---------+
| PDU 1 | | PDU 2 |
+---------+ +---------+
| \ / | <-- Power outlets
| \ / |
| \ / |
| X |
| / \ |
| / \ |
| / \ | <-- Power ports
+--------+ +--------+
| Server | | Router |
+--------+ +--------+
```

Several features within NetBox, such as export templates and webhooks, utilize Jinja2 templating. For convenience, objects which support custom field assignment expose custom field data through the `cf` property. This is a bit cleaner than accessing custom field data through the actual field (`custom_field_data`).
For example, a custom field named `foo123` on the Site model is accessible on an instance as `{{ site.cf.foo123 }}`.
## Custom Fields and the REST API
When retrieving an object via the REST API, all of its custom data will be included within the `custom_fields` attribute. For example, below is the partial output of a site with two custom fields defined:
@@ -6,22 +6,24 @@ Custom scripting was introduced to provide a way for users to execute custom log
* Create a range of new reserved prefixes or IP addresses
* Fetch data from an external source and import it to NetBox
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 written from scratch, a custom script can be used to accomplish just about anything.
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.
## Writing Custom Scripts
All custom scripts must inherit from the `extras.scripts.Script` base class. This class provides the functionality necessary to generate forms and log activity.
```
```python
from extras.scripts import Script
class MyScript(Script):
..
...
```
Scripts comprise two core components: variables and a `run()` method. Variables allow your script to accept user input via the NetBox UI. The `run()` method is where your script's execution logic lives. (Note that your script can have as many methods as needed: this is merely the point of invocation for NetBox.)
Scripts comprise two core components: a set of variables and a `run()` method. Variables allow your script to accept user input via the NetBox UI, but they are optional: If your script does not require any user input, there is no need to define any variables.
```
The `run()` method is where your script's execution logic lives. (Note that your script can have as many methods as needed: this is merely the point of invocation for NetBox.)
```python
class MyScript(Script):
var1 = StringVar(...)
var2 = IntegerVar(...)
@@ -37,17 +39,31 @@ The `run()` method should accept two arguments:
* `commit` - A boolean indicating whether database changes will be committed.
!!! note
The `commit` argument was introduced in NetBox v2.7.8. Backward compatibility is maintained for scripts which accept only the `data` argument, however moving forward scripts should accept both arguments.
The `commit` argument was introduced in NetBox v2.7.8. Backward compatibility is maintained for scripts which accept only the `data` argument, however beginning with v2.10 NetBox will require the `run()` method of every script to accept both arguments. (Either argument may still be ignored within the method.)
Defining variables is optional: You may create a script with only a `run()` method if no user input is needed.
Defining script variables is optional: You may create a script with only a `run()` method if no user input is needed.
Returning output from your script is optional. Any raw output generated by the script will be displayed under the "output" tab in the UI.
Any output generated by the script during its execution will be displayed under the "output" tab in the UI.
By default, scripts within a module are ordered alphabetically in the scripts list page. To return scripts in a specific order, you can define the `script_order` variable at the end of your module. The `script_order` variable is a tuple which contains each Script class in the desired order. Any scripts that are omitted from this list will be listed last.
You can define `name` within a script module (the Python file which contains one or more scripts) to set the module name. If `name` is not defined, the filename will be used.
You can define `name` within a script module (the Python file which contains one or more scripts) to set the module name. If `name` is not defined, the module's filename will be used.
## Script Attributes
@@ -63,28 +79,31 @@ A human-friendly description of what your script does.
### `field_order`
A list of field names indicating the order in which the form fields should appear. This is optional, however on Python 3.5 and earlier the fields will appear in random order. (Declarative ordering is preserved on Python 3.6 and above.) For example:
```
field_order = ['var1', 'var2', 'var3']
```
By default, script variables will be ordered in the form as they are defined in the script. `field_order` may be defined as an iterable of field names to determine the orderin which variables are rendered. Any fields not included in this iterable be listed last.
### `commit_default`
The checkbox to commit database changes when executing a script is checked by default. Set `commit_default` to False under the script's Meta class to leave this option unchecked by default.
```
```python
commit_default = False
```
### `job_timeout`
Set the maximum allowed runtime for the script. If not set, `RQ_DEFAULT_TIMEOUT` will be used.
!!! info "This feature was introduced in v3.2.1"
## Accessing Request Data
Details of the current HTTP request (the one being made to execute the script) are available as the instance attribute `self.request`. This can be used to infer, for example, the user executing the script and the client IP address:
```python
username = self.request.user.username
ip_address = self.request.META.get('HTTP_X_FORWARDED_FOR') or self.request.META.get('REMOTE_ADDR')
self.log_info("Running as user {} (IP: {})...".format(username, ip_address))
ip_address = self.request.META.get('HTTP_X_FORWARDED_FOR') or \
self.request.META.get('REMOTE_ADDR')
self.log_info(f"Running as user {username} (IP: {ip_address})...")
```
For a complete list of available request parameters, please see the [Django documentation](https://docs.djangoproject.com/en/stable/ref/request-response/).
@@ -112,30 +131,40 @@ Log messages are returned to the user upon execution of the script. Markdown ren
## Variable Reference
### Default Options
All custom script variables support the following default options:
* `default` - The field's default value
* `description` - A brief user-friendly description of the field
* `label` - The field name to be displayed in the rendered form
* `required` - Indicates whether the field is mandatory (all fields are required by default)
* `widget` - The class of form widget to use (see the [Django documentation](https://docs.djangoproject.com/en/stable/ref/forms/widgets/))
### StringVar
Stores a string of characters (i.e. a line of text). Options include:
Stores a string of characters (i.e. text). Options include:
* `min_length` - Minimum number of characters
* `max_length` - Maximum number of characters
* `regex` - A regular expression against which the provided value must match
Note:`min_length` and `max_length` can be set to the same number to effect a fixed-length field.
Note that`min_length` and `max_length` can be set to the same number to effect a fixed-length field.
### TextVar
Arbitrary text of any length. Renders as multi-line text input field.
Arbitrary text of any length. Renders as a multi-line text input field.
### IntegerVar
Stored a numeric integer. Options include:
Stores a numeric integer. Options include:
* `min_value` - Minimum value
* `max_value` - Maximum value
### BooleanVar
A true/false flag. This field has no options beyond the defaults.
A true/false flag. This field has no options beyond the defaults listed above.
### ChoiceVar
@@ -154,15 +183,52 @@ CHOICES = (
direction = ChoiceVar(choices=CHOICES)
```
In the example above, selecting the choice labeled "North" will submit the value `n`.
### MultiChoiceVar
Similar to `ChoiceVar`, but allows for the selection of multiple choices.
### ObjectVar
A NetBox object. The list of available objects is defined by the queryset parameter. Each instance of this variable is limited to a single object type.
A particular object within NetBox. Each ObjectVar must specify a particular model, and allows the user to select one of the available instances. ObjectVar accepts several arguments, listed below.
* `queryset` - A [Django queryset](https://docs.djangoproject.com/en/stable/topics/db/queries/)
* `model` - The model class
* `query_params` - A dictionary of query parameters to use when retrieving available options (optional)
* `null_option` - A label representing a "null" or empty choice (optional)
To limit the selections available within the list, additional query parameters can be passed as the `query_params` dictionary. For example, to show only devices with an "active" status:
```python
device = ObjectVar(
model=Device,
query_params={
'status': 'active'
}
)
```
Multiple values can be specified by assigning a list to the dictionary key. It is also possible to reference the value of other fields in the form by prepending a dollar sign (`$`) to the variable's name.
```python
region = ObjectVar(
model=Region
)
site = ObjectVar(
model=Site,
query_params={
'region_id': '$region'
}
)
```
### MultiObjectVar
Similar to `ObjectVar`, but allows for the selection of multiple objects.
### FileVar
An uploaded file. Note that uploaded files are present in memory only for the duration of the script's execution: They will not be save for future use.
An uploaded file. Note that uploaded files are present in memory only for the duration of the script's execution: They will not be automatically saved for future use. The script is responsible for writing file contents to disk where necessary.
### IPAddressVar
@@ -176,18 +242,48 @@ An IPv4 or IPv6 address with a mask. Returns a `netaddr.IPNetwork` object which
An IPv4 or IPv6 network with a mask. Returns a `netaddr.IPNetwork` object. Two attributes are available to validate the provided mask:
* `min_prefix_length` - Minimum length of the mask (default: none)
* `max_prefix_length` - Maximum length of the mask (default: none)
* `min_prefix_length` - Minimum length of the mask
* `max_prefix_length` - Maximum length of the mask
### Default Options
## Running Custom Scripts
All variables support the following default options:
!!! note
To run a custom script, a user must be assigned the `extras.run_script` permission. This is achieved by assigning the user (or group) a permission on the Script object and specifying the `run` action in the admin UI as shown below.
* `default` - The field's default value
* `description` - A brief description of the field
* `label` - The name of the form field
* `required` - Indicates whether the field is mandatory (default: true)
* `widget` - The class of form widget to use (see the [Django documentation](https://docs.djangoproject.com/en/stable/ref/forms/widgets/))

### Via the Web UI
Custom scripts can be run via the web UI by navigating to the script, completing any required form data, and clicking the "run script" button.
### Via the API
To run a script via the REST API, issue a POST request to the script's endpoint specifying the form data and commitment. For example, to run a script named `example.MyReport`, we would make a request such as the following:
The required ``<module>.<script>`` argument is the script to run where ``<module>`` is the name of the python file in the ``scripts`` directory without the ``.py`` extension and ``<script>`` is the name of the script class in the ``<module>`` to run.
The optional ``--data "<data>"`` argument is the data to send to the script
The optional ``--loglevel`` argument is the desired logging level to output to the console.
The optional ``--commit`` argument will commit any changes in the script to the database.
## Example
@@ -199,11 +295,11 @@ Below is an example script that creates new objects for a planned site. The user
These variables are presented as a web form to be completed by the user. Once submitted, the script's `run()` method is called to create the appropriate objects.
```
```python
from django.utils.text import slugify
from dcim.choices import DeviceStatusChoices, SiteStatusChoices
from dcim.models import Device, DeviceRole, DeviceType, Site
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from extras.scripts import *
@@ -220,12 +316,16 @@ class NewBranchScript(Script):
NetBox validates every object prior to it being written to the database to ensure data integrity. This validation includes things like checking for proper formatting and that references to related objects are valid. However, you may wish to supplement this validation with some rules of your own. For example, perhaps you require that every site's name conforms to a specific pattern. This can be done using custom validation rules.
## Custom Validation Rules
Custom validation rules are expressed as a mapping of model attributes to a set of rules to which that attribute must conform. For example:
```json
{
"name":{
"min_length":5,
"max_length":30
}
}
```
This defines a custom validator which checks that the length of the `name` attribute for an object is at least five characters long, and no longer than 30 characters. This validation is executed _after_ NetBox has performed its own internal validation.
The `CustomValidator` class supports several validation types:
*`min`: Minimum value
*`max`: Maximum value
*`min_length`: Minimum string length
*`max_length`: Maximum string length
*`regex`: Application of a [regular expression](https://en.wikipedia.org/wiki/Regular_expression)
*`required`: A value must be specified
*`prohibited`: A value must _not_ be specified
The `min` and `max` types should be defined for numeric values, whereas `min_length`, `max_length`, and `regex` are suitable for character strings (text values). The `required` and `prohibited` validators may be used for any field, and should be passed a value of `True`.
!!! warning
Bear in mind that these validators merely supplement NetBox's own validation: They will not override it. For example, if a certain model field is required by NetBox, setting a validator for it with `{'prohibited': True}` will not work.
### Custom Validation Logic
There may be instances where the provided validation types are insufficient. NetBox provides a `CustomValidator` class which can be extended to enforce arbitrary validation logic by overriding its `validate()` method, and calling `fail()` when an unsatisfactory condition is detected.
self.fail("Active sites must have a description set!",field='status')
```
The `fail()` method may optionally specify a field with which to associate the supplied error message. If specified, the error message will appear to the user as associated with this field. If omitted, the error message will not be associated with any field.
## Assigning Custom Validators
Custom validators are associated with specific NetBox models under the [CUSTOM_VALIDATORS](../configuration/dynamic-settings.md#custom_validators) configuration parameter. There are three manners by which custom validation rules can be defined:
1. Plain JSON mapping (no custom logic)
2. Dotted path to a custom validator class
3. Direct reference to a custom validator class
### Plain Data
For cases where custom logic is not needed, it is sufficient to pass validation rules as plain JSON-compatible objects. This approach typically affords the most portability for your configuration. For instance:
```python
CUSTOM_VALIDATORS={
"dcim.site":[
{
"name":{
"min_length":5,
"max_length":30,
}
}
],
"dcim.device":[
{
"platform":{
"required":True,
}
}
]
}
```
### Dotted Path
In instances where a custom validator class is needed, it can be referenced by its Python path (relative to NetBox's working directory):
```python
CUSTOM_VALIDATORS={
'dcim.site':(
'my_validators.Validator1',
'my_validators.Validator2',
),
'dcim.device':(
'my_validators.Validator3',
)
}
```
### Direct Class Reference
This approach requires each class being instantiated to be imported directly within the Python configuration file.
When it is necessary to provide authentication credentials (such as when [`LOGIN_REQUIRED`](../configuration/optional-settings.md#login_required) has been enabled), it is recommended to render export templates via the REST API. This allows the client to specify an authentication token. To render an export template via the REST API, make a `GET` request to the model's list endpoint and append the `export` parameter specifying the export template name. For example:
```
GET /api/dcim/sites/?export=MyTemplateName
```
Note that the body of the response will contain only the rendered export template content, as opposed to a JSON object or list.
## Example
Here's an example device export template that will generate a simple Nagios configuration from a list of devices.
```
{% for device in queryset %}{% if device.status and device.primary_ip %}define host{
use generic-switch
host_name {{ device.name }}
address {{ device.primary_ip.address.ip }}
}
{% endif %}{% endfor %}
```
The generated output will look something like this:
@@ -12,7 +12,7 @@ A NetBox report is a mechanism for validating the integrity of data within NetBo
## Writing Reports
Reports must be saved as files in the [`REPORTS_ROOT`](../../configuration/optional-settings/#reports_root) path (which defaults to `netbox/reports/`). Each file created within this path is considered a separate module. Each module holds one or more reports (Python classes), each of which performs a certain function. The logic of each report is broken into discrete test methods, each of which applies a small portion of the logic comprising the overall test.
Reports must be saved as files in the [`REPORTS_ROOT`](../configuration/optional-settings.md#reports_root) path (which defaults to `netbox/reports/`). Each file created within this path is considered a separate module. Each module holds one or more reports (Python classes), each of which performs a certain function. The logic of each report is broken into discrete test methods, each of which applies a small portion of the logic comprising the overall test.
!!! warning
The reports path includes a file named `__init__.py`, which registers the path as a Python module. Do not delete this file.
@@ -33,7 +33,6 @@ Within each report class, we'll create a number of test methods to execute our r
```
from dcim.choices import DeviceStatusChoices
from dcim.constants import CONNECTION_STATUS_PLANNED
from dcim.models import ConsolePort, Device, PowerPort
from extras.reports import Report
@@ -51,7 +50,7 @@ class DeviceConnectionsReport(Report):
console_port.device,
"No console connection defined for {}".format(console_port.name)
"Console connection for {} marked as planned".format(console_port.name)
@@ -67,7 +66,7 @@ class DeviceConnectionsReport(Report):
for power_port in PowerPort.objects.filter(device=device):
if power_port.connected_endpoint is not None:
connected_ports += 1
if power_port.connection_status == CONNECTION_STATUS_PLANNED:
if not power_port.path.is_active:
self.log_warning(
device,
"Power connection for {} marked as planned".format(power_port.name)
@@ -81,11 +80,25 @@ class DeviceConnectionsReport(Report):
self.log_success(device)
```
As you can see, reports are completely customizable. Validation logic can be as simple or as complex as needed.
As you can see, reports are completely customizable. Validation logic can be as simple or as complex as needed. Also note that the `description` attribute support markdown syntax. It will be rendered in the report list page.
!!! warning
Reports should never alter data: If you find yourself using the `create()`, `save()`, `update()`, or `delete()` methods on objects within reports, stop and re-evaluate what you're trying to accomplish. Note that there are no safeguards against the accidental alteration or destruction of data.
## Report Attributes
### `description`
A human-friendly description of what your report does.
### `job_timeout`
Set the maximum allowed runtime for the report. If not set, `RQ_DEFAULT_TIMEOUT` will be used.
!!! info "This feature was introduced in v3.2.1"
## Logging
The following methods are available to log results within a report:
* log(message)
@@ -94,19 +107,36 @@ The following methods are available to log results within a report:
* log_warning(object, message)
* log_failure(object, message)
The recording of one or more failure messages will automatically flag a report as failed. It is advised to log a success for each object that is evaluated so that the results will reflect how many objects are being reported on. (The inclusion of a log message is optional for successes.) Messages recorded with `log()` will appear in a report's results but are not associated with a particular object or status.
The recording of one or more failure messages will automatically flag a report as failed. It is advised to log a success for each object that is evaluated so that the results will reflect how many objects are being reported on. (The inclusion of a log message is optional for successes.) Messages recorded with `log()` will appear in a report's results but are not associated with a particular object or status. Log messages also support using markdown syntax and will be rendered on the report result page.
To perform additional tasks, such as sending an email or calling a webhook, after a report has been run, extend the `post_run()` method. The status of the report is available as `self.failed` and the results object is `self.result`.
To perform additional tasks, such as sending an email or calling a webhook, before or after a report is run, extend the `pre_run()` and/or `post_run()` methods, respectively. The status of a completed report is available as `self.failed` and the results object is `self.result`.
By default, reports within a module are ordered alphabetically in the reports list page. To return reports in a specific order, you can define the `report_order` variable at the end of your module. The `report_order` variable is a tuple which contains each Report class in the desired order. Any reports that are omitted from this list will be listed last.
Once you have created a report, it will appear in the reports list. Initially, reports will have no results associated with them. To generate results, run the report.
## Running Reports
!!! note
To run a report, a user must be assigned the `extras.run_report` permission. This is achieved by assigning the user (or group) a permission on the Report object and specifying the `run` action in the admin UI as shown below.

### Via the Web UI
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Note that a user must have permission to create ReportResults in order to run reports. (Permissions can be assigned through the admin UI.)
Once a report has been run, its associated results will be included in the report view.
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Once a report has been run, its associated results will be included in the report view.
Models within each app are stored in either `models.py` or within a submodule under the `models/` directory. When creating a model, be sure to subclass the [appropriate base model](models.md) from `netbox.models`. This will typically be NetBoxModel or OrganizationalModel. Remember to add the model class to the `__all__` listing for the module.
Each model should define, at a minimum:
* A `Meta` class specifying a deterministic ordering (if ordered by fields other than the primary ID)
* A `__str__()` method returning a user-friendly string representation of the instance
* A `get_absolute_url()` method returning an instance's direct URL (using `reverse()`)
## 2. Define field choices
If the model has one or more fields with static choices, define those choices in `choices.py` by subclassing `utilities.choices.ChoiceSet`.
## 3. Generate database migrations
Once your model definition is complete, generate database migrations by running `manage.py makemigrations -n $NAME --no-header`. Always specify a short unique name when generating migrations.
!!! info "Configuration Required"
Set `DEVELOPER = True` in your NetBox configuration to enable the creation of new migrations.
## 4. Add all standard views
Most models will need view classes created in `views.py` to serve the following operations:
* List view
* Detail view
* Edit view
* Delete view
* Bulk import
* Bulk edit
* Bulk delete
## 5. Add URL paths
Add the relevant URL path for each view created in the previous step to `urls.py`.
## 6. Add relevant forms
Depending on the type of model being added, you may need to define several types of form classes. These include:
* A base model form (for creating/editing individual objects)
* A bulk edit form
* A bulk import form (for CSV-based import)
* A filterset form (for filtering the object list view)
## 7. Create the FilterSet
Each model should have a corresponding FilterSet class defined. This is used to filter UI and API queries. Subclass the appropriate class from `netbox.filtersets` that matches the model's parent class.
## 8. Create the table class
Create a table class for the model in `tables.py` by subclassing `utilities.tables.BaseTable`. Under the table's `Meta` class, be sure to list both the fields and default columns.
## 9. Create the object template
Create the HTML template for the object view. (The other views each typically employ a generic template.) This template should extend `generic/object.html`.
## 10. Add the model to the navigation menu
Add the relevant navigation menu items in `netbox/netbox/navigation_menu.py`.
## 11. REST API components
Create the following for each model:
* Detailed (full) model serializer in `api/serializers.py`
* Nested serializer in `api/nested_serializers.py`
* API view in `api/views.py`
* Endpoint route in `api/urls.py`
## 12. GraphQL API components
Create a Graphene object type for the model in `graphql/types.py` by subclassing the appropriate class from `netbox.graphql.types`.
Also extend the schema class defined in `graphql/schema.py` with the individual object and object list fields per the established convention.
## 13. Add tests
Add tests for the following:
* UI views
* API views
* Filter sets
## 14. Documentation
Create a new documentation page for the model in `docs/models/<app_label>/<model_name>.md`. Include this file under the "features" documentation where appropriate.
Also add your model to the index in `docs/development/models.md`.
The registry is an in-memory data structure which houses various application-wide parameters, such as the list of enabled plugins. It is not exposed to the user and is not intended to be modified by any code outside of NetBox core.
The registry behaves essentially like a Python dictionary, with the notable exception that once a store (key) has been declared, it cannot be deleted or overwritten. The value of a store can, however, be modified; e.g. by appending a value to a list. Store values generally do not change once the application has been initialized.
The registry can be inspected by importing `registry` from `extras.registry`.
## Stores
### `model_features`
A dictionary of particular features (e.g. custom fields) mapped to the NetBox models which support them, arranged by app. For example:
```python
{
'custom_fields':{
'circuits':['provider','circuit'],
'dcim':['site','rack','devicetype',...],
...
},
'webhooks':{
...
},
...
}
```
### `plugin_menu_items`
Navigation menu items provided by NetBox plugins. Each plugin is registered as a key with the list of menu items it provides. An example:
```python
{
'Plugin A':(
<MenuItem>,<MenuItem>,<MenuItem>,
),
'Plugin B':(
<MenuItem>,<MenuItem>,<MenuItem>,
),
}
```
### `plugin_template_extensions`
Plugin content that gets embedded into core NetBox templates. The store comprises NetBox models registered as dictionary keys, each pointing to a list of applicable template extension classes that exist. An example:
Below is a list of items to consider when adding a new field to a model:
Below is a list of tasks to consider when adding a new field to a core model.
## 1. Generate and run database migration
## 1. Generate and run database migrations
Django migrations are used to express changes to the database schema. In most cases, Django can generate these automatically, however very complex changes may require manual intervention. Always remember to specify a short but descriptive name when generating a new migration.
[Django migrations](https://docs.djangoproject.com/en/stable/topics/migrations/) are used to express changes to the database schema. In most cases, Django can generate these automatically, however very complex changes may require manual intervention. Always remember to specify a short but descriptive name when generating a new migration.
```
./manage.py makemigrations <app> -n <name>
./manage.py migrate
```
Where possible, try to merge related changes into a single migration. For example, if three new fields are being added to different models within an app, these can be expressed in the same migration. You can merge a new migration with an existing one by combining their `operations` lists.
Where possible, try to merge related changes into a single migration. For example, if three new fields are being added to different models within an app, these can be expressed in a single migration. You can merge a newly generated migration with an existing one by combining their `operations` lists.
!!! note
Migrations can only be merged within a release. Once a new release has been published, its migrations cannot be altered.
!!! warning "Do not alter existing migrations"
Migrations can only be merged within a release. Once a new release has been published, its migrations cannot be altered (other than for the purpose of correcting a bug).
## 2. Add validation logic to `clean()`
If the new field introduces additional validation requirements (beyond what's included with the field itself), implement them in the model's `clean()` method. Remember to call the model's original method using `super()` before or agter your custom validation as appropriate:
If the new field introduces additional validation requirements (beyond what's included with the field itself), implement them in the model's `clean()` method. Remember to call the model's original method using `super()` before or after your custom validation as appropriate:
```
class Foo(models.Model):
def clean(self):
super(DeviceCSVForm, self).clean()
super().clean()
# Custom validation goes here
if self.bar is None:
raise ValidationError()
```
## 3. Add CSV helpers
## 3. Update relevant querysets
Add the name of the new field to `csv_headers` and included a CSV-friendly representation of its data in the model's `to_csv()` method. These will be used when exporting objects in CSV format.
If you're adding a relational field (e.g. `ForeignKey`) and intend to include the data when retrieving a list of objects, be sure to include the field using `prefetch_related()` as appropriate. This will optimize the view and avoid extraneous database queries.
## 4. Update relevant querysets
## 4. Update API serializer
If you're adding a relational field (e.g. `ForeignKey`) and intend to include the data when retreiving a list of objects, be sure to include the field using `prefetch_related()` as appropriate. This will optimize the view and avoid excessive database lookups.
Extend the model's API serializer in `<app>.api.serializers` to include the new field. In most cases, it will not be necessary to also extend the nested serializer, which produces a minimal representation of the model.
## 5. Update API serializer
## 5. Add fields to forms
Extend the model's API serializer in `<app>.api.serializers` to include the new field. In most cases, it will not be necessary to also extend the nested serializer, which produces a minimal represenation of the model.
## 6. Add choices to API view
If the new field has static choices, add it to the `FieldChoicesViewSet` for the app.
## 7. Add field to forms
Extend any forms to include the new field as appropriate. Common forms include:
Extend any forms to include the new field(s) as appropriate. These are found under the `forms/` directory within each app. Common forms include:
* **Credit/edit** - Manipulating a single object
* **Bulk edit** - Performing a change on mnay objects at once
* **Bulk edit** - Performing a change on many objects at once
* **CSV import** - The form used when bulk importing objects in CSV format
* **Filter** - Displays the options available for filtering a list of objects (both UI and API)
## 8. Extend object filter set
## 6. Extend object filter set
If the new field should be filterable, add it to the `FilterSet` for the model. If the field should be searchable, remember to reference it in the FilterSet's `search()` method.
If the new field should be filterable, add it to the `FilterSet` for the model. If the field should be searchable, remember to query it in the FilterSet's `search()` method.
## 9. Add column to object table
## 7. Add column to object table
If the new field will be included in the object list view, add a column to the model's table. For simple fields, adding the field name to `Meta.fields` will be sufficient. More complex fields may require explicitly declaring a new column.
If the new field will be included in the object list view, add a column to the model's table. For simple fields, adding the field name to `Meta.fields` will be sufficient. More complex fields may require declaring a custom column. Also add the field name to `default_columns` if the column should be present in the table by default.
## 10. Update the UI templates
## 8. Update the UI templates
Edit the object's view template to display the new field. There may also be a custom add/edit form template that needs to be updated.
## 11. Create/extend test cases
## 9. Create/extend test cases
Create or extend the relevant test cases to verify that the new field and any accompanying validation logic perform as expected. This is especially important for relational fields. NetBox incorporates various test suites, including:
@@ -80,3 +71,7 @@ Create or extend the relevant test cases to verify that the new field and any ac
* View tests
Be diligent to ensure all of the relevant test suites are adapted or extended as necessary to test any new functionality.
## 10. Update the model's documentation
Each model has a dedicated page in the documentation, at `models/<app>/<model>.md`. Update this file to include any relevant information about the new field.
Getting started with NetBox development is pretty straightforward, and should feel very familiar to anyone with Django development experience. There are a few things you'll need:
* A Linux system or environment
* A PostgreSQL server, which can be installed locally [per the documentation](../installation/1-postgresql.md)
* A Redis server, which can also be [installed locally](../installation/2-redis.md)
* A supported version of Python
### Fork the Repo
Assuming you'll be working on your own fork, your first step will be to fork the [official git repository](https://github.com/netbox-community/netbox). (If you're a maintainer who's going to be working directly with the official repo, skip this step.) Click the "fork" button at top right (be sure that you've logged into GitHub first).
The NetBox project utilizes three persistent git branches to track work:
* `master` - Serves as a snapshot of the current stable release
* `develop` - All development on the upcoming stable release occurs here
* `feature` - Tracks work on an upcoming major release
Typically, you'll base pull requests off of the `develop` branch, or off of `feature` if you're working on a new major release. **Never** merge pull requests into the `master` branch: This branch only ever merges pull requests from the `develop` branch, to effect a new release.
For example, assume that the current NetBox release is v3.1.1. Work applied to the `develop` branch will appear in v3.1.2, and work done under the `feature` branch will be included in the next minor release (v3.2.0).
### Enable Pre-Commit Hooks
NetBox ships with a [git pre-commit hook](https://githooks.com/) script that automatically checks for style compliance and missing database migrations prior to committing changes. This helps avoid erroneous commits that result in CI test failures. You are encouraged to enable it by creating a link to `scripts/git-hooks/pre-commit`:
```no-highlight
$ cd .git/hooks/
$ ln -s ../../scripts/git-hooks/pre-commit
```
### Create a Python Virtual Environment
A [virtual environment](https://docs.python.org/3/tutorial/venv.html) (or "venv" for short) is like a container for a set of Python packages. These allow you to build environments suited to specific projects without interfering with system packages or other projects. When installed per the documentation, NetBox uses a virtual environment in production.
Create a virtual environment using the `venv` Python module:
```no-highlight
$ mkdir ~/.venv
$ python3 -m venv ~/.venv/netbox
```
This will create a directory named `.venv/netbox/` in your home directory, which houses a virtual copy of the Python executable and its related libraries and tooling. When running NetBox for development, it will be run using the Python binary at `~/.venv/netbox/bin/python`.
!!! info "Where to Create Your Virtual Environments"
Keeping virtual environments in `~/.venv/` is a common convention but entirely optional: Virtual environments can be created almost wherever you please. Also consider using [`virtualenvwrapper`](https://virtualenvwrapper.readthedocs.io/en/stable/) to simplify the management of multiple venvs.
Once created, activate the virtual environment:
```no-highlight
$ source ~/.venv/netbox/bin/activate
(netbox) $
```
Notice that the console prompt changes to indicate the active environment. This updates the necessary system environment variables to ensure that any Python scripts are run within the virtual environment.
### Install Dependencies
With the virtual environment activated, install the project's required Python packages using the `pip` module:
* `REDIS`: Redis configuration, if different from the defaults
* `SECRET_KEY`: Set to a random string (use `generate_secret_key.py` in the parent directory to generate a suitable key)
* `DEBUG`: Set to `True`
* `DEVELOPER`: Set to `True` (this enables the creation of new database migrations)
### Start the Development Server
Django provides a lightweight, auto-updating HTTP/WSGI server for development use. It is started with the `runserver` management command:
```no-highlight
$ ./manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
February 18, 2022 - 20:29:57
Django version 4.0.2, using settings 'netbox.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```
This ensures that your development environment is now complete and operational. Any changes you make to the code base will be automatically adapted by the development server.
!!! info "IDE Integration"
Some IDEs, such as PyCharm, will integrate with Django's development server and allow you to run it directly within the IDE. This is strongly encouraged as it makes for a much more convenient development environment.
## Populating Demo Data
Once you have your development environment up and running, it might be helpful to populate some "dummy" data to make interacting with the UI and APIs more convenient. Check out the [netbox-demo-data](https://github.com/netbox-community/netbox-demo-data) repo on GitHub, which houses a collection of sample data that can be easily imported to any new NetBox deployment. (This sample data is used to populate the public demo instance at <https://demo.netbox.dev>.)
The demo data is provided in JSON format and loaded into an empty database using Django's `loaddata` management command. Consult the demo data repo's `README` file for complete instructions on populating the data.
## Running Tests
Prior to committing any substantial changes to the code base, be sure to run NetBox's test suite to catch any potential errors. Tests are run using the `test` management command, which employs Python's [`unittest`](https://docs.python.org/3/library/unittest.html#module-unittest) library. Remember to ensure the Python virtual environment is active before running this command. Also keep in mind that these commands are executed in the `netbox/` directory, not the root directory of the repository.
To avoid potential issues with your local configuration file, set the `NETBOX_CONFIGURATION` to point to the packaged test configuration at `netbox/configuration_testing.py`. This will handle things like ensuring that the dummy plugin is enabled for comprehensive testing.
In cases where you haven't made any changes to the database schema (which is typical), you can append the `--keepdb` argument to this command to reuse the test database between runs. This cuts down on the time it takes to run the test suite since the database doesn't have to be rebuilt each time. (Note that this argument will cause errors if you've modified any model fields since the previous test run.)
```no-highlight
$ python manage.py test --keepdb
```
You can also reduce testing time by enabling parallel test execution with the `--parallel` flag. (By default, this will run as many parallel tests as you have processors. To avoid sluggishness, it's a good idea to specify a lower number of parallel tests.) This flag can be combined with `--keepdb`, although if you encounter any strange errors, try running the test suite again with parallelization disabled.
```no-highlight
$ python manage.py test --parallel <n>
```
Finally, it's possible to limit the run to a specific set of tests, specified by their Python path. For example, to run only IPAM and DCIM view tests:
```no-highlight
$ python manage.py test dcim.tests.test_views ipam.tests.test_views
```
This is handy for instances where just a few tests are failing and you want to re-run them individually.
## Submitting Pull Requests
Once you're happy with your work and have verified that all tests pass, commit your changes and push it upstream to your fork. Always provide descriptive (but not excessively verbose) commit messages. When working on a specific issue, be sure to prefix your commit message with the word "Fixes" or "Closes" and the issue number (with a hash mark). This tells GitHub to automatically close the referenced issue once the commit has been merged.
```no-highlight
$ git commit -m "Closes #1234: Add IPv5 support"
$ git push origin
```
Once your fork has the new commit, submit a [pull request](https://github.com/netbox-community/netbox/compare) to the NetBox repo to propose the changes. Be sure to provide a detailed accounting of the changes being made and the reasons for doing so.
Once submitted, a maintainer will review your pull request and either merge it or request changes. If changes are needed, you can make them via new commits to your fork: The pull request will update automatically.
!!! note "Remember to Open an Issue First"
Remember, pull requests are permitted only for **accepted** issues. If an issue you want to work on hasn't been approved by a maintainer yet, it's best to avoid risking your time and effort on a change that might not be accepted. (The one exception to this is trivial changes to the documentation or other non-critical resources.)
NetBox is maintained as a [GitHub project](https://github.com/netbox-community/netbox) under the Apache 2 license. Users are encouraged to submit GitHub issues for feature requests and bug reports, however we are very selective about pull requests. Please see the `CONTRIBUTING` guide for more direction on contributing to NetBox.
NetBox is maintained as a [GitHub project](https://github.com/netbox-community/netbox) under the Apache 2 license. Users are encouraged to submit GitHub issues for feature requests and bug reports, however we are very selective about pull requests. Each pull request must be preceded by an **approved** issue. Please see the `CONTRIBUTING` guide for more direction on contributing to NetBox.
## Communication
Communication among developers should always occur via public channels:
There are several official forums for communication among the developers and community members:
* [GitHub issues](https://github.com/netbox-community/netbox/issues) - All feature requests, bug reports, and other substantial changes to the code base **must** be documented in an issue.
* [The mailing list](https://groups.google.com/forum/#!forum/netbox-discuss) - The preferred forum for general discussion and support issues. Ideal for shaping a feature request prior to submitting an issue.
* [#netbox on NetworkToCode](http://slack.networktocode.com/) - Good for quick chats. Avoid any discussion that might need to be referenced later on, as the chat history is not retained long.
* [GitHub issues](https://github.com/netbox-community/netbox/issues) - All feature requests, bug reports, and other substantial changes to the code base **must** be documented in a GitHub issue.
* [GitHub discussions](https://github.com/netbox-community/netbox/discussions) - The preferred forum for general discussion and support issues. Ideal for shaping a feature request prior to submitting an issue.
* [#netbox on NetDev Community Slack](https://netdev.chat/) - Good for quick chats. Avoid any discussion that might need to be referenced later on, as the chat history is not retained long.
## Governance
NetBox follows the [benevolent dictator](http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel) model of governance, with [Jeremy Stretch](https://github.com/jeremystretch) ultimately responsible for all changes to the code base. While community contributions are welcomed and encouraged, the lead maintainer's primary role is to ensure the project's long-term maintainability and continued focus on its primary functions (in other words, avoid scope creep).
NetBox follows the [benevolent dictator](http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel) model of governance, with [Jeremy Stretch](https://github.com/jeremystretch) ultimately responsible for all changes to the code base. While community contributions are welcomed and encouraged, the lead maintainer's primary role is to ensure the project's long-term maintainability and continued focus on its primary functions.
## Project Structure
All development of the current NetBox release occurs in the `develop` branch; releases are packaged from the `master` branch. The `master` branch should _always_ represent the current stable release in its entirety, such that installing NetBox by either downloading a packaged release or cloning the `master` branch provides the same code base.
All development of the current NetBox release occurs in the `develop` branch; releases are packaged from the `master` branch. The `master` branch should _always_ represent the current stable release in its entirety, such that installing NetBox by either downloading a packaged release or cloning the `master` branch provides the same code base. Only pull requests representing new releases should be merged into `master`.
NetBox components are arranged into functional subsections called _apps_ (a carryover from Django verancular). Each app holds the models, views, and templates relevant to a particular function:
NetBox components are arranged into Django apps. Each app holds the models, views, and other resources relevant to a particular function:
*`circuits`: Communications circuits and providers (not to be confused with power circuits)
*`dcim`: Datacenter infrastructure management (sites, racks, and devices)
*`extras`: Additional features not considered part of the core data model
*`ipam`: IP address management (VRFs, prefixes, IP addresses, and VLANs)
*`secrets`: Encrypted storage of sensitive data (e.g. login credentials)
*`tenancy`: Tenants (such as customers) to which NetBox objects may be assigned
*`users`: Authentication and user preferences
*`utilities`: Resources which are not user-facing (extendable classes, etc.)
*`virtualization`: Virtual machines and clusters
*`wireless`: Wireless links and LANs
All core functionality is stored within the `netbox/` subdirectory. HTML templates are stored in a common `templates/` directory, with model- and view-specific templates arranged by app. Documentation is kept in the `docs/` root directory.
A NetBox model represents a discrete object type such as a device or IP address. Each model is defined as a Python class and has its own SQL table. All NetBox data models can be categorized by type.
The Django [content types](https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/) framework can be used to reference models within the database. A ContentType instance references a model by its `app_label` and `name`: For example, the Site model is referred to as `dcim.site`. The content type combined with an object's primary key form a globally unique identifier for the object (e.g. `dcim.site:123`).
### Features Matrix
* [Change logging](../additional-features/change-logging.md) - Changes to these objects are automatically recorded in the change log
* [Webhooks](../additional-features/webhooks.md) - NetBox is capable of generating outgoing webhooks for these objects
* [Custom fields](../customization/custom-fields.md) - These models support the addition of user-defined fields
* [Export templates](../customization/export-templates.md) - Users can create custom export templates for these models
* [Tagging](../models/extras/tag.md) - The models can be tagged with user-defined tags
* [Journaling](../additional-features/journaling.md) - These models support persistent historical commentary
* Nesting - These models can be nested recursively to create a hierarchy
Check `base_requirements.txt` for any dependencies pinned to a specific version, and upgrade them to their most stable release (where possible).
### Link to the Release Notes Page
Add the release notes (`/docs/release-notes/X.Y.md`) to the table of contents within `mkdocs.yml`, and add a summary of the major changes to `index.md`.
### Manually Perform a New Install
Install `mkdocs` in your local environment, then start the documentation server:
```no-highlight
$ pip install -r docs/requirements.txt
$ mkdocs serve
```
Follow these instructions to perform a new installation of NetBox. This process must _not_ be automated: The goal of this step is to catch any errors or omissions in the documentation, and ensure that it is kept up-to-date for each release. Make any necessary changes to the documentation before proceeding with the release.
### Close the Release Milestone
Close the release milestone on GitHub after ensuring there are no remaining open issues associated with it.
### Merge the Release Branch
Submit a pull request to merge the `feature` branch into the `develop` branch in preparation for its release.
---
## All Releases
### Update Requirements
Required Python packages are maintained in two files. `base_requirements.txt` contains a list of all the packages required by NetBox. Some of them may be pinned to a specific version of the package due to a known issue. For example:
@@ -13,47 +44,15 @@ djangorestframework==3.8.1
The other file is `requirements.txt`, which lists each of the required packages pinned to its current stable version. When NetBox is installed, the Python environment is configured to match this file. This helps ensure that a new release of a dependency doesn't break NetBox.
Every minor version release should refresh `requirements.txt` so that it lists the most recent stable release of each package. To do this:
Every release should refresh `requirements.txt` so that it lists the most recent stable release of each package. To do this:
1. Create a new virtual environment.
2. Install the latest version of all required packages via pip:
```
pip install -U -r base_requirements.txt
```
2. Install the latest version of all required packages `pip install -U -r base_requirements.txt`).
3. Run all tests and check that the UI and API function as expected.
4. Update the package versions in `requirements.txt` as appropriate.
4. Review each requirement's release notes for any breaking or otherwise noteworthy changes.
5. Update the package versions in `requirements.txt` as appropriate.
### Update Static Libraries
Update the following static libraries to their most recent stable release:
* Bootstrap 3
* Font Awesome 4
* Select2
* jQuery
* jQuery UI
### Squash Schema Migrations
Database schema migrations should be squashed for each new minor release. See the [squashing guide](squashing-migrations.md) for the detailed process.
### Create a new Release Notes Page
Create a file at `/docs/release-notes/X.Y.md` to establish the release notes for the new release. Add the file to the table of contents within `mkdocs.yml`.
### Manually Perform a New Install
Create a new installation of NetBox by following [the current documentation](http://netbox.readthedocs.io/en/latest/). This should be a manual process, so that issues with the documentation can be identified and corrected.
### Close the Release Milestone
Close the release milestone on GitHub. Ensure that there are no remaining open issues associated with it.
---
## All Releases
In cases where upgrading a dependency to its most recent release is breaking, it should be pinned to its current minor version in `base_requirements.txt` (with an explanatory comment) and revisited for the next major NetBox release.
### Verify CI Build Status
@@ -61,11 +60,15 @@ Ensure that continuous integration testing on the `develop` branch is completing
### Update Version and Changelog
Update the `VERSION` constant in `settings.py` to the new release version and annotate the current data in the release notes for the new version.
* Update the `VERSION` constant in `settings.py` to the new release version.
* Update the example version numbers in the feature request and bug report templates under `.github/ISSUE_TEMPLATES/`.
* Replace the "FUTURE" placeholder in the release notes with the current date.
Commit these changes to the `develop` branch.
### Submit a Pull Request
Submit a pull request title **"Release vX.Y.Z"** to merge the `develop` branch into `master`. Include a brief change log listing the features, improvements, and/or bugs addressed in the release.
Submit a pull request title **"Release vX.Y.Z"** to merge the `develop` branch into `master`. Copy the documented release notes into the pull request's body.
Once CI has completed on the PR, merge it.
@@ -73,20 +76,16 @@ Once CI has completed on the PR, merge it.
Draft a [new release](https://github.com/netbox-community/netbox/releases/new) with the following parameters.
* **Tag:** Current version (e.g. `v2.3.4`)
* **Tag:** Current version (e.g. `v2.9.9`)
* **Target:** `master`
* **Title:** Version and date (e.g. `v2.3.4 - 2018-08-02`)
* **Title:** Version and date (e.g. `v2.9.9 - 2020-11-09`)
Copy the description from the pull request into the release notes.
Copy the description from the pull request to the release.
### Update the Development Version
On the `develop` branch, update `VERSION` in `settings.py` to point to the next release. For example, if you just released v2.3.4, set:
On the `develop` branch, update `VERSION` in `settings.py` to point to the next release. For example, if you just released v2.9.9, set:
```
VERSION = 'v2.3.5-dev'
VERSION = 'v2.9.10-dev'
```
### Announce the Release
Announce the release on the [mailing list](https://groups.google.com/forum/#!forum/netbox-discuss). Include a link to the release and the (HTML-formatted) release notes.
The Django framework on which NetBox is built utilizes [migration files](https://docs.djangoproject.com/en/stable/topics/migrations/) to keep track of changes to the PostgreSQL database schema. Each time a model is altered, the resulting schema change is captured in a migration file, which can then be applied to effect the new schema.
As changes are made over time, more and more migration files are created. Although not necessarily problematic, it can be beneficial to merge and compress these files occasionally to reduce the total number of migrations that need to be applied upon installation of NetBox. This merging process is called _squashing_ in Django vernacular, and results in two parallel migration paths: individual and squashed.
Below is an example showing both individual and squashed migration files within an app:
In the example above, a new installation can leverage the squashed migrations to apply only two migrations:
*`0001_initial_squashed_0004_add_field`
*`0005_another_field`
This is because the squash file contains all of the operations performed by files `0001` through `0004`.
However, an existing installation that has already applied some of the individual migrations contained within the squash file must continue applying individual migrations. For instance, an installation which currently has up to `0002_alter_field` applied must apply the following migrations to become current:
*`0003_remove_field`
*`0004_add_field`
*`0005_another_field`
Squashed migrations are opportunistic: They are used only if applicable to the current environment. Django will fall back to using individual migrations if the squashed migrations do not agree with the current database schema at any point.
## Squashing Migrations
During every minor (i.e. 2.x) release, migrations should be squashed to help simplify the migration process for new installations. The process below describes how to squash migrations efficiently and with minimal room for error.
### 1. Create a New Branch
Create a new branch off of the `develop-2.x` branch. (Migrations should be squashed _only_ in preparation for a new minor release.)
```
git checkout -B squash-migrations
```
### 2. Delete Existing Squash Files
Delete the most recent squash file within each NetBox app. This allows us to extend squash files where the opportunity exists. For example, we might be able to replace `0005_to_0008` with `0005_to_0011`.
### 3. Generate the Current Migration Plan
Use Django's `showmigrations` utility to display the order in which all migrations would be applied for a new installation.
```
manage.py showmigrations --plan
```
From the resulting output, delete all lines which reference an external migration. Any migrations imposed by Django itself on an external package are not relevant.
### 4. Create Squash Files
Begin iterating through the migration plan, looking for successive sets of migrations within an app. These are candidates for squashing. For example:
Migrations `0014` through `0019` in `extras` can be squashed, as can migrations `0062` through `0065` in `dcim`. Migration `0066` cannot be included in the same squash file, because the `circuits` migration must be applied before it. (Note that whether or not each migration is currently applied to the database does not matter.)
Squash files are created using Django's `squashmigrations` utility:
```
manage.py squashmigrations <app> <start> <end>
```
For example, our first step in the example would be to run `manage.py squashmigrations extras 0014 0019`.
!!! note
Specifying a migration file's numeric index is enough to uniquely identify it within an app. There is no need to specify the full filename.
This will create a new squash file within the app's `migrations` directory, named as a concatenation of its beginning and ending migration. Some manual editing is necessary for each new squash file for housekeeping purposes:
* Remove the "automatically generated" comment at top (to indicate that a human has reviewed the file).
* Reorder `import` statements as necessary per PEP8.
* It may be necessary to copy over custom functions from the original migration files (this will be indicated by a comment near the top of the squash file). It is safe to remove any functions that exist solely to accomodate reverse migrations (which we no longer support).
Repeat this process for each candidate set of migrations until you reach the end of the migration plan.
### 5. Check for Missing Migrations
If everything went well, at this point we should have a completed squashed path. Perform a dry run to check for any missing migrations:
```
manage.py migrate --dry-run
```
### 5. Run Migrations
Next, we'll apply the entire migration path to an empty database. Begin by dropping and creating your development database.
!!! warning
Obviously, first back up any data you don't want to lose.
```
sudo -u postgres psql -c 'drop database netbox'
sudo -u postgres psql -c 'create database netbox'
```
Apply the migrations with the `migrate` management command. It is not necessary to specify a particular migration path; Django will detect and use the squashed migrations automatically. You can verify the exact migrations being applied by enabling verboes output with `-v 2`.
```
manage.py migrate -v 2
```
### 6. Commit the New Migrations
If everything is successful to this point, commit your changes to the `squash-migrations` branch.
### 7. Validate Resulting Schema
To ensure our new squashed migrations do not result in a deviation from the original schema, we'll compare the two. With the new migration file safely commit, check out the `develop-2.x` branch, which still contains only the individual migrations.
```
git checkout develop-2.x
```
Temporarily install the [django-extensions](https://django-extensions.readthedocs.io/) package, which provides the `sqldiff utility`:
```
pip install django-extensions
```
Also add `django_extensions` to `INSTALLED_APPS` in `netbox/netbox/settings.py`.
At this point, our database schema has been defined by using the squashed migrations. We can run `sqldiff` to see if it differs any from what the current (non-squashed) migrations would generate. `sqldiff` accepts a list of apps against which to run:
It is safe to ignore errors indicating an "unknown database type" for the following fields:
*`dcim_interface.mac_address`
*`ipam_aggregate.prefix`
*`ipam_prefix.prefix`
It is also safe to ignore the message "Table missing: extras_script".
Resolve any differences by correcting migration files in the `squash-migrations` branch.
!!! warning
Don't forget to remove `django_extension` from `INSTALLED_APPS` before committing your changes.
### 8. Merge the Squashed Migrations
Once all squashed migrations have been validated and all tests run successfully, merge the `squash-migrations` branch into `develop-2.x`. This completes the squashing process.
NetBox generally follows the [Django style guide](https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/), which is itself based on [PEP 8](https://www.python.org/dev/peps/pep-0008/). [Pycodestyle](https://github.com/pycqa/pycodestyle) is used to validate code formatting, ignoring certain violations. See `scripts/cibuild.sh`.
NetBox generally follows the [Django style guide](https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/), which is itself based on [PEP 8](https://www.python.org/dev/peps/pep-0008/). [Pycodestyle](https://github.com/pycqa/pycodestyle) is used to validate code formatting, ignoring certain violations. See `scripts/cibuild.sh` for details.
## PEP 8 Exceptions
* Wildcard imports (for example, `from .constants import *`) are acceptable under any of the following conditions:
* The library being import contains only constant declarations (`constants.py`)
* The library being imported explicitly defines `__all__` (e.g. `<app>.api.nested_serializers`)
* The library being import contains only constant declarations (e.g. `constants.py`)
* The library being imported explicitly defines `__all__`
* Maximum line length is 120 characters (E501)
* This does not apply to HTML templates or to automatically generated code (e.g. database migrations).
The introduction of a new dependency is best avoided unless it is absolutely necessary. For small features, it's generally preferable to replicate functionality within the NetBox code base rather than to introduce reliance on an external project. This reduces both the burden of tracking new releases and our exposure to outside bugs and attacks.
The introduction of a new dependency is best avoided unless it is absolutely necessary. For small features, it's generally preferable to replicate functionality within the NetBox code base rather than to introduce reliance on an external project. This reduces both the burden of tracking new releases and our exposure to outside bugs and supply chain attacks.
If there's a strong case for introducing a new dependency, it must meet the following criteria:
@@ -43,9 +43,9 @@ When adding a new dependency, a short description of the package and the URL of
## General Guidance
* When in doubt, remain consistent: It is better to be consistently incorrect than inconsistently correct. If you notice in the course of unrelated work a pattern that should be corrected, continue to follow the pattern for now and open a bug so that the entire code base can be evaluated at a later point.
* When in doubt, remain consistent: It is better to be consistently incorrect than inconsistently correct. If you notice in the course of unrelated work a pattern that should be corrected, continue to follow the pattern for now and submit a separate bug report so that the entire code base can be evaluated at a later point.
* Prioritize readability over concision. Python is a very flexible language that typically gives us several options for expressing a given piece of logic, but some may be more friendly to the reader than others. (List comprehensions are particularly vulnerable to over-optimization.) Always remain considerate of the future reader who may need to interpret your code without the benefit of the context within which you are writing it.
* Prioritize readability over concision. Python is a very flexible language that typically offers several options for expressing a given piece of logic, but some may be more friendly to the reader than others. (List comprehensions are particularly vulnerable to over-optimization.) Always remain considerate of the future reader who may need to interpret your code without the benefit of the context within which you are writing it.
* No easter eggs. While they can be fun, NetBox must be considered as a business-critical tool. The potential, however minor, for introducing a bug caused by unnecessary logic is best avoided entirely.
The `users.UserConfig` model holds individual preferences for each user in the form of JSON data. This page serves as a manifest of all recognized user preferences in NetBox.
Utility views are reusable views that handle common CRUD tasks, such as listing and updating objects. Some views operate on individual objects, whereas others (referred to as "bulk" views) operate on multiple objects at once.
## Individual Views
### ObjectListView
Generates a paginated table of objects from a given queryset, which may optionally be filtered.
### ObjectEditView
Updates an object identified by a primary key (PK) or slug. If no existing object is specified, a new object will be created.
### ObjectDeleteView
Deletes an object. The user is redirected to a confirmation page before the deletion is executed.
## Bulk Views
### BulkCreateView
Creates multiple objects at once based on a given pattern. Currently used only for IP addresses.
### BulkImportView
Accepts CSV-formatted data and creates a new object for each line. Creation is all-or-none.
### BulkEditView
Applies changes to multiple objects at once in a two-step operation. First, the list of PKs for selected objects is POSTed and an edit form is presented to the user. On submission of that form, the specified changes are made to all selected objects.
### BulkDeleteView
Deletes multiple objects. The user selects the objects to be deleted and confirms the deletion.
## Component Views
### ComponentCreateView
Create one or more component objects beloning to a parent object (e.g. interfaces attached to a device).
### ComponentEditView
A subclass of `ObjectEditView`: Updates an individual component object.
### ComponentDeleteView
A subclass of `ObjectDeleteView`: Deletes an individual component object.
### BulkComponentCreateView
Create a set of components objects for each of a selected set of parent objects. This view can be used e.g. to create multiple interfaces on multiple devices at once.
The NetBox UI is built on languages and frameworks:
### Styling & HTML Elements
#### [Bootstrap](https://getbootstrap.com/) 5
The majority of the NetBox UI is made up of stock Bootstrap components, with some styling modifications and custom components added on an as-needed basis. Bootstrap uses [Sass](https://sass-lang.com/), and NetBox extends Bootstrap's core Sass files for theming and customization.
All client-side scripting is transpiled from TypeScript to JavaScript and served by Django. In development, TypeScript is an _extremely_ effective tool for accurately describing and checking the code, which leads to significantly fewer bugs, a better development experience, and more predictable/readable code.
As part of the [bundling](#bundling) process, Bootstrap's JavaScript plugins are imported and bundled alongside NetBox's front-end code.
!!! danger "NetBox is jQuery-free"
Following the Bootstrap team's deprecation of jQuery in Bootstrap 5, NetBox also no longer uses jQuery in front-end code.
## Guidance
NetBox generally follows the following guidelines for front-end code:
- Bootstrap utility classes may be used to solve one-off issues or to implement singular components, as long as the class list does not exceed 4-5 classes. If an element needs more than 5 utility classes, a custom SCSS class should be added that contains the required style properties.
- Custom classes must be commented, explaining the general purpose of the class and where it is used.
- Reuse SCSS variables whenever possible. CSS values should (almost) never be hard-coded.
- All TypeScript functions must have, at a minimum, a basic [JSDoc](https://jsdoc.app/) description of what the function is for and where it is used. If possible, document all function arguments via [`@param` JSDoc block tags](https://jsdoc.app/tags-param.html).
- Expanding on NetBox's [dependency policy](style-guide.md#introducing-new-dependencies), new front-end dependencies should be avoided unless absolutely necessary. Every new front-end dependency adds to the CSS/JavaScript file size that must be loaded by the client and this should be minimized as much as possible. If adding a new dependency is unavoidable, use a tool like [Bundlephobia](https://bundlephobia.com/) to ensure the smallest possible library is used.
- All UI elements must be usable on all common screen sizes, including mobile devices. Be sure to test newly implemented solutions (JavaScript included) on as many screen sizes and device types as possible.
- NetBox aligns with Bootstrap's [supported Browsers and Devices](https://getbootstrap.com/docs/5.1/getting-started/browsers-devices/) list.
## UI Development
To contribute to the NetBox UI, you'll need to review the main [Getting Started guide](getting-started.md) in order to set up your base environment.
### Tools
Once you have a working NetBox development environment, you'll need to install a few more tools to work with the NetBox UI:
- [NodeJS](https://nodejs.org/en/download/) (the LTS release should suffice)
After Node and Yarn are installed on your system, you'll need to install all the NetBox UI dependencies:
```console
$cd netbox/project-static
$ yarn
```
!!! warning "Check Your Working Directory"
You need to be in the `netbox/project-static` directory to run the below `yarn` commands.
### Bundling
In order for the TypeScript and Sass (SCSS) source files to be usable by a browser, they must first be transpiled (TypeScript → JavaScript, Sass → CSS), bundled, and minified. After making changes to TypeScript or Sass source files, run `yarn bundle`.
`yarn bundle` is a wrapper around the following subcommands, any of which can be run individually:
All output files will be written to `netbox/project-static/dist`, where Django will pick them up when `manage.py collectstatic` is run.
!!! info "Remember to re-run `manage.py collectstatic`"
If you're running the development web server — `manage.py runserver` — you'll need to run `manage.py collectstatic` to see your changes.
### Linting, Formatting & Type Checking
Before committing any changes to TypeScript files, and periodically throughout the development process, you should run `yarn validate` to catch formatting, code quality, or type errors.
!!! tip "IDE Integrations"
If you're using an IDE, it is strongly recommended to install [ESLint](https://eslint.org/docs/user-guide/integrations), [TypeScript](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support), and [Prettier](https://prettier.io/docs/en/editors.html) integrations, if available. Most of them will automatically check and/or correct issues in the code as you develop, which can significantly increase your productivity as a contributor.
`yarn validate` is a wrapper around the following subcommands, any of which can be run individually:
NetBox provides a read-only [GraphQL](https://graphql.org/) API to complement its REST API. This API is powered by the [Graphene](https://graphene-python.org/) library and [Graphene-Django](https://docs.graphene-python.org/projects/django/en/latest/).
## Queries
GraphQL enables the client to specify an arbitrary nested list of fields to include in the response. All queries are made to the root `/graphql` API endpoint. For example, to return the circuit ID and provider name of each circuit with an active status, you can issue a request such as the following:
The response will include the requested data formatted as JSON:
```json
{
"data":{
"circuits":[
{
"cid":"1002840283",
"provider":{
"name":"CenturyLink"
}
},
{
"cid":"1002840457",
"provider":{
"name":"CenturyLink"
}
}
]
}
}
```
!!! note
It's recommended to pass the return data through a JSON parser such as `jq` for better readability.
NetBox provides both a singular and plural query field for each object type:
*`$OBJECT`: Returns a single object. Must specify the object's unique ID as `(id: 123)`.
*`$OBJECT_list`: Returns a list of objects, optionally filtered by given parameters.
For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of filters) to fetch all devices.
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/).
## Filtering
The GraphQL API employs the same filtering logic as the UI and REST API. Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only sites within the North Carolina region with a status of active:
NetBox's GraphQL API uses the same API authentication tokens as its REST API. Authentication tokens are included with requests by attaching an `Authorization` HTTP header in the following form:
```
Authorization: Token $TOKEN
```
## Disabling the GraphQL API
If not needed, the GraphQL API can be disabled by setting the [`GRAPHQL_ENABLED`](../configuration/dynamic-settings.md#graphql_enabled) configuration parameter to False and restarting NetBox.
NetBox is an open source web application designed to help manage and document computer networks. 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. It encompasses the following aspects of network management:
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:
* **IP address management (IPAM)** - IP networks and addresses, VRFs, and VLANs
* **Equipment racks** - Organized by group and site
@@ -10,7 +10,6 @@ NetBox is an open source web application designed to help manage and document co
* **Connections** - Network, console, and power connections among devices
* **Virtualization** - Virtual machines and clusters
* **Data circuits** - Long-haul communications circuits and providers
* **Secrets** - Encrypted storage of sensitive credentials
## What NetBox Is Not
@@ -49,14 +48,16 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and
| HTTP service | nginx or Apache |
| WSGI service | gunicorn or uWSGI |
| Application | Django/Python |
| Database | PostgreSQL 9.4+ |
| Database | PostgreSQL 10+ |
| Task queuing | Redis/django-rq |
| Live device access | NAPALM |
| Live device access | NAPALM (optional) |
## Supported Python Versions
NetBox supports Python 3.5, 3.6, and 3.7 environments currently. Python 3.5 is scheduled to be unsupported in NetBox v2.8.
NetBox supports Python 3.8, 3.9, and 3.10 environments.
## Getting Started
See the [installation guide](installation/index.md) for help getting NetBox up and running quickly.
Minor NetBox releases (e.g. v3.1) are published three times a year; in April, August, and December. These typically introduce major new features and may contain breaking API changes. Patch releases are published roughly every one to two weeks to resolve bugs and fulfill minor feature requests. These are backward-compatible with previous releases unless otherwise noted. The NetBox maintainers strongly recommend running the latest stable release whenever possible.
Please see the [official installation guide](installation/index.md) for detailed instructions on obtaining and installing NetBox.
This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md).
!!! warning
NetBox requires PostgreSQL 9.4 or higher. Please note that MySQL and other relational databases are **not** supported.
The installation instructions provided here have been tested to work on Ubuntu 18.04 and CentOS 7.5. The particular commands needed to install dependencies on other distributions may vary significantly. Unfortunately, this is outside the control of the NetBox maintainers. Please consult your distribution's documentation for assistance with any errors.
!!! warning "PostgreSQL 10 or later required"
NetBox requires PostgreSQL 10 or later. Please note that MySQL and other relational databases are **not** supported.
## Installation
#### Ubuntu
=== "Ubuntu"
If a recent enough version of PostgreSQL is not available through your distribution's package manager, you'll need to install it from an official [PostgreSQL repository](https://wiki.postgresql.org/wiki/Apt).
```no-highlight
sudo apt update
sudo apt install -y postgresql
```
=== "CentOS"
```no-highlight
sudo yum install -y postgresql-server
sudo postgresql-setup --initdb
```
CentOS configures ident host-based authentication for PostgreSQL by default. Because NetBox will need to authenticate using a username and password, modify `/var/lib/pgsql/data/pg_hba.conf` to support MD5 authentication by changing `ident` to `md5` for the lines below:
```no-highlight
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
```
Once PostgreSQL has been installed, start the service and enable it to run at boot:
```no-highlight
# apt-get update
# apt-get install -y postgresql libpq-dev
sudo systemctl start postgresql
sudo systemctl enable postgresql
```
#### CentOS
CentOS 7.5 does not ship with a recent enough version of PostgreSQL, so it will need to be installed from an external repository. The instructions below show the installation of PostgreSQL 9.6.
Before continuing, verify that you have installed PostgreSQL 10 or later:
CentOS users should modify the PostgreSQL configuration to accept password-based authentication by replacing `ident` with `md5` for all host entries within `/var/lib/pgsql/9.6/data/pg_hba.conf`. For example:
```no-highlight
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
```
Then, start the service and enable it to run at boot:
```no-highlight
# systemctl start postgresql-9.6
# systemctl enable postgresql-9.6
psql -V
```
## Database Creation
At a minimum, we need to create a database for NetBox and assign it a username and password for authentication. This is done with the following commands.
!!! danger
DO NOT USE THE PASSWORD FROM THE EXAMPLE.
At a minimum, we need to create a database for NetBox and assign it a username and password for authentication. Start by invoking the PostgreSQL shell as the system Postgres user.
```no-highlight
# sudo -u postgres psql
psql (9.4.5)
Type "help" for help.
postgres=# CREATE DATABASE netbox;
CREATE DATABASE
postgres=# CREATE USER netbox WITH PASSWORD 'J5brHrAXFLQSif0K';
CREATE ROLE
postgres=# GRANT ALL PRIVILEGES ON DATABASE netbox TO netbox;
GRANT
postgres=# \q
sudo -u postgres psql
```
Within the shell, enter the following commands to create the database and user (role), substituting your own value for the password:
```postgresql
CREATE DATABASE netbox;
CREATE USER netbox WITH PASSWORD 'J5brHrAXFLQSif0K';
GRANT ALL PRIVILEGES ON DATABASE netbox TO netbox;
```
!!! danger "Use a strong password"
**Do not use the password from the example.** Choose a strong, random password to ensure secure database authentication for your NetBox installation.
Once complete, enter `\q` to exit the PostgreSQL shell.
## Verify Service Status
You can verify that authentication works issuing the following command and providing the configured password. (Replace `localhost` with your database server if using a remote database.)
You can verify that authentication works by executing the `psql` command and passing the configured username and password. (Replace `localhost` with your database server if using a remote database.)
[Redis](https://redis.io/) is an in-memory key-value store which NetBox employs for caching and queuing. This section entails the installation and configuration of a local Redis instance. If you already have a Redis service in place, skip to [the next section](3-netbox.md).
### Ubuntu
!!! warning "Redis v4.0 or later required"
NetBox v2.9.0 and later require Redis v4.0 or higher. If your distribution does not offer a recent enough release, you will need to build Redis from source. Please see [the Redis installation documentation](https://github.com/redis/redis) for further details.
=== "Ubuntu"
```no-highlight
sudo apt install -y redis-server
```
=== "CentOS"
```no-highlight
sudo yum install -y redis
sudo systemctl start redis
sudo systemctl enable redis
```
Before continuing, verify that your installed version of Redis is at least v4.0:
```no-highlight
# apt-get install -y redis-server
```
### CentOS
```no-highlight
# yum install -y epel-release
# yum install -y redis
# systemctl start redis
# systemctl enable redis
redis-server -v
```
You may wish to modify the Redis configuration at `/etc/redis.conf` or `/etc/redis/redis.conf`, however in most cases the default configuration is sufficient.
@@ -26,6 +34,7 @@ You may wish to modify the Redis configuration at `/etc/redis.conf` or `/etc/red
Use the `redis-cli` utility to ensure the Redis service is functional:
```no-highlight
$ redis-cli ping
PONG
redis-cli ping
```
If successful, you should receive a `PONG` response from the server.
This section of the documentation discusses installing and configuring the NetBox application. Begin by installing all system packages required by NetBox and its dependencies:
This section of the documentation discusses installing and configuring the NetBox application itself.
## Install System Packages
### Ubuntu
Begin by installing all system packages required by NetBox and its dependencies.
You may opt to install NetBox either from a numbered release or by cloning the master branch of its repository on GitHub.
This documentation provides two options for installing NetBox: from a downloadable archive, or from the git repository. Installing from a package (option A below) requires manually fetching and extracting the archive for every future update, whereas installation via git (option B) allows for seamless upgrades by re-pulling the `master` branch.
### Option A: Download a Release
### Option A: Download a Release Archive
Download the [latest stable release](https://github.com/netbox-community/netbox/releases) from GitHub as a tarball or ZIP archive and extract it to your desired path. In this example, we'll use `/opt/netbox`.
Download the [latest stable release](https://github.com/netbox-community/netbox/releases) from GitHub as a tarball or ZIP archive and extract it to your desired path. In this example, we'll use `/opt/netbox` as the NetBox root.
It is recommended to install NetBox in a directory named for its version number. For example, NetBox v3.0.0 would be installed into `/opt/netbox-3.0.0`, and a symlink from `/opt/netbox/` would point to this location. (You can verify this configuration with the command `ls -l /opt | grep netbox`.) This allows for future releases to be installed in parallel without interrupting the current installation. When changing to the new release, only the symlink needs to be updated.
### Option B: Clone the Git Repository
Create the base directory for the NetBox installation. For this guide, we'll use `/opt/netbox`.
```no-highlight
# mkdir -p /opt/netbox/ && cd /opt/netbox/
sudo mkdir -p /opt/netbox/
cd /opt/netbox/
```
If `git` is not already installed, install it:
#### Ubuntu
=== "Ubuntu"
```no-highlight
sudo apt install -y git
```
=== "CentOS"
```no-highlight
sudo yum install -y git
```
Next, clone the **master** branch of the NetBox GitHub repository into the current directory. (This branch always holds the current stable release.)
Create a system user account named `netbox`. We'll configure the WSGI and HTTP services to run under this account. We'll also assign this user ownership of the media directory. This ensures that NetBox will be able to save local files.
!!! note
CentOS users may need to create the `netbox` group first.
The `git clone` command above utilizes a "shallow clone" to retrieve only the most recent commit. If you need to download the entire history, omit the `--depth 1` argument.
The `git clone` command should generate output similar to the following:
Installation via git also allows you to easily try out different versions of NetBox. To check out a [specific NetBox release](https://github.com/netbox-community/netbox/releases), use the `git checkout` command with the desired release tag. For example, `git checkout v3.0.8`.
We'll use a Python [virtual environment](https://docs.python.org/3.6/tutorial/venv.html) to ensure NetBox's required packages don't conflict with anything in the base system. This will create a directory named `venv` in our NetBox root.
## Create the NetBox System User
```no-highlight
# python3 -m venv /opt/netbox/venv
```
Create a system user account named `netbox`. We'll configure the WSGI and HTTP services to run under this account. We'll also assign this user ownership of the media directory. This ensures that NetBox will be able to save uploaded files.
Next, activate the virtual environment and install the required Python packages. You should see your console prompt change to indicate the active environment. (Activating the virtual environment updates your command shell to use the local copy of Python that we just installed for NetBox instead of the system's Python interpreter.)
NetBox supports integration with the [NAPALM automation](https://napalm-automation.net/) library. NAPALM allows NetBox to fetch live data from devices and return it to a requester via its REST API. Installation of NAPALM is optional. To enable it, install the `napalm` package:
```no-highlight
(venv) # pip3 install napalm
```
To ensure NAPALM is automatically re-installed during future upgrades, create a file named `local_requirements.txt` in the NetBox root directory (alongside `requirements.txt`) and list the `napalm` package:
```no-highlight
# echo napalm >> local_requirements.txt
```
### Remote File Storage (Optional)
By default, NetBox will use the local filesystem to storage uploaded files. To use a remote filesystem, install the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) library and configure your [desired backend](../../configuration/optional-settings/#storage_backend) in `configuration.py`.
```no-highlight
(venv) # pip3 install django-storages
```
Don't forget to add the `django-storages` package to `local_requirements.txt` to ensure it gets re-installed during future upgrades:
Move into the NetBox configuration directory and make a copy of `configuration.example.py` named `configuration.py`.
Move into the NetBox configuration directory and make a copy of `configuration_example.py` named `configuration.py`. This file will hold all of your local configuration parameters.
Open `configuration.py` with your preferred editor and set the following variables:
Open `configuration.py` with your preferred editor to begin configuring NetBox. NetBox offers [many configuration parameters](../configuration/index.md), but only the following four are required for new installations:
* `ALLOWED_HOSTS`
* `DATABASE`
@@ -141,19 +128,21 @@ Open `configuration.py` with your preferred editor and set the following variabl
### ALLOWED_HOSTS
This is a list of the valid hostnames by which this server can be reached. You must specify at least one name or IP address.
Example:
This is a list of the valid hostnames and IP addresses by which this server can be reached. You must specify at least one name or IP address. (Note that this does not restrict the locations from which NetBox may be accessed: It is merely for [HTTP host header validation](https://docs.djangoproject.com/en/3.0/topics/security/#host-headers-virtual-hosting).)
If you are not yet sure what the domain name and/or IP address of the NetBox installation will be, you can set this to a wildcard (asterisk) to allow all host values:
```python
ALLOWED_HOSTS = ['*']
```
### DATABASE
This parameter holds the database configuration details. You must define the username and password used when you configured PostgreSQL. If the service is running on a remote host, replace `localhost` with its address. See the [configuration documentation](../../configuration/required-settings/#database) for more detail on individual parameters.
Example:
This parameter holds the database configuration details. You must define the username and password used when you configured PostgreSQL. If the service is running on a remote host, update the `HOST` and `PORT` parameters accordingly. See the [configuration documentation](../configuration/required-settings.md#database) for more detail on individual parameters.
'PORT': '', # Database port (leave blank for default)
'CONN_MAX_AGE': 300, # Max database connection age
'CONN_MAX_AGE': 300, # Max database connection age (seconds)
}
```
### REDIS
Redis is a in-memory key-value store required as part of the NetBox installation. It is used for features such as webhooks and caching. Redis typically requires minimal configuration; the values below should suffice for most installations. See the [configuration documentation](../../configuration/required-settings/#redis) for more detail on individual parameters.
Redis is a in-memory key-value store used by NetBox for caching and background task queuing. Redis typically requires minimal configuration; the values below should suffice for most installations. See the [configuration documentation](../configuration/required-settings.md#redis) for more detail on individual parameters.
Note that NetBox requires the specification of two separate Redis databases: `tasks` and `caching`. These may both be provided by the same Redis service, however each should have a unique numeric database ID.
```python
REDIS = {
'webhooks': {
'HOST': 'redis.example.com',
'PORT': 1234,
'PASSWORD': 'foobar',
'DATABASE': 0,
'DEFAULT_TIMEOUT': 300,
'SSL': False,
'tasks': {
'HOST': 'localhost', # Redis server
'PORT': 6379, # Redis port
'PASSWORD': '', # Redis password (optional)
'DATABASE': 0, # Database ID
'SSL': False, # Use SSL (optional)
},
'caching': {
'HOST': 'localhost',
'PORT': 6379,
'PASSWORD': '',
'DATABASE': 1,
'DEFAULT_TIMEOUT': 300,
'DATABASE': 1, # Unique ID for second database
'SSL': False,
}
}
@@ -193,77 +182,125 @@ REDIS = {
### SECRET_KEY
Generate a random secret key of at least 50 alphanumeric characters. This key must be unique to this installation and must not be shared outside the local system.
This parameter must be assigned a randomly-generated key employed as a salt for hashing and related cryptographic functions. (Note, however, that it is _never_ directly used in the encryption of secret data.) This key must be unique to this installation and is recommended to be at least 50 characters long. It should not be shared outside the local system.
You may use the script located at `netbox/generate_secret_key.py` to generate a suitable key.
!!! note
In the case of a highly available installation with multiple web servers, `SECRET_KEY` must be identical among all servers in order to maintain a persistent user session state.
## Run Database Migrations
Before NetBox can run, we need to install the database schema. This is done by running `python3 manage.py migrate` from the `netbox` directory (`/opt/netbox/netbox/` in our example):
A simple Python script named `generate_secret_key.py` is provided in the parent directory to assist in generating a suitable key:
If this step results in a PostgreSQL authentication error, ensure that the username and password created in the database match what has been specified in `configuration.py`
!!! warning "SECRET_KEY values must match"
In the case of a highly available installation with multiple web servers, `SECRET_KEY` must be identical among all servers in order to maintain a persistent user session state.
When you have finished modifying the configuration, remember to save the file.
## Optional Requirements
All Python packages required by NetBox are listed in `requirements.txt` and will be installed automatically. NetBox also supports some optional packages. If desired, these packages must be listed in `local_requirements.txt` within the NetBox root directory.
### NAPALM
Integration with the [NAPALM automation](../additional-features/napalm.md) library allows NetBox to fetch live data from devices and return it to a requester via its REST API. The `NAPALM_USERNAME` and `NAPALM_PASSWORD` configuration parameters define the credentials to be used when connecting to a device.
```no-highlight
sudo sh -c "echo 'napalm' >> /opt/netbox/local_requirements.txt"
```
### Remote File Storage
By default, NetBox will use the local filesystem to store uploaded files. To use a remote filesystem, install the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) library and configure your [desired storage backend](../configuration/optional-settings.md#storage_backend) in `configuration.py`.
```no-highlight
sudo sh -c "echo 'django-storages' >> /opt/netbox/local_requirements.txt"
```
## Run the Upgrade Script
Once NetBox has been configured, we're ready to proceed with the actual installation. We'll run the packaged upgrade script (`upgrade.sh`) to perform the following actions:
* Create a Python virtual environment
* Installs all required Python packages
* Run database schema migrations
* Builds the documentation locally (for offline use)
* Aggregate static resource files on disk
```no-highlight
sudo /opt/netbox/upgrade.sh
```
Note that **Python 3.8 or later is required** for NetBox v3.2 and later releases. If the default Python installation on your server is set to a lesser version, pass the path to the supported installation as an environment variable named `PYTHON`. (Note that the environment variable must be passed _after_ the `sudo` command.)
Upon completion, the upgrade script may warn that no existing virtual environment was detected. As this is a new installation, this warning can be safely ignored.
## Create a Super User
NetBox does not come with any predefined user accounts. You'll need to create a super user to be able to log into NetBox:
NetBox does not come with any predefined user accounts. You'll need to create a super user (administrative account) to be able to log into NetBox. First, enter the Python virtual environment created by the upgrade script:
```no-highlight
(venv) # python3 manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.
source /opt/netbox/venv/bin/activate
```
## Collect Static Files
Once the virtual environment has been activated, you should notice the string `(venv)` prepended to your console prompt.
Next, we'll create a superuser account using the `createsuperuser` Django management command (via `manage.py`). Specifying an email address for the user is not required, but be sure to use a very strong password.
959 static files copied to '/opt/netbox/netbox/static'.
cd /opt/netbox/netbox
python3 manage.py createsuperuser
```
## Schedule the Housekeeping Task
NetBox includes a `housekeeping` management command that handles some recurring cleanup tasks, such as clearing out old sessions and expired change records. Although this command may be run manually, it is recommended to configure a scheduled job using the system's `cron` daemon or a similar utility.
A shell script which invokes this command is included at `contrib/netbox-housekeeping.sh`. It can be copied to or linked from your system's daily cron task directory, or included within the crontab directly. (If installing NetBox into a nonstandard path, be sure to update the system paths within this script first.)
If successful, you should see output similar to the following:
```no-highlight
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
November 28, 2018 - 09:33:45
Django version 2.0.9, using settings 'netbox.settings'
Starting development server at http://0.0.0.0:8000/
August 30, 2021 - 18:02:23
Django version 3.2.6, using settings 'netbox.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```
Next, connect to the name or IP of the server (as defined in `ALLOWED_HOSTS`) on port 8000; for example, <http://127.0.0.1:8000/>. You should be greeted with the NetBox home page. Note that this built-in web service is for development and testing purposes only. **It is not suited for production use.**
Next, connect to the name or IP of the server (as defined in `ALLOWED_HOSTS`) on port 8000; for example, <http://127.0.0.1:8000/>. You should be greeted with the NetBox home page. Try logging in using the username and password specified when creating a superuser.
!!! note
By default RHEL based distros will likely block your testing attempts with firewalld. The development server port can be opened with `firewall-cmd` (add `--permanent` if you want the rule to survive server restarts):
```no-highlight
firewall-cmd --zone=public --add-port=8000/tcp
```
!!! danger "Not for production use"
The development server is for development and testing purposes only. It is neither performant nor secure enough for production use. **Do not use it in production.**
!!! warning
If the test service does not run, or you cannot reach the NetBox home page, something has gone wrong. Do not proceed with the rest of this guide until the installation has been corrected.
Note that the initial UI will be locked down for non-authenticated users.

After logging in as the superuser you created earlier, all areas of the UI will be available.

Like most Django applications, NetBox runs as a [WSGI application](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface) behind an HTTP server. This documentation shows how to install and configure [gunicorn](http://gunicorn.org/) (which is automatically installed with NetBox) for this role, however other WSGI servers are available and should work similarly well. [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) is a popular alternative.
## Configuration
NetBox ships with a default configuration file for gunicorn. To use it, copy `/opt/netbox/contrib/gunicorn.py` to `/opt/netbox/gunicorn.py`. (We make a copy of this file rather than pointing to it directly to ensure that any local changes to it do not get overwritten by a future upgrade.)
While the provided configuration should suffice for most initial installations, you may wish to edit this file to change the bound IP address and/or port number, or to make performance-related adjustments. See [the Gunicorn documentation](https://docs.gunicorn.org/en/stable/configure.html) for the available configuration parameters.
## systemd Setup
We'll use systemd to control both gunicorn and NetBox's background worker process. First, copy `contrib/netbox.service` and `contrib/netbox-rq.service` to the `/etc/systemd/system/` directory and reload the systemd daemon:
We'll set up a simple WSGI front end using [gunicorn](http://gunicorn.org/) for the purposes of this guide. For web servers, we provide example configurations for both [nginx](https://www.nginx.com/resources/wiki/) and [Apache](http://httpd.apache.org/docs/2.4). (You are of course free to use whichever combination of HTTP and WSGI services you'd like.) We'll use systemd to enable service persistence.
!!! info
For the sake of brevity, only Ubuntu 18.04 instructions are provided here, but this sort of web server and WSGI configuration is not unique to NetBox. Please consult your distribution's documentation for assistance if needed.
## HTTP Daemon Installation
### Option A: nginx
The following will serve as a minimal nginx configuration. Be sure to modify your server name and installation path appropriately.
```no-highlight
# apt-get install -y nginx
```
Once nginx is installed, save the following configuration to `/etc/nginx/sites-available/netbox`. Be sure to replace `netbox.example.com` with the domain name or IP address of your installation. (This should match the value configured for `ALLOWED_HOSTS` in `configuration.py`.)
```nginx
server {
listen 80;
server_name netbox.example.com;
client_max_body_size 25m;
location /static/ {
alias /opt/netbox/netbox/static/;
}
location / {
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;
}
}
```
Then, delete `/etc/nginx/sites-enabled/default` and create a symlink in the `sites-enabled` directory to the configuration file you just created.
```no-highlight
# cd /etc/nginx/sites-enabled/
# rm default
# ln -s /etc/nginx/sites-available/netbox
```
Restart the nginx service to use the new configuration.
```no-highlight
# service nginx restart
```
To enable SSL, consider this guide on [securing nginx with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04).
Once Apache is installed, proceed with the following configuration (Be sure to modify the `ServerName` appropriately):
```apache
<VirtualHost *:80>
ProxyPreserveHost On
ServerName netbox.example.com
Alias /static /opt/netbox/netbox/static
# Needed to allow token-based API authentication
WSGIPassAuthorization on
<Directory /opt/netbox/netbox/static>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Require all granted
</Directory>
<Location /static>
ProxyPass !
</Location>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
ProxyPass / http://127.0.0.1:8001/
ProxyPassReverse / http://127.0.0.1:8001/
</VirtualHost>
```
Save the contents of the above example in `/etc/apache2/sites-available/netbox.conf`, enable the `proxy` and `proxy_http` modules, and reload Apache:
```no-highlight
# a2enmod proxy
# a2enmod proxy_http
# a2enmod headers
# a2ensite netbox
# service apache2 restart
```
To enable SSL, consider this guide on [securing Apache with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04).
!!! note
Certain components of NetBox (such as the display of rack elevation diagrams) rely on the use of embedded objects. Ensure that your HTTP server configuration does not override the `X-Frame-Options` response header set by NetBox.
## gunicorn Configuration
Copy `/opt/netbox/contrib/gunicorn.py` to `/opt/netbox/gunicorn.py`. (We make a copy of this file to ensure that any changes to it do not get overwritten by a future upgrade.)
```no-highlight
# cd /opt/netbox
# cp contrib/gunicorn.py /opt/netbox/gunicorn.py
```
You may wish to edit this file to change the bound IP address or port number, or to make performance-related adjustments.
## systemd Configuration
We'll use systemd to control the daemonization of NetBox services. First, copy `contrib/netbox.service` and `contrib/netbox-rq.service` to the `/etc/systemd/system/` directory:
```no-highlight
# cp contrib/*.service /etc/systemd/system/
```
Then, start the `netbox` and `netbox-rq` services and enable them to initiate at boot time:
```no-highlight
# systemctl daemon-reload
# systemctl start netbox netbox-rq
# systemctl enable netbox netbox-rq
```
You can use the command `systemctl status netbox` to verify that the WSGI service is running:
At this point, you should be able to connect to the HTTP service at the server name or IP address you provided.
!!! info
Please keep in mind that the configurations provided here are bare minimums required to get NetBox up and running. You may want to make adjustments to better suit your production environment.
## Troubleshooting
If you are unable to connect to the HTTP server, check that:
* Nginx/Apache is running and configured to listen on the correct port.
* Access is not being blocked by a firewall. (Try connecting locally from the server itself.)
If you are able to connect but receive a 502 (bad gateway) error, check the following:
* The NetBox system process (gunicorn) is running: `systemctl status netbox`
* nginx/Apache is configured to connect to the port on which gunicorn is listening (default is 8001).
* SELinux is not preventing the reverse proxy connection. You may need to allow HTTP network connections with the command `setsebool -P httpd_can_network_connect 1`
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.