# NetBox Rack Concept Rack blueprints for NetBox. A "rack concept" is a fully planned rack including its equipment — but **not** a real rack and **no** real devices. Concepts therefore appear neither in the rack list nor in the device list, do not skew utilisation reports and do not consume serial numbers or IP addresses. Once the plan is final, a concept is turned into real NetBox objects with one click — once or twenty times. | | | |---|---| | **Plugin name** | `netbox_rack_concept` | | **Package** | `netbox-rack-concept` | | **NetBox** | `4.6.0` – `4.7.x` | | **Python** | `>=3.12` | | **Repository** | | ## Features | Workflow | Where | |---|---| | Real rack → concept | **Copy to concept** button on the rack detail page. Width, height and starting unit of the concept rack are freely selectable; devices that no longer fit are skipped and reported as warnings | | Concept → concept (variant) | **Clone concept** button on the concept detail page | | 2 concepts → 1 larger concept | **Merge** in the menu or **Merge with another** on the concept detail page — e.g. stacks two half-height racks into a full one; the top concept is shifted up by the height of the bottom one, both sources stay unchanged | | 2 real racks → 1 new concept | **Merge into concept** above the real rack list. Select two racks via checkbox and click the button — you land on the same merge form, pre-filled with the two real racks as sources | | Concept → real racks (n times) | **Deploy to NetBox** button, with naming scheme `DC1-R{n:02d}` | | Create a concept manually | Menu **Rack Concepts → Rack Concepts → +** | In addition: - **Drag & drop elevation** – move devices with the mouse, including from the front to the rear view (and vice versa). Everything is validated server-side; an invalid move is rejected and changes nothing. - **Devices with image and label** – device type front/rear images are shown in the elevation with the device name as white, black-outlined text. On the rear, a **full-depth** device only shows its own rear image; a **non-full-depth** device without a rear image (e.g. a power strip) shows its front image. A dropdown switches between "Images and labels", "Images only" and "Labels only" — just like real racks in NetBox, remembered in the browser. - **Partial widths** (1/1, 1/2, 1/3, 1/4 plus horizontal slot position), matching the partial-width feature of `netbox_utilities`. - **Tenant and tenant group** on the concept and on every planned device. - **Placeholders without device type** – reserved space with only a height. - **Click on an empty U** opens "Add planned device", pre-filled with position and face — just like a real rack elevation. - **Cabling of concept devices, 1:1 like real devices** – the device detail page has the same tabs as a real `dcim.Device` (interfaces, front/rear ports, console ports, console server ports, power ports, power outlets; tabs only shown when populated). **Sync components** copies them 1:1 from the device type's component templates, including front ↔ rear mapping of patch panels. **Connect** on every uncabled component creates a concept cable. An **Add Components** dropdown creates new components per type — needed for placeholders without a device type. - **Export** – **Export** button above the elevation: front or rear as standalone **SVG**, as **PNG** (single or both sides), and the whole concept as a **draw.io** diagram (`.drawio`). PNG is drawn directly on a `` in the browser; device type images are fetched individually, so a failing image only affects that one image. No server-side image library is needed. - Full REST API, filters, CSV import/export, bulk edit, changelog, journal, tags, custom fields and global search — like any core object. ## Compatibility - NetBox `4.6.0` – `4.7.x` - Python `>=3.12` - Optional: [Netbox-Utilities](https://git.mrblake.cc/MrBlake/Netbox-Utilities) for partial widths - Optional: `netbox-reorder-rack` — **v1.1.5 requires NetBox 4.7**; on NetBox 4.6 pin `netbox-reorder-rack<1.1.5` ## 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-Concept.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-Concept.git@main" /opt/netbox/local_requirements.txt \ || echo "git+https://git.mrblake.cc/MrBlake/NetBox-Concept.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`. ### 3. Enable the plugin In `/opt/netbox/netbox/netbox/configuration.py`: ```python PLUGINS = [ "netbox_rack_concept", # optional, in any order: "netbox_utilities", "netbox_reorder_rack", ] ``` If other plugins are already configured, add `netbox_rack_concept` to the existing list instead of replacing it. See [Configuration](#configuration) for optional settings. ### 4. Apply migrations, collect static files, restart ```bash cd /opt/netbox/netbox /opt/netbox/venv/bin/python manage.py migrate netbox_rack_concept /opt/netbox/venv/bin/python manage.py collectstatic --no-input sudo systemctl restart netbox netbox-rq ``` > If `migrate` cannot apply the bundled migration because base fields differ in > your NetBox installation: delete `netbox_rack_concept/migrations/0001_initial.py` > and run `manage.py makemigrations netbox_rack_concept`. The migration was > written by hand against NetBox 4.6.8. ## Update ```bash /opt/netbox/venv/bin/pip install --upgrade --force-reinstall --no-deps \ "git+https://git.mrblake.cc/MrBlake/NetBox-Concept.git@main" cd /opt/netbox/netbox /opt/netbox/venv/bin/python manage.py migrate netbox_rack_concept /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 ``` ## Uninstall 1. Remove `"netbox_rack_concept"` from `PLUGINS` and `PLUGINS_CONFIG`. 2. Remove the line from `/opt/netbox/local_requirements.txt`. 3. Uninstall the package and restart NetBox: ```bash /opt/netbox/venv/bin/pip uninstall netbox-rack-concept sudo systemctl restart netbox netbox-rq ``` ## Configuration All values are optional; the defaults are shown. ```python PLUGINS_CONFIG = { "netbox_rack_concept": { # Defaults when creating a new concept "default_u_height": 42, "default_width": 19, # Show the "Copy to concept" button on the rack page "enable_rack_tab": True, # Status of objects created on deployment "deployed_rack_status": "planned", "deployed_device_status": "planned", # Link to the partial widths of netbox_utilities. # Leave "model" empty if netbox_utilities stores the fields on dcim.Device directly. "partial_width": { "enabled": True, "model": "netbox_utilities.RackDevicePosition", "device_field": "device", "fraction_field": "width_fraction", "position_field": "horizontal_position", }, }, } ``` ## Usage ### Cabling Concept devices can be cabled, but **not** via NetBox's real `dcim.Cable`, which can only connect real `dcim` components. Instead the plugin ships its own lightweight model pair: - **ConceptComponent** — an interface, front/rear port, power port/outlet or console port on a planned device. **Sync components** creates them 1:1 from the device type's component templates (name, label, type, positions) — repeatable, without duplicates or data loss on already cabled components. Placeholders without a device type get components via **Add component**. - **ConceptCable** — connects two `ConceptComponent`s. Both ends must belong to devices in the same rack concept; a component can only be in one cable at a time. **Patch panels work exactly like real devices**, because the plugin reads the same front ↔ rear mapping NetBox maintains on the device type (`PortTemplateMapping`). It does not depend on the role name "Patchpanel" but on whether the device type defines front/rear ports with a mapping. **When copying a real rack into a concept** (and when merging two real racks), components of all copied devices are synced automatically, and every real cable whose **both** ends lie within the copied rack(s) is recreated as a `ConceptCable` — including status, type, colour and label. Cables leaving the rack and multi-trunk cables (e.g. MPO) cannot be taken over and are reported as warnings with a count. Cloning or merging concepts leaves cabling unchanged. ### Interaction with other plugins **netbox-reorder-rack** works on `dcim.Device` querysets. A concept has none by definition, so this plugin ships its own drag & drop elevation (`static/netbox_rack_concept/elevation.js`). Once deployed, the result is a normal rack and reorder-rack applies as usual. **netbox_utilities** provides partial widths for real devices. On deployment, this plugin writes `width_fraction` and `horizontal_position` there; when copying a real rack it reads them. The field mapping is configurable in `PLUGINS_CONFIG`. If `netbox_utilities` is not installed or the mapping does not match, partial widths are simply not written and a warning is logged. ### What is not deployed A concept describes space, not operational data. Intentionally **not** created: cables, interfaces beyond the device type templates, IP addresses, serial numbers, asset tags. Planned devices without a role, device type or position are skipped — the confirmation page lists them before deployment. ### REST API Base path: `/api/plugins/rack-concepts/` | Method | Endpoint | Purpose | |---|---|---| | `GET/POST` | `concepts/` | List and create concepts | | `GET/PATCH/DELETE` | `concepts/{id}/` | Single concept | | `POST` | `concepts/copy-from-rack/` | Copy a real rack into a concept (with `override_width`/`override_u_height`/`override_starting_unit`) | | `POST` | `concepts/{id}/clone/` | Duplicate a concept | | `POST` | `concepts/merge/` | Stack two concepts into a larger one (`concept_bottom`, `concept_top`) | | `POST` | `concepts/{id}/deploy/` | Deploy a concept (`dry_run` supported) | | `GET` | `concepts/{id}/elevation/` | Computed elevation as JSON | | `GET/POST` | `devices/` | Planned devices | | `GET/POST` | `components/` | Components of planned devices | | `GET/POST` | `cables/` | Concept cables | Example — ten racks from one concept, as a dry run first: ```bash curl -s -X POST https://netbox.example/api/plugins/rack-concepts/concepts/3/deploy/ \ -H "Authorization: Token $NETBOX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name_pattern": "DC1-R{n:02d}", "count": 10, "start_index": 1, "site": 4, "location": 12, "create_devices": true, "device_name_pattern": "{rack}-{name}", "dry_run": true }' ``` Response: ```json { "dry_run": true, "racks": ["DC1-R01", "…", "DC1-R10"], "devices_per_rack": 7, "total_devices": 70, "warnings": ["Blanking panel 3 has no role. NetBox requires one, so it will not be created."] } ``` Set `dry_run` to `false` to actually create the objects. Deployment runs in **one** transaction: if a rack or device fails, nothing is created. ### Permissions Standard NetBox object permissions apply: `netbox_rack_concept.view_rackconcept`, `add_`, `change_`, `delete_` — and analogously for `conceptdevice`. Deployment additionally checks `dcim.add_rack`. ### Language The plugin is available in English (source) and German. Switch the display language as usual in the user profile (**Preferences → Language**). Translations live in `netbox_rack_concept/locale/de/LC_MESSAGES/`. ## License MIT