Skip to content

Commit a3f7dc0

Browse files
Merge pull request #16072 from netbox-community/develop
Release v4.0.1
2 parents 91f156d + ab62f41 commit a3f7dc0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+299
-173
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ body:
2626
attributes:
2727
label: NetBox Version
2828
description: What version of NetBox are you currently running?
29-
placeholder: v4.0.0
29+
placeholder: v4.0.1
3030
validations:
3131
required: true
3232
- type: dropdown
3333
attributes:
3434
label: Python Version
3535
description: What version of Python are you currently running?
3636
options:
37-
- "3.8"
38-
- "3.9"
3937
- "3.10"
4038
- "3.11"
39+
- "3.12"
4140
validations:
4241
required: true
4342
- type: textarea

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ body:
1414
attributes:
1515
label: NetBox version
1616
description: What version of NetBox are you currently running?
17-
placeholder: v4.0.0
17+
placeholder: v4.0.1
1818
validations:
1919
required: true
2020
- type: dropdown

contrib/generated_schema.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@
353353
"800gbase-x-qsfpdd",
354354
"800gbase-x-osfp",
355355
"1000base-kx",
356+
"2.5gbase-kx",
357+
"5gbase-kr",
356358
"10gbase-kr",
357359
"10gbase-kx4",
358360
"25gbase-kr",

contrib/uwsgi.ini

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,24 @@ master = true
1111
; clear environment on exit
1212
vacuum = true
1313

14+
; make SIGTERM stop the app (instead of reload)
15+
die-on-term = true
16+
1417
; exit if no app can be loaded
1518
need-app = true
1619

1720
; do not use multiple interpreters
1821
single-interpreter = true
22+
23+
; change to the project directory
24+
chdir = netbox
25+
26+
; specify the WSGI module to load
27+
module = netbox.wsgi
28+
29+
; workaround to make uWSGI reloads work with pyuwsgi (not to be used if using uwsgi package instead)
30+
binary-path = venv/bin/python
31+
32+
; only log internal messages and errors (reverse proxy already logs the requests)
33+
disable-logging = true
34+
log-5xx = true

docs/development/adding-models.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Create the following for each model:
7777

7878
## 13. GraphQL API components
7979

80-
Create a Graphene object type for the model in `graphql/types.py` by subclassing the appropriate class from `netbox.graphql.types`.
80+
Create a GraphQL object type for the model in `graphql/types.py` by subclassing the appropriate class from `netbox.graphql.types`.
8181

8282
Also extend the schema class defined in `graphql/schema.py` with the individual object and object list fields per the established convention.
8383

docs/development/release-checklist.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ In cases where upgrading a dependency to its most recent release is breaking, it
7272

7373
### Update UI Dependencies
7474

75-
Check whether any UI dependencies (JavaScript packages, fonts, etc.) need to be updated by running `yarn outdated` from within the `project-static/` directory. [Upgrade these dependencies](http://0.0.0.0:9000/development/web-ui/#updating-dependencies) as necessary, then run `yarn bundle` to generate the necessary files for distribution.
75+
Check whether any UI dependencies (JavaScript packages, fonts, etc.) need to be updated by running `yarn outdated` from within the `project-static/` directory. [Upgrade these dependencies](./web-ui.md#updating-dependencies) as necessary, then run `yarn bundle` to generate the necessary files for distribution.
7676

7777
### Rebuild the Device Type Definition Schema
7878

docs/installation/4b-uwsgi.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pip3 install pyuwsgi
1717
Once installed, add the package to `local_requirements.txt` to ensure it is re-installed during future rebuilds of the virtual environment:
1818

1919
```no-highlight
20-
sudo sh -c "echo 'pyuwgsi' >> /opt/netbox/local_requirements.txt"
20+
sudo sh -c "echo 'pyuwsgi' >> /opt/netbox/local_requirements.txt"
2121
```
2222

2323
## Configuration

docs/integrations/graphql-api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GraphQL API Overview
22

3-
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/).
3+
NetBox provides a read-only [GraphQL](https://graphql.org/) API to complement its REST API. This API is powered by [Strawberry Django](https://strawberry-graphql.github.io/strawberry-django/).
44

55
## Queries
66

@@ -47,7 +47,7 @@ NetBox provides both a singular and plural query field for each object type:
4747

4848
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.
4949

50-
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/) as well as the [GraphQL queries documentation](https://graphql.org/learn/queries/).
50+
For more detail on constructing GraphQL queries, see the [GraphQL queries documentation](https://graphql.org/learn/queries/). For filtering and lookup syntax, please refer to the [Strawberry Django documentation](https://strawberry-graphql.github.io/strawberry-django/guide/filters/).
5151

5252
## Filtering
5353

docs/plugins/development/graphql-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Defining the Schema Class
44

5-
A plugin can extend NetBox's GraphQL API by registering its own schema class. By default, NetBox will attempt to import `graphql.schema` from the plugin, if it exists. This path can be overridden by defining `graphql_schema` on the PluginConfig instance as the dotted path to the desired Python class. This class must be a subclass of `graphene.ObjectType`.
5+
A plugin can extend NetBox's GraphQL API by registering its own schema class. By default, NetBox will attempt to import `graphql.schema` from the plugin, if it exists. This path can be overridden by defining `graphql_schema` on the PluginConfig instance as the dotted path to the desired Python class.
66

77
### Example
88

docs/plugins/development/index.md

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,20 @@ project-name/
5555
- template_content.py
5656
- urls.py
5757
- views.py
58+
- pyproject.toml
5859
- README.md
59-
- setup.py
6060
```
6161

6262
The top level is the project root, which can have any name that you like. Immediately within the root should exist several items:
6363

64-
* `setup.py` - This is a standard installation script used to install the plugin package within the Python environment.
64+
* `pyproject.toml` - is a standard configuration file used to install the plugin package within the Python environment.
6565
* `README.md` - A brief introduction to your plugin, how to install and configure it, where to find help, and any other pertinent information. It is recommended to write `README` files using a markup language such as Markdown to enable human-friendly display.
6666
* The plugin source directory. This must be a valid Python package name, typically comprising only lowercase letters, numbers, and underscores.
6767

6868
The plugin source directory contains all the actual Python code and other resources used by your plugin. Its structure is left to the author's discretion, however it is recommended to follow best practices as outlined in the [Django documentation](https://docs.djangoproject.com/en/stable/intro/reusable-apps/). At a minimum, this directory **must** contain an `__init__.py` file containing an instance of NetBox's `PluginConfig` class, discussed below.
6969

70+
**Note:** The [Cookiecutter NetBox Plugin](https://github.com/netbox-community/cookiecutter-netbox-plugin) can be used to auto-generate all the needed directories and files for a new plugin.
71+
7072
## PluginConfig
7173

7274
The `PluginConfig` class is a NetBox-specific wrapper around Django's built-in [`AppConfig`](https://docs.djangoproject.com/en/stable/ref/applications/) class. It is used to declare NetBox plugin functionality within a Python package. Each plugin should provide its own subclass, defining its name, metadata, and default and required configuration parameters. An example is below:
@@ -136,31 +138,48 @@ Apps from this list are inserted *before* the plugin's `PluginConfig` in the ord
136138

137139
Any additional apps must be installed within the same Python environment as NetBox or `ImproperlyConfigured` exceptions will be raised when loading the plugin.
138140

139-
## Create setup.py
141+
## Create pyproject.toml
140142

141-
`setup.py` is the [setup script](https://docs.python.org/3.10/distutils/setupscript.html) used to package and install our plugin once it's finished. The primary function of this script is to call the setuptools library's `setup()` function to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. An example `setup.py` is below:
143+
`pyproject.toml` is the [configuration file](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) used to package and install our plugin once it's finished. It is used by packaging tools, as well as other tools. The primary function of this file is to call the build system to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. There are three possible TOML tables in this file:
144+
145+
* `[build-system]` allows you to declare which build backend you use and which other dependencies (if any) are needed to build your project.
146+
* `[project]` is the format that most build backends use to specify your project’s basic metadata, such as the author's name, project URL, etc.
147+
* `[tool]` has tool-specific subtables, e.g., `[tool.black]`, `[tool.mypy]`. Consult the particular tool’s documentation for reference.
148+
149+
An example `pyproject.toml` is below:
142150

143-
```python
144-
from setuptools import find_packages, setup
145-
146-
setup(
147-
name='my-example-plugin',
148-
version='0.1',
149-
description='An example NetBox plugin',
150-
url='https://github.com/jeremystretch/my-example-plugin',
151-
author='Jeremy Stretch',
152-
license='Apache 2.0',
153-
install_requires=[],
154-
packages=find_packages(),
155-
include_package_data=True,
156-
zip_safe=False,
157-
)
158151
```
152+
# See PEP 518 for the spec of this file
153+
# https://www.python.org/dev/peps/pep-0518/
154+
155+
[build-system]
156+
requires = ["setuptools"]
157+
build-backend = "setuptools.build_meta"
158+
159+
[project]
160+
name = "my-example-plugin"
161+
version = "0.1.0"
162+
authors = [
163+
{name = "John Doe", email = "[email protected]"},
164+
]
165+
description = "An example NetBox plugin."
166+
readme = "README.md"
167+
168+
classifiers=[
169+
'Development Status :: 3 - Alpha',
170+
'Intended Audience :: Developers',
171+
'Natural Language :: English',
172+
"Programming Language :: Python :: 3 :: Only",
173+
'Programming Language :: Python :: 3.10',
174+
'Programming Language :: Python :: 3.11',
175+
'Programming Language :: Python :: 3.12',
176+
]
159177
160-
Many of these are self-explanatory, but for more information, see the [setuptools documentation](https://setuptools.readthedocs.io/en/latest/setuptools.html).
178+
requires-python = ">=3.10.0"
179+
180+
```
161181

162-
!!! info
163-
`zip_safe=False` is **required** as the current plugin iteration is not zip safe due to upstream python issue [issue19699](https://bugs.python.org/issue19699)
182+
Many of these are self-explanatory, but for more information, see the [pyproject.toml documentation](https://packaging.python.org/en/latest/specifications/pyproject-toml/).
164183

165184
## Create a Virtual Environment
166185

@@ -178,11 +197,12 @@ echo /opt/netbox/netbox > $VENV/lib/python3.10/site-packages/netbox.pth
178197

179198
## Development Installation
180199

181-
To ease development, it is recommended to go ahead and install the plugin at this point using setuptools' `develop` mode. This will create symbolic links within your Python environment to the plugin development directory. Call `setup.py` from the plugin's root directory with the `develop` argument (instead of `install`):
200+
To ease development, it is recommended to go ahead and install the plugin at this point using setuptools' `develop` mode. This will create symbolic links within your Python environment to the plugin development directory. Call `pip` from the plugin's root directory with the `-e` flag:
182201

183202
```no-highlight
184-
$ python setup.py develop
203+
$ pip install -e .
185204
```
205+
More information on editable builds can be found at [Editable installs for pyproject.toml ](https://peps.python.org/pep-0660/).
186206

187207
## Configure NetBox
188208

docs/release-notes/version-4.0.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# NetBox v4.0
22

3+
## v4.0.1 (2024-05-09)
4+
5+
### Enhancements
6+
7+
* [#15148](https://github.com/netbox-community/netbox/issues/15148) - Add copy-to-clipboard button for config context data
8+
* [#15328](https://github.com/netbox-community/netbox/issues/15328) - Add a virtual machines UI tab for host devices
9+
* [#15451](https://github.com/netbox-community/netbox/issues/15451) - Add 2.5 and 5 Gbps backplane Ethernet interface types
10+
* [#16010](https://github.com/netbox-community/netbox/issues/16010) - Enable Prometheus middleware only if metrics are enabled
11+
12+
### Bug Fixes
13+
14+
* [#15968](https://github.com/netbox-community/netbox/issues/15968) - Avoid resizing quick search field to display clear button
15+
* [#15973](https://github.com/netbox-community/netbox/issues/15973) - Fix AttributeError exception when modifying cable termination type
16+
* [#15977](https://github.com/netbox-community/netbox/issues/15977) - Hide all admin menu items for non-authenticated users
17+
* [#15982](https://github.com/netbox-community/netbox/issues/15982) - Restore the "assign IP" tab for assigning existing IP addresses to interfaces
18+
* [#15992](https://github.com/netbox-community/netbox/issues/15992) - Fix AttributeError exception when Sentry integration is enabled
19+
* [#15995](https://github.com/netbox-community/netbox/issues/15995) - Permit nullable fields referenced by unique constraints to be omitted from REST API requests
20+
* [#15999](https://github.com/netbox-community/netbox/issues/15999) - Fix layout of login form labels for certain languages
21+
* [#16003](https://github.com/netbox-community/netbox/issues/16003) - Enable cache busting for `setmode.js` asset to avoid breaking dark mode support on upgrade
22+
* [#16011](https://github.com/netbox-community/netbox/issues/16011) - Fix site tenant assignment by PK via REST API
23+
* [#16020](https://github.com/netbox-community/netbox/issues/16020) - Include Python version in system UI view
24+
* [#16022](https://github.com/netbox-community/netbox/issues/16022) - Fix database migration failure when encountering a script module which no longer exists on disk
25+
* [#16025](https://github.com/netbox-community/netbox/issues/16025) - Fix execution of scripts via the `runscript` management command
26+
* [#16031](https://github.com/netbox-community/netbox/issues/16031) - Render Markdown content in script log messages
27+
* [#16051](https://github.com/netbox-community/netbox/issues/16051) - Translate "empty" text for object tables
28+
* [#16061](https://github.com/netbox-community/netbox/issues/16061) - Omit hidden fields from display within event rule edit form
29+
30+
---
31+
332
## v4.0.0 (2024-05-06)
433

534
!!! tip "Plugin Maintainers"

netbox/circuits/api/serializers_/circuits.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class Meta:
4848
class CircuitSerializer(NetBoxModelSerializer):
4949
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
5050
provider = ProviderSerializer(nested=True)
51-
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True)
51+
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
5252
status = ChoiceField(choices=CircuitStatusChoices, required=False)
5353
type = CircuitTypeSerializer(nested=True)
5454
tenant = TenantSerializer(nested=True, required=False, allow_null=True)

netbox/circuits/api/serializers_/providers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Meta:
4545
class ProviderAccountSerializer(NetBoxModelSerializer):
4646
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provideraccount-detail')
4747
provider = ProviderSerializer(nested=True)
48+
name = serializers.CharField(allow_blank=True, max_length=100, required=False, default='')
4849

4950
class Meta:
5051
model = ProviderAccount

netbox/circuits/tests/test_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def setUpTestData(cls):
141141
{
142142
'cid': 'Circuit 6',
143143
'provider': providers[1].pk,
144-
'provider_account': provider_accounts[1].pk,
144+
# Omit provider account to test uniqueness constraint
145145
'type': circuit_types[1].pk,
146146
},
147147
]
@@ -237,7 +237,7 @@ def setUpTestData(cls):
237237
'account': '5678',
238238
},
239239
{
240-
'name': 'Provider Account 6',
240+
# Omit name to test uniqueness constraint
241241
'provider': providers[0].pk,
242242
'account': '6789',
243243
},

netbox/dcim/api/serializers_/devices.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def get_config_context(self, obj):
122122
class VirtualDeviceContextSerializer(NetBoxModelSerializer):
123123
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
124124
device = DeviceSerializer(nested=True)
125+
identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None)
125126
tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None)
126127
primary_ip = IPAddressSerializer(nested=True, read_only=True, allow_null=True)
127128
primary_ip4 = IPAddressSerializer(nested=True, required=False, allow_null=True)

netbox/dcim/api/serializers_/sites.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class SiteSerializer(NetBoxModelSerializer):
5151
status = ChoiceField(choices=SiteStatusChoices, required=False)
5252
region = RegionSerializer(nested=True, required=False, allow_null=True)
5353
group = SiteGroupSerializer(nested=True, required=False, allow_null=True)
54-
tenant = TenantSerializer(required=False, allow_null=True)
54+
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
5555
time_zone = TimeZoneSerializerField(required=False, allow_null=True)
5656
asns = SerializedPKRelatedField(
5757
queryset=ASN.objects.all(),
@@ -83,7 +83,7 @@ class Meta:
8383
class LocationSerializer(NestedGroupModelSerializer):
8484
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
8585
site = SiteSerializer(nested=True)
86-
parent = NestedLocationSerializer(required=False, allow_null=True)
86+
parent = NestedLocationSerializer(required=False, allow_null=True, default=None)
8787
status = ChoiceField(choices=LocationStatusChoices, required=False)
8888
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
8989
rack_count = serializers.IntegerField(read_only=True)

netbox/dcim/choices.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,8 @@ class InterfaceTypeChoices(ChoiceSet):
848848

849849
# Ethernet Backplane
850850
TYPE_1GE_KX = '1000base-kx'
851+
TYPE_2GE_KX = '2.5gbase-kx'
852+
TYPE_5GE_KR = '5gbase-kr'
851853
TYPE_10GE_KR = '10gbase-kr'
852854
TYPE_10GE_KX4 = '10gbase-kx4'
853855
TYPE_25GE_KR = '25gbase-kr'
@@ -1008,6 +1010,8 @@ class InterfaceTypeChoices(ChoiceSet):
10081010
_('Ethernet (backplane)'),
10091011
(
10101012
(TYPE_1GE_KX, '1000BASE-KX (1GE)'),
1013+
(TYPE_2GE_KX, '2.5GBASE-KX (2.5GE)'),
1014+
(TYPE_5GE_KR, '5GBASE-KR (5GE)'),
10111015
(TYPE_10GE_KR, '10GBASE-KR (10GE)'),
10121016
(TYPE_10GE_KX4, '10GBASE-KX4 (10GE)'),
10131017
(TYPE_25GE_KR, '25GBASE-KR (25GE)'),

0 commit comments

Comments
 (0)