mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge branch 'develop' into develop-2.10
This commit is contained in:
@ -93,6 +93,10 @@ appropriate labels will be applied for categorization.
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
* If you're interested in contributing to NetBox, be sure to check out our
|
||||
[getting started](https://netbox.readthedocs.io/en/stable/development/getting-started/)
|
||||
documentation for tips on setting up your development environment.
|
||||
|
||||
* Be sure to open an issue **before** starting work on a pull request, and
|
||||
discuss your idea with the NetBox maintainers before beginning work. This will
|
||||
help prevent wasting time on something that might we might not be able to
|
||||
|
@ -277,7 +277,7 @@ The lifetime (in seconds) of the authentication cookie issued to a NetBox user u
|
||||
|
||||
Default: False
|
||||
|
||||
Setting this to True will display a "maintenance mode" banner at the top of every page.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
# Application Registry
|
||||
|
||||
The registry is an in-memory data structure which houses various miscellaneous application-wide parameters, such as installed plugins. It is not exposed to the user and is not intended to be modified by any code outside of NetBox core.
|
||||
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, me modified; e.g. by appending a value to a list. Store values generally do not change once the application has been initialized.
|
||||
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
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# Extending Models
|
||||
|
||||
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.
|
||||
|
||||
@ -14,18 +14,18 @@ Django migrations are used to express changes to the database schema. In most ca
|
||||
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.
|
||||
|
||||
!!! note
|
||||
Migrations can only be merged within a release. Once a new release has been published, its migrations cannot be altered.
|
||||
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:
|
||||
@ -38,7 +38,7 @@ Add the name of the new field to `csv_headers` and included a CSV-friendly repre
|
||||
|
||||
## 4. Update relevant querysets
|
||||
|
||||
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.
|
||||
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 extraneous database queries.
|
||||
|
||||
## 5. Update API serializer
|
||||
|
||||
@ -49,7 +49,7 @@ Extend the model's API serializer in `<app>.api.serializers` to include the new
|
||||
Extend any forms to include the new field as appropriate. 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)
|
||||
|
||||
@ -59,7 +59,7 @@ If the new field should be filterable, add it to the `FilterSet` for the model.
|
||||
|
||||
## 8. 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.
|
||||
|
||||
## 9. Update the UI templates
|
||||
|
||||
@ -76,3 +76,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.
|
||||
|
||||
## 11. 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.
|
||||
|
140
docs/development/getting-started.md
Normal file
140
docs/development/getting-started.md
Normal file
@ -0,0 +1,140 @@
|
||||
# Getting Started
|
||||
|
||||
## Setting up a Development Environment
|
||||
|
||||
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/)
|
||||
* A Redis server, which can also be [installed locally](/installation/2-redis/)
|
||||
* 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.) You can then clone your GitHub fork locally for development:
|
||||
|
||||
```no-highlight
|
||||
$ git clone https://github.com/youruseraccount/netbox.git
|
||||
Cloning into 'netbox'...
|
||||
remote: Enumerating objects: 231, done.
|
||||
remote: Counting objects: 100% (231/231), done.
|
||||
remote: Compressing objects: 100% (147/147), done.
|
||||
remote: Total 56705 (delta 134), reused 145 (delta 84), pack-reused 56474
|
||||
Receiving objects: 100% (56705/56705), 27.96 MiB | 34.92 MiB/s, done.
|
||||
Resolving deltas: 100% (44177/44177), done.
|
||||
$ ls netbox/
|
||||
base_requirements.txt contrib docs mkdocs.yml NOTICE requirements.txt upgrade.sh
|
||||
CHANGELOG.md CONTRIBUTING.md LICENSE.txt netbox README.md scripts
|
||||
```
|
||||
|
||||
The NetBox project utilizes three long-term branches:
|
||||
|
||||
* `master` - Serves as a snapshot of the current stable release
|
||||
* `develop` - All development on the upcoming stable release occurs here
|
||||
* `develop-x.y` - Tracks work on an upcoming major release
|
||||
|
||||
Typically, you'll base pull requests off of the `develop` branch, or off of `develop-x.y` if you're working on a new major release. **Never** base pull requests off of the master branch, which receives merged only from the `develop` branch.
|
||||
|
||||
### 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) is like a container for a set of Python packages. They 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
|
||||
Keeping virtual environments in `~/.venv/` is a common convention but entirely optional: Virtual environments can be created wherever you please.
|
||||
|
||||
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:
|
||||
|
||||
```no-highlight
|
||||
(netbox) $ python -m pip install -r requirements.txt
|
||||
Collecting Django==3.1 (from -r requirements.txt (line 1))
|
||||
Cache entry deserialization failed, entry ignored
|
||||
Using cached https://files.pythonhosted.org/packages/2b/5a/4bd5624546912082a1bd2709d0edc0685f5c7827a278d806a20cf6adea28/Django-3.1-py3-none-any.whl
|
||||
...
|
||||
```
|
||||
|
||||
### Configure NetBox
|
||||
|
||||
Within the `netbox/netbox/` directory, copy `configuration.example.py` to `configuration.py` and update the following parameters:
|
||||
|
||||
* `ALLOWED_HOSTS`: This can be set to `['*']` for development purposes
|
||||
* `DATABASE`: PostgreSQL database connection parameters
|
||||
* `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. NetBox extends this slightly to automatically import models and other utilities. Run the NetBox development server with the `nbshell` management command:
|
||||
|
||||
```no-highlight
|
||||
$ python netbox/manage.py runserver
|
||||
Performing system checks...
|
||||
|
||||
System check identified no issues (0 silenced).
|
||||
November 18, 2020 - 15:52:31
|
||||
Django version 3.1, 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.
|
||||
|
||||
## Running Tests
|
||||
|
||||
Throughout the course of development, it's a good idea to occasionally run NetBox's test suite to catch any potential errors. Tests are run using the `test` management command:
|
||||
|
||||
```no-highlight
|
||||
$ python netbox/manage.py test
|
||||
```
|
||||
|
||||
In cases where you haven't made any changes to the database (which is most of the time), 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 netbox/manage.py test --keepdb
|
||||
```
|
||||
|
||||
## 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 reference it.
|
||||
|
||||
```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, pull requests are entertained 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.
|
@ -18,7 +18,7 @@ NetBox follows the [benevolent dictator](http://oss-watch.ac.uk/resources/benevo
|
||||
|
||||
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.
|
||||
|
||||
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 functional subsections called _apps_ (a carryover from Django vernacular). Each app holds the models, views, and templates 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)
|
||||
@ -26,5 +26,6 @@ NetBox components are arranged into functional subsections called _apps_ (a carr
|
||||
* `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
|
||||
|
@ -16,28 +16,24 @@ The other file is `requirements.txt`, which lists each of the required packages
|
||||
Every minor version 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
|
||||
* Material Design Icons
|
||||
* Select2
|
||||
* jQuery
|
||||
* jQuery UI
|
||||
|
||||
### Create a new Release Notes Page
|
||||
### Link to the 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`, and point `index.md` to the new file.
|
||||
Add the release notes (`/docs/release-notes/X.Y.md`) to the table of contents within `mkdocs.yml`, and point `index.md` to the new file.
|
||||
|
||||
### Manually Perform a New Install
|
||||
|
||||
@ -52,7 +48,14 @@ Follow these instructions to perform a new installation of NetBox. This process
|
||||
|
||||
### Close the Release Milestone
|
||||
|
||||
Close the release milestone on GitHub. Ensure that there are no remaining open issues associated with it.
|
||||
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 release branch `develop-x.y` into the `develop` branch in preparation for its releases.
|
||||
|
||||
!!! warning
|
||||
No further releases for the current major version can be published once this pull request is merged.
|
||||
|
||||
---
|
||||
|
||||
@ -64,11 +67,11 @@ 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 and annotate the current data in the release notes for the new version. 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.
|
||||
|
||||
@ -76,16 +79,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'
|
||||
```
|
||||
|
@ -5,8 +5,8 @@ NetBox generally follows the [Django style guide](https://docs.djangoproject.com
|
||||
## 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).
|
||||
@ -45,7 +45,7 @@ When adding a new dependency, a short description of the package and the URL of
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
|
@ -8,4 +8,4 @@ The `users.UserConfig` model holds individual preferences for each user in the f
|
||||
| ---- | ----------- |
|
||||
| extras.configcontext.format | Preferred format when rendering config context data (JSON or YAML) |
|
||||
| pagination.per_page | The number of items to display per page of a paginated table |
|
||||
| tables.${table_name}.columns | The ordered list of columns to display when viewing the table |
|
||||
| tables.TABLE_NAME.columns | The ordered list of columns to display when viewing the table |
|
||||
|
@ -1,57 +0,0 @@
|
||||
# Utility Views
|
||||
|
||||
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
|
||||
|
||||
### ObjectView
|
||||
|
||||
Retrieve and display a single object.
|
||||
|
||||
### 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.
|
@ -1,16 +1,21 @@
|
||||
# NetBox v2.9
|
||||
|
||||
## v2.9.10 (FUTURE)
|
||||
## v2.9.10 (2020-11-24)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [#5319](https://github.com/netbox-community/netbox/issues/5319) - Add USB types for power ports and outlets
|
||||
* [#5337](https://github.com/netbox-community/netbox/issues/5337) - Add "splice" type for pass-through ports
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#5235](https://github.com/netbox-community/netbox/issues/5235) - Fix exception when editing IP address with a NAT IP assigned to a non-racked device
|
||||
* [#5309](https://github.com/netbox-community/netbox/issues/5309) - Avoid extraneous database queries when manipulating objects
|
||||
* [#5345](https://github.com/netbox-community/netbox/issues/5345) - Fix non-deterministic ordering of prefixes and IP addresses
|
||||
* [#5350](https://github.com/netbox-community/netbox/issues/5350) - Filter available racks by selected group when creating a rack reservation
|
||||
* [#5355](https://github.com/netbox-community/netbox/issues/5355) - Limit rack groups by selected site when editing a rack
|
||||
* [#5356](https://github.com/netbox-community/netbox/issues/5356) - Populate manufacturer field when adding a device component template
|
||||
* [#5360](https://github.com/netbox-community/netbox/issues/5360) - Clear VLAN assignments when setting interface mode to none
|
||||
|
||||
---
|
||||
|
||||
|
@ -68,8 +68,8 @@ nav:
|
||||
- Working with Secrets: 'rest-api/working-with-secrets.md'
|
||||
- Development:
|
||||
- Introduction: 'development/index.md'
|
||||
- Getting Started: 'development/getting-started.md'
|
||||
- Style Guide: 'development/style-guide.md'
|
||||
- Utility Views: 'development/utility-views.md'
|
||||
- Extending Models: 'development/extending-models.md'
|
||||
- Application Registry: 'development/application-registry.md'
|
||||
- User Preferences: 'development/user-preferences.md'
|
||||
|
@ -304,6 +304,16 @@ class PowerPortTypeChoices(ChoiceSet):
|
||||
TYPE_ITA_M = 'ita-m'
|
||||
TYPE_ITA_N = 'ita-n'
|
||||
TYPE_ITA_O = 'ita-o'
|
||||
# USB
|
||||
TYPE_USB_A = 'usb-a'
|
||||
TYPE_USB_B = 'usb-b'
|
||||
TYPE_USB_C = 'usb-c'
|
||||
TYPE_USB_MINI_A = 'usb-mini-a'
|
||||
TYPE_USB_MINI_B = 'usb-mini-b'
|
||||
TYPE_USB_MICRO_A = 'usb-micro-a'
|
||||
TYPE_USB_MICRO_B = 'usb-micro-b'
|
||||
TYPE_USB_3_B = 'usb-3-b'
|
||||
TYPE_USB_3_MICROB = 'usb-3-micro-b'
|
||||
|
||||
CHOICES = (
|
||||
('IEC 60320', (
|
||||
@ -393,6 +403,17 @@ class PowerPortTypeChoices(ChoiceSet):
|
||||
(TYPE_ITA_N, 'ITA Type N'),
|
||||
(TYPE_ITA_O, 'ITA Type O'),
|
||||
)),
|
||||
('USB', (
|
||||
(TYPE_USB_A, 'USB Type A'),
|
||||
(TYPE_USB_B, 'USB Type B'),
|
||||
(TYPE_USB_C, 'USB Type C'),
|
||||
(TYPE_USB_MINI_A, 'USB Mini A'),
|
||||
(TYPE_USB_MINI_B, 'USB Mini B'),
|
||||
(TYPE_USB_MICRO_A, 'USB Micro A'),
|
||||
(TYPE_USB_MICRO_B, 'USB Micro B'),
|
||||
(TYPE_USB_3_B, 'USB 3.0 Type B'),
|
||||
(TYPE_USB_3_MICROB, 'USB 3.0 Micro B'),
|
||||
)),
|
||||
)
|
||||
|
||||
|
||||
@ -482,6 +503,10 @@ class PowerOutletTypeChoices(ChoiceSet):
|
||||
TYPE_ITA_M = 'ita-m'
|
||||
TYPE_ITA_N = 'ita-n'
|
||||
TYPE_ITA_O = 'ita-o'
|
||||
# USB
|
||||
TYPE_USB_A = 'usb-a'
|
||||
TYPE_USB_MICROB = 'usb-micro-b'
|
||||
TYPE_USB_C = 'usb-c'
|
||||
# Proprietary
|
||||
TYPE_HDOT_CX = 'hdot-cx'
|
||||
|
||||
@ -572,6 +597,11 @@ class PowerOutletTypeChoices(ChoiceSet):
|
||||
(TYPE_ITA_N, 'ITA Type N'),
|
||||
(TYPE_ITA_O, 'ITA Type O'),
|
||||
)),
|
||||
('USB', (
|
||||
(TYPE_USB_A, 'USB Type A'),
|
||||
(TYPE_USB_MICROB, 'USB Micro B'),
|
||||
(TYPE_USB_C, 'USB Type C'),
|
||||
)),
|
||||
('Proprietary', (
|
||||
(TYPE_HDOT_CX, 'HDOT Cx'),
|
||||
)),
|
||||
|
@ -470,6 +470,13 @@ class RackForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
'region_id': '$region'
|
||||
}
|
||||
)
|
||||
group = DynamicModelChoiceField(
|
||||
queryset=RackGroup.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'site_id': '$site'
|
||||
}
|
||||
)
|
||||
role = DynamicModelChoiceField(
|
||||
queryset=RackRole.objects.all(),
|
||||
required=False
|
||||
@ -1027,7 +1034,10 @@ class ComponentTemplateCreateForm(ComponentForm):
|
||||
"""
|
||||
manufacturer = DynamicModelChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
initial_params={
|
||||
'device_types': 'device_type'
|
||||
}
|
||||
)
|
||||
device_type = DynamicModelChoiceField(
|
||||
queryset=DeviceType.objects.all(),
|
||||
|
@ -464,6 +464,18 @@ class BaseInterface(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
# Remove untagged VLAN assignment for non-802.1Q interfaces
|
||||
if not self.mode:
|
||||
self.untagged_vlan = None
|
||||
|
||||
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
|
||||
if self.pk and self.mode != InterfaceModeChoices.MODE_TAGGED:
|
||||
self.tagged_vlans.clear()
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
@extras_features('export_templates', 'webhooks')
|
||||
class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
||||
@ -580,18 +592,6 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
||||
"device, or it must be global".format(self.untagged_vlan)
|
||||
})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
# Remove untagged VLAN assignment for non-802.1Q interfaces
|
||||
if self.mode is None:
|
||||
self.untagged_vlan = None
|
||||
|
||||
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
|
||||
if self.pk and self.mode != InterfaceModeChoices.MODE_TAGGED:
|
||||
self.tagged_vlans.clear()
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self.device
|
||||
|
@ -5,10 +5,10 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from django_rq import get_queue
|
||||
|
||||
from extras.models import Webhook
|
||||
from utilities.api import get_serializer_for_model
|
||||
from .choices import *
|
||||
from .utils import FeatureQuery
|
||||
from .models import Webhook
|
||||
from .registry import registry
|
||||
|
||||
|
||||
def generate_signature(request_body, secret):
|
||||
@ -28,13 +28,14 @@ def enqueue_webhooks(instance, user, request_id, action):
|
||||
Find Webhook(s) assigned to this instance + action and enqueue them
|
||||
to be processed
|
||||
"""
|
||||
obj_type = ContentType.objects.get_for_model(instance.__class__)
|
||||
|
||||
webhook_models = ContentType.objects.filter(FeatureQuery('webhooks').get_query())
|
||||
if obj_type not in webhook_models:
|
||||
# Determine whether this type of object supports webhooks
|
||||
app_label = instance._meta.app_label
|
||||
model_name = instance._meta.model_name
|
||||
if model_name not in registry['model_features']['webhooks'].get(app_label, []):
|
||||
return
|
||||
|
||||
# Retrieve any applicable Webhooks
|
||||
obj_type = ContentType.objects.get_for_model(instance)
|
||||
action_flag = {
|
||||
ObjectChangeActionChoices.ACTION_CREATE: 'type_create',
|
||||
ObjectChangeActionChoices.ACTION_UPDATE: 'type_update',
|
||||
|
@ -453,18 +453,6 @@ class VMInterface(BaseInterface):
|
||||
"virtual machine, or it must be global".format(self.untagged_vlan)
|
||||
})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
# Remove untagged VLAN assignment for non-802.1Q interfaces
|
||||
if self.mode is None:
|
||||
self.untagged_vlan = None
|
||||
|
||||
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
|
||||
if self.pk and self.mode != InterfaceModeChoices.MODE_TAGGED:
|
||||
self.tagged_vlans.clear()
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def to_objectchange(self, action):
|
||||
# Annotate the parent VirtualMachine
|
||||
return ObjectChange(
|
||||
|
Reference in New Issue
Block a user