Metadata-Version: 2.4
Name: nautobot-cable-utils
Version: 3.0.0
Summary: A Nautobot plugin for working with cables
License: Apache-2.0
License-File: LICENSE.txt
Author: Gesellschaft für wissenschaftliche Datenverarbeitung mbH Göttingen
Requires-Python: >=3.11,<3.15
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: igraph (>=0.11.5,<2.0.0)
Requires-Dist: nautobot (>=3.2.0,<4.0.0)
Project-URL: Repository, https://gitlab-ce.gwdg.de/gwdg-netz/nautobot-plugins/nautobot-cable-utils
Description-Content-Type: text/markdown

# Nautobot Cable Utilities

Nautobot app for what cable management in Nautobot 3.2 still lacks:

- **Cable inventory:** the cables in storage, as ordinary cables without ends and with the status *In Stock*.
- **Commission / Undo Commission:** hand a stock cable to a Planned cable, standard or breakout, or take it back.
- **Device Commission:** commission all Planned cables of a device in one loop, with QR code scanning.
- **Auto-Link:** propose and create Planned cables between ports through patch panels in different racks.

| cable-utils | Nautobot   | Python       |
|-------------|------------|--------------|
| 3.x         | 3.2 to 3.x | 3.11 to 3.14 |
| 1.x         | 2.x        | 3.11         |

Nautobot 3.2 changed how cables attach to ports, so 3.0 and 3.1 are not supported. PostgreSQL is required.
The router reads Nautobot's cable tables with raw SQL, which is why the supported range stops below 4.0.
See [CHANGELOG.md](CHANGELOG.md) for what changed.

## Installation

Install into the same environment as Nautobot:

```
pip install nautobot-cable-utils
```

Enable the app in `nautobot_config.py` (no `PLUGINS_CONFIG` entry needed):

```python
PLUGINS = ["nautobot_cable_utils"]
```

Then run migrations and restart Nautobot:

```
nautobot-server post_upgrade
```

`post_upgrade` creates the cable status *In Stock*, the custom fields *Cable number*, *Plug* and *Procurement identifier*, and the relationships *Cable owner*, *Cable supplier* and *Cable storage rack*. The choices for *Plug* are yours to add under **Extensibility → Custom Fields → Plug**.

### Permissions

- `dcim.view_cable` for the menu entry and the stock list.
- `dcim.add_cable` to add or import stock cables and to use Auto-Link.
- `dcim.change_cable` and `dcim.delete_cable` for Commission and Device Commission (the stock cable is consumed).
- `dcim.change_cable` and `dcim.add_cable` for Undo Commission (the stock cable is recreated).

Commission, Undo Commission and Device Commission respect constraints on these permissions: they only reach cables the user may change, and stock cables the user may delete.

### Upgrading from 1.x

Upgrade Nautobot to 3.2 or newer together with the app.

- **Stock cables replace the inventory.** Migration `0013` turns every inventory item into a stock cable and `0014` drops the old tables. Free items become cables with status *In Stock*, items in use keep their cable and only get the number and the rest. `name` becomes the custom field *Cable number*, `plug` the custom field *Plug* (its choices are the old plugs), `procurement_ident` the custom field *Procurement identifier*, and `owner`, `supplier` and `storage_rack` the relationships *Cable owner*, *Cable supplier* and *Cable storage rack*. The REST endpoints `cable-inventory-item` and `cable-plug` are gone; use `/api/dcim/cables/?status=In%20Stock`. Rehearse the migration on a copy of your database.
- **Lengths without a unit** (the old form allowed them) become meters, because a cable needs a unit for its length.
- **Commission works on the cable you already have.** The planned cable keeps its id and ends and receives the data of the stock cable; the stock cable is deleted. Undo Commission turns it back.
- **Measurement logs** are removed. Migration `0012` drops the table `nautobot_cable_utils_measurementlog`, and the rows cannot be restored afterwards. Export them before running `post_upgrade`, for example in `psql`:

  ```
  \copy nautobot_cable_utils_measurementlog TO 'measurement_logs.csv' CSV HEADER
  ```

- **Reconnect** is gone. The button on a cable now opens Nautobot's own Edit Cable page, which changes the terminations of the same cable.
- **Permissions:** commissioning now checks `dcim.change_cable` and `dcim.delete_cable`. 1.x checked `dcim.edit_cable`, which Nautobot does not define, so grant *change* and *delete* on *Cable* to everyone who commissions.
- **The menu entry moved** from Apps to **Devices → Cable Utilities → Cable Inventory**, right after Nautobot's own Connections group with Cables.

## Usage

Screenshots show the Nautobot 2 UI; the pages look different in Nautobot 3 but work the same.

### Cable inventory

Open **Devices → Cable Utilities → Cable Inventory**. It lists **every cable**, in stock, planned or connected, with the columns number, label, status, A and B ends, cable type, plug, owner, supplier, storage rack and procurement identifier. **Stock cables**, **Planned cables** and **Connected cables** open the same list narrowed by status: a Planned cable is waiting for a stock cable, a Connected cable keeps its number after it was commissioned. All of Nautobot's cable filters, exports and bulk actions work on it, and the plain list stays under **Devices → Connections → Cables**.

A stock cable is a normal cable, so everything else about it is edited on its cable page: type, color, length and, for a fan-out cable, the cable type (for example *1x4 Breakout*). The cable number is unique across all cables.

- **Add stock cables** takes a number pattern such as `T-[1-20]` and the properties all of them share.
- **Import stock cables** takes CSV with the columns `cable_number`, `label`, `type`, `cable_type`, `plug`, `color`, `length`, `length_unit`, `owner`, `supplier`, `storage_rack` and `procurement_ident`. Only `cable_number` is required (`name`, the 1.x column name, also works). `cable_type`, `owner`, `supplier` and `storage_rack` are given by name or id; use the id when a name, such as a rack name, is not unique. `length` is a whole number up to 32767. The import is all or nothing.

### Commission and Undo Commission

On the page of a Planned cable with ends, **Commission** asks for a cable number, typed or scanned with the camera (browsers allow camera access only over HTTPS). The page lists every end of the cable: `A1` and `B1` for a standard cable, `A1`, `B1` to `B4` for a *1x4 Breakout*. The cable becomes Connected and takes over the type, label (the number if there is none), color, length, number, plug, procurement identifier, owner, supplier and storage rack of the stock cable. The stock cable is deleted, and with it its tags, notes and other custom fields: only the properties listed here are carried over.

Both cables need the same cable type. Change the cable type of the planned cable first if they differ.

<img alt="Commission button" src="./docs/commission_button.png" width="150">

**Undo Commission** appears on a commissioned cable. After confirmation, the cable is Planned again with its properties cleared, its ends untouched, and the stock cable exists again with all its data.

<img alt="Undo Commission button" src="./docs/undo_commission_button.png" width="180">

### Device Commission

A device with Planned cables shows a **Device Commission** button.

<img alt="Device Commission button" src="./docs/device_commission_button.png" width="180">

It walks through the Planned cables one by one, each cable once, however many of its ends are on the device. The page shows how many are left, every end of the cable and the cable number field.

<img alt="Device Commission form" src="./docs/device_commission_form.png" width="800">

- **Create** commissions the cable with the entered number and shows the next one.
- **Skip** leaves it Planned and shows the next one.
- **Cancel** stops and returns to the device.
- **Scan** reads the cable number from a QR code.

The loop is stored in the session. If you leave without pressing **Cancel**, it continues at the same cable when you come back, until the session expires or you start another device. Skipped cables only show up again after **Cancel** and a fresh start.

### Auto-Link

On an interface or front port without a cable, **Auto-Link** offers an interface or a front port as destination.

<img alt="Auto Link Button" src="./docs/auto-link-button.png" width="500">

Choose the destination and the media type. The app shows the proposed cable trace and the Planned cables it would create.

<img alt="Auto Router Form" src="./docs/auto-router-form.png" width="500">

The router builds a graph with all racks as vertices and the cables between rear ports of rack-mounted patch panels as edges. It finds a path from the source rack to the destination rack and lists the cables still needed. **Create** adds them with Planned status, all or none.

**Allow Next Rack Patches** lets the path hop to a neighboring rack in the same location. Neighbors are decided by the SQL function `is_neighbor()` from migration `0009`, which only knows GWDG's rack names (`1519-…`, `V1519.…`, `V2356.…`). With other rack names the option has no effect; to add a naming scheme, replace that function. Breakout cables are not routed.

## Development

Tests need a Nautobot 3.2+ environment with PostgreSQL:

```
nautobot-server test nautobot_cable_utils
```

CI runs `flake8 .` on Python 3.11 to 3.14.

