Files
Netbox-Utilities/README.md
T
MrBlakeandClaude Opus 5.5 cbb8128385 fix: downscale oversized bulk uploads so NetBox can render thumbnails
NetBox renders image attachment thumbnails under its global 25 MP Pillow
limit, so 50 MP photos uploaded via the bulk form showed no preview.
Scale images above that limit down (applying EXIF orientation) before
saving. Also resolve leftover merge conflict markers in the README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:19:19 +02:00

438 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NetBox Utilities
A collection of quality-of-life improvements for NetBox: personalised navigation,
a global tenant filter, mandatory tenancy, partial-width rack devices, bulk
uploads and more.
| | |
|---|---|
| **Plugin name** | `netbox_utilities` |
| **Package** | `netbox-utilities` |
| **NetBox** | `4.6.5` – `4.7.x` |
| **Python** | `>=3.12` |
| **Repository** | <https://git.mrblake.cc/MrBlake/Netbox-Utilities> |
## Features
- Every user can reorder or hide the menus of the left navigation.
- A header dropdown sets a session-wide filter for a tenant or tenant group.
- Optional mandatory tenant assignment for all tenant-aware objects.
- Automatic pre-fill of tenant and tenant group from the object or filter context.
- Automatic 1:1 mapping of front and rear ports on devices with the role `Patchpanel`.
- Devices with an optional partial width can share the same rack unit.
- The rack view of the optional [MrBlake NetBox Topology Views](https://git.mrblake.cc/MrBlake/mrb-netbox-topology-views) plugin renders partial-width devices correctly.
- Upload multiple images at once in an object's **Images** tab.
- Install multiple modules of the same type into free module bays in one step.
- Optional bulk save for devices moved in NetBox Reorder Rack.
- Rack widths are preserved by the optional [NetBox-Export](https://git.mrblake.cc/MrBlake/NetBox-Export) export/import.
- Cables and wireless links can be assigned to one or more VLANs.
- The B-side device selection of a cable can be pre-filtered by tenant group, tenant and site.
- A **Prefix** column (first word of the site name) for device and rack lists, including sorting and filtering.
Navigation settings are stored per user. The active tenant or tenant-group
selection is stored in the browser session.
## Compatibility
- NetBox `4.6.5` – `4.7.x`
- Python `>=3.12`
- Optional: NetBox Reorder Rack `1.1.4`
- Optional: NetBox-Export `0.3.11` or newer
- Optional: MrBlake NetBox Topology Views with rack view
Other NetBox versions are rejected on purpose, because the navigation
customisation depends on the HTML structure of the NetBox core menu.
## Installation
All paths assume a standard installation under `/opt/netbox`.
### 1. Install the package
```bash
/opt/netbox/venv/bin/pip install --upgrade --force-reinstall \
"git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@main"
```
For reproducible production installs, replace `main` with a release tag or a
full commit ID.
### 2. Add the plugin to `local_requirements.txt`
This makes `upgrade.sh` reinstall the plugin automatically on every NetBox upgrade:
```bash
grep -qxF "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@main" /opt/netbox/local_requirements.txt \
|| echo "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@main" | sudo tee -a /opt/netbox/local_requirements.txt
```
If the repository is private, the NetBox server needs a read-only deploy token
or an SSH key. Do not store credentials in `local_requirements.txt`. With SSH the
entry looks like this:
```text
git+ssh://git@git.mrblake.cc/MrBlake/Netbox-Utilities.git@main
```
### 3. Enable the plugin
In `/opt/netbox/netbox/netbox/configuration.py`:
```python
PLUGINS = [
"netbox_utilities",
]
PLUGINS_CONFIG = {
"netbox_utilities": {
"navigation_customization_enabled": True,
"connection_vlans_enabled": True,
"connection_tenant_filter_enabled": True,
"reorder_rack_bulk_save_enabled": True,
"topology_views_rack_width_enabled": True,
"tenant_filter_enabled": True,
"tenant_required": True,
"site_prefix_column_enabled": True,
},
}
```
If other plugins are already configured, add `netbox_utilities` to the existing
list and dictionary instead of replacing them.
### 4. Apply migrations, collect static files, restart
```bash
cd /opt/netbox/netbox
/opt/netbox/venv/bin/python manage.py migrate netbox_utilities
/opt/netbox/venv/bin/python manage.py collectstatic --no-input
sudo systemctl restart netbox netbox-rq
```
After changes to JavaScript or CSS a hard reload in the browser (`Ctrl+F5`) may
be necessary.
### Verify the installation
```bash
/opt/netbox/venv/bin/python -c \
"import netbox_utilities; print(netbox_utilities.__version__, netbox_utilities.__file__)"
test -f /opt/netbox/netbox/static/netbox_utilities/reorder-rack-width.js
test -f /opt/netbox/netbox/static/netbox_utilities/topology-rack-width.js
cd /opt/netbox/netbox
/opt/netbox/venv/bin/python manage.py shell -c \
"from django.urls import reverse; print(reverse('dcim:rack_reorder', kwargs={'pk': 1})); print(reverse('plugins:netbox_topology_views:rack_elevation'))"
```
The last two routes only resolve when Reorder Rack and Topology Views are installed.
## Update
```bash
/opt/netbox/venv/bin/pip install --upgrade --force-reinstall \
"git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@main"
cd /opt/netbox/netbox
/opt/netbox/venv/bin/python manage.py migrate netbox_utilities
/opt/netbox/venv/bin/python manage.py collectstatic --no-input
sudo systemctl restart netbox netbox-rq
```
`--force-reinstall` makes pip pick up branch changes even if the package
version has not been bumped.
When NetBox itself is upgraded, `upgrade.sh` reinstalls the plugin from
`local_requirements.txt` and runs migrations and `collectstatic`:
```bash
sudo /opt/netbox/upgrade.sh
sudo systemctl restart netbox netbox-rq
```
If you pinned a release tag in `local_requirements.txt`, change the tag there
before running the upgrade. Test updates in a staging instance and back up the
NetBox database first.
### Migrating from NetBox Site Prefix
The Prefix column is now part of NetBox Utilities. Remove the separate
`netbox_site_prefix` plugin, otherwise the column is registered twice:
1. Remove `"netbox_site_prefix"` from `PLUGINS` in `configuration.py`.
2. Remove `git+https://git.mrblake.cc/MrBlake/Netbox-Prefixes.git` from
`/opt/netbox/local_requirements.txt`.
3. Run `/opt/netbox/venv/bin/pip uninstall netbox-site-prefix` and restart NetBox.
The column name `site_prefix` is unchanged, so saved user table configurations keep working.
## Uninstall
1. Resolve all shared rack units first (see [Multiple devices in one rack unit](#multiple-devices-in-one-rack-unit)).
2. Remove `"netbox_utilities"` from `PLUGINS` and `PLUGINS_CONFIG`.
3. Remove the line from `/opt/netbox/local_requirements.txt`.
4. Uninstall the package and restart NetBox:
```bash
/opt/netbox/venv/bin/pip uninstall netbox-utilities
sudo systemctl restart netbox netbox-rq
```
## Configuration
| Key | Default | Description |
|---|---|---|
| `navigation_customization_enabled` | `True` | Per-user navigation ordering, hiding, resizing and icon mode |
| `connection_vlans_enabled` | `True` | VLAN assignment on cables and wireless links |
| `connection_tenant_filter_enabled` | `True` | Tenant group / tenant / site pre-filter on the cable B-side |
| `reorder_rack_bulk_save_enabled` | `True` | Bulk save integration for NetBox Reorder Rack `1.1.4` |
| `topology_views_rack_width_enabled` | `True` | Partial-width rendering in Topology Views' rack view |
| `tenant_filter_enabled` | `True` | Global tenant / tenant-group filter (overrides the UI setting) |
| `tenant_required` | `True` | Mandatory tenant assignment (overrides the UI setting) |
| `site_prefix_column_enabled` | `True` | Prefix column in device and rack lists |
## Usage
### Prefix column in device and rack lists
Device and rack lists get a **Prefix** column as the first data column. The
value is the first word of the site name, e.g. `Berlin` for `Berlin Campus West`
or `DC01` for `DC01 Frankfurt`. Without a site the cell stays empty.
Clicking the column header sorts ascending/descending by site name. If a user
has saved a custom column selection, add **Prefix** under **Configure Table**
or reset the table configuration.
Both lists offer a **Prefix** filter in the **Site** section. The comparison is
case-insensitive and only matches the first word: `DC01` matches
`DC01 Frankfurt` but not `DC011 Hamburg`. Separate multiple prefixes with commas
(`Berlin, DC01`). The filter also works via URL and REST API, e.g.
`/dcim/devices/?site_prefix=DC01` or
`/api/dcim/racks/?site_prefix=Berlin&site_prefix=DC01`.
### Pre-filter for the B-side of a cable
When creating or editing a cable, the **B-side** section shows optional
**Tenant group**, **Tenant** and **Site** fields above the device selection.
They filter the B-side dropdowns live (devices, power panels — site only — and
circuits).
The fields are pre-filled with the tenant and site of the selected A-side if
they are unambiguous, otherwise with the tenant or tenant group of the global
header filter.
This is only a **pre-filter**: the values are not stored on the cable. To cable
across tenants or sites, simply clear the field. The tenant filter uses the
device's own `tenant` field; devices whose tenant is only implied by their site
do not appear — use the site filter in that case.
### VLANs on connections
The create/edit form of cables and wireless links has an optional
**Connection VLANs** field. One or more existing VLANs can be selected; the
assignment is also shown on the connection's detail page.
It documents which VLANs are carried over the connection. It intentionally does
**not** change the **Untagged VLAN** / **Tagged VLANs** of the connected
interfaces, since both ends can use different interface modes.
- Applies to physical cables (including paths through patch panels) and `WirelessLink`s.
- In the cable form the field sits in the **B-side** section, below the B-side termination.
- An optional **VLAN group** field acts as a dynamic filter for the VLAN selection; it is not stored.
- Empty selections create no record; deleting a connection removes its VLAN assignment.
- With NetBox-Export installed, the assignments are exported and imported together with connections and VLANs.
### Multiple devices in one rack unit
The regular device create/edit form gets two optional fields right after **Position**:
- **Rack width**: full, half, third or quarter width;
- **Width position**: position 1 to 4, counted from the left.
Example: for a router and a second device in the same U, choose **1/2 rack width**
for both, give the router **Position 1 (left)** and the other device
**Position 2**. Rack, U and face may then be identical. Collision checks take
height and width into account; multi-U devices are supported. The width
position updates immediately when the rack width changes.
Without a width, a device occupies the full rack width as before. If two to
four devices already share a U and face without plugin placements, the display
splits the space evenly between them. This does not change database values.
NetBox enforces a unique constraint on rack, U and face. Plugin migration
`0007` removes only this core constraint so that multiple devices can share a U;
the plugin performs the width-aware check on save instead. **Before removing the
plugin, shared rack units must be resolved** — the constraint is not restored
automatically on uninstall.
The extra fields are maintained in the web form. REST or standard CSV
operations without these fields treat new devices as full width; the portable
ZIP export of NetBox-Export does transfer them.
### Rack widths in NetBox-Export
With [NetBox-Export](https://git.mrblake.cc/MrBlake/NetBox-Export) installed,
NetBox Utilities extends its ZIP export and import automatically. Rack width and
width position are stored for every device. The import conflict check considers
both height and horizontal rack space, so two half-width devices can be imported
into the same U. Full width is stored explicitly, so a device reset to full
width in a newer export loses its stale partial-width placement. Older archives
without these metadata remain importable.
### Partial widths in MrBlake NetBox Topology Views
If [MrBlake NetBox Topology Views](https://git.mrblake.cc/MrBlake/mrb-netbox-topology-views)
with its **rack view** is installed, NetBox Utilities detects it automatically.
Partial-width devices are rendered side by side, including the **SVG**, **PNG**
and **draw.io** exports. The cable topology is unchanged.
Both plugins must be enabled (order does not matter):
```python
PLUGINS = [
"netbox_topology_views",
"netbox_utilities",
]
```
The integration does not modify Topology Views' files and creates no database
records. Disable it with `topology_views_rack_width_enabled = False`.
### Automatic front/rear port mapping for patch panels
Devices whose role is named `Patchpanel` (case-insensitive) are treated as patch
panels. The plugin maps ports with the same number on port position 1:
`Front 1` ↔ `Rear 1`, `Front 2` ↔ `Rear 2`, and so on. Short forms such as
`F01` and `R1` and additional labels such as `LC` are recognised. If the
counterpart is missing, the port stays unmapped; following numbers do not shift.
The mapping is only created when a patch panel is first created, a new module
is installed, or a new front or rear port is created. Editing existing objects
does not trigger it, and there is no automatic run over existing data on
install or update.
### Moving multiple devices with NetBox Reorder Rack
With `netbox-reorder-rack` `1.1.4` installed and enabled, NetBox Utilities
extends its save action: several devices can be moved or swapped in the
drag-and-drop view and saved together via **Save**. Partial-width devices are
shown side by side on a 12-column grid and snap to valid positions; height,
face and width position are saved in one transaction.
```bash
/opt/netbox/venv/bin/pip install "netbox-reorder-rack==1.1.4"
echo "netbox-reorder-rack==1.1.4" | sudo tee -a /opt/netbox/local_requirements.txt
```
```python
PLUGINS = [
"netbox_reorder_rack",
"netbox_utilities",
]
```
Reorder Rack's files are not modified; its UI and API are extended at startup.
On save, all affected devices and the rack are locked and validated with the
normal NetBox model validation. If any placement, validation or permission
error occurs, the whole rack stays unchanged. Every moved device still gets a
normal changelog entry. Versions other than `1.1.4` are left untouched and only
produce a log message.
### Uploading multiple images
In the **Images** tab of supported objects, the single upload is replaced by
**Upload multiple images**. Up to 50 images can be selected at once, with
previews before saving. Each file is validated by NetBox; if one is invalid,
none are saved. An optional shared description can be applied; the original
file name is kept as the display name. Requires permission to add image
attachments and to view the target object.
NetBox caps Pillow at 25 megapixels, which breaks current 50 MP smartphone
photos (e.g. Google Pixel, 8160×6144) and their thumbnails. The bulk upload
therefore scales larger images down to NetBox' limit (EXIF orientation is
applied) before saving. If an image is rejected, the form also shows Pillow's
exact error message.
### Installing multiple modules
Under **Plugins > NetBox Utilities > Install multiple modules** (or via the
button on device pages with free module bays), choose a device, a module type
and several free module bays — or enter a **Quantity (1–x)** to use the first
free bays in natural order. All modules get the same type, status and
description; component replication from the module type templates is optional.
The operation is atomic: if a bay is taken meanwhile or a naming conflict
occurs, nothing is saved. Requires the permission to add modules; object
permissions still apply.
### Personalised navigation
Under **Plugins > NetBox Utilities > Customize navigation** users see every menu
they have access to. Arrow buttons change the order; a toggle hides a menu.
The desktop sidebar can be resized between 216 and 408 px by dragging its right
edge. A small handle collapses it into an **icon mode** where menus open as a
flyout (closed on selection, outside click or Escape). **Reset** restores order,
visibility and the default width of 288 px.
### Global tenant and tenant-group filter
The building icon in the header opens the selection of tenants and tenant
groups the user may see. A tenant group includes tenants of its child groups.
**All tenants** removes the filter.
The filter:
- enforces `tenant_id` or `tenant_group_id` in supported NetBox lists;
- restricts the tenant list itself;
- restricts NetBox global search results;
- applies to HTMX table updates and exports from filtered lists;
- does **not** change REST or GraphQL requests.
Superusers can disable it at runtime under **Plugins > NetBox Utilities > Settings**;
`tenant_filter_enabled = False` disables it permanently and takes precedence.
### Mandatory tenant assignment
Enabled by default under **Plugins > NetBox Utilities > Settings**. For all
object types with a `tenant` field, the field becomes required — in forms, CSV
imports, the REST API and `Model.save()` calls from scripts. Existing objects
without a tenant remain until they are next saved. Global reference models
without a `tenant` field are not affected.
When a form opens, missing values are pre-filled carefully: first from a
recognisable parent object (rack, site, device, cluster, …), otherwise from the
global tenant filter. Existing values are never overwritten. For cables, both
cable ends are evaluated; the tenant is only set if it is unambiguous. If an
automatically set tenant is saved unchanged, the browser asks for an explicit
confirmation.
`tenant_required = False` disables the feature permanently and takes precedence
over the UI setting.
## Important semantics
The tenant filter is a **view filter, not access control**. Direct object URLs
are not blocked; NetBox object permissions remain the security boundary. The
mandatory tenant assignment, however, is server-side data validation.
Only models with a tenant relation are filtered. Global reference data such as
manufacturers, roles or platforms stays visible.
The sidebar personalisation uses NetBox's official global
`PluginTemplateExtension` and reorders the already rendered core menus in the
browser. It changes neither core templates nor NetBox files.
## Development and tests
In a NetBox development environment:
```bash
pip install -e /path/to/Netbox-Utilities
python netbox/manage.py test netbox_utilities
```
## License
See [LICENSE](LICENSE).