Changelog¶
All notable changes to netbox-osp are documented here. The format follows
Keep a Changelog and this project
adheres to Semantic Versioning.
Per-release NetBox / Python compatibility lives on the Compatibility page.
Unreleased¶
0.2.2 — 2026-05-18¶
Docs¶
- README screenshots now use absolute raw.githubusercontent.com URLs so they render inline on the PyPI project page.
- New 8-step demo walkthrough at /demo/ on the docs site with 10 live screenshots (OSP model, splice closures, loss-budget gauge, MTP harness deploy form, visual core tracer, plant map).
- No code changes — metadata-only.
0.2.1 — 2026-05-14¶
Fixed¶
- Visual core tracer rendered an empty Path graph because dagre-d3 declares an external d3 dependency. Vendored d3.v5.min.js alongside the dagre-d3 bundle.
0.2.0 — 2026-05-13¶
Five-PR cycle adding inter-rack fibre infrastructure: MPO/MTP trunks with breakouts to cassettes, one-click harness deploy, cassette device-type catalogue, and an end-to-end visual core tracer.
Added¶
FibreTrunkmodel — parent for multi-fibre rack-to-rack physical trunks (MPO/MTP 12/24/72-fibre, Ribbon 144-fibre, loose-tube indoor runs). Carriescid,trunk_type,fibre_count,manufacturer,length_m,status(reusesOspStatusChoices), GeoJSONroutewithshow_on_mapopt-out,description,comments,tenant,tags. DB-levelCheckConstraintonfibre_count > 0plus a form-friendly validation. NewTrunkTypeChoicespalette with a per-typeDEFAULT_FIBRE_COUNTmapping for follow-up auto-fill.- REST CRUD under
/api/plugins/osp/trunks/. - GraphQL —
osp_fibre_trunkandosp_fibre_trunk_listqueries. - Admin chrome — list / add / edit / delete / bulk-edit / bulk-delete / bulk-import / changelog views, table, filter form, sidebar entry under a new "Trunks" group, search-index registration.
- Tests —
tests/test_fibretrunk.pycovering__str__, defaults,clean(), tagging, REST CRUD, and GraphQL module-level exposure. TrunkBreakoutthrough-table bridgingFibreTrunkto NetBox's nativedcim.Cable. Captures the trunk-with-breakouts pattern: "24F MTP trunk → 12F breakout to rack A + 12F breakout to rack B" as one entity.trunkFK (CASCADE),cableFK (PROTECT), 1-indexedfibre_range_start/fibre_range_end, twounique_togetherto prevent double-allocation, and field-keyedclean()rejecting overflow and sibling overlap.FibreTrunk.clean()now enforces sum-of-children ≤fibre_count.FibreTrunk.fibres_used/fibres_remaining/fibres_utilization_pctcomputed properties.- "Import from cables" wizard at
/plugins/osp/trunks/<trunk_id>/import-cables/— atomic multi-select bind of unbounddcim.Cables to fibre ranges. - REST + GraphQL for
TrunkBreakout. - CSV bulk import keyed by
trunk_cid+cable_label. - MTP harness one-click deploy form at
/plugins/osp/trunks/deploy-harness/— a single form submit creates the parentFibreTrunk+ N cassettedcim.Devices + Ndcim.Cables + NTrunkBreakoutrows atomically. Two-step preview/confirm flow usesdjango.core.signing.dumps(base64-encoded, HTML-safe) for the state token. Replaces ~30 individual NetBox object writes with one form. - Bundled cassette catalogue — five
DeviceTypeJSON templates atnetbox_osp/device_types/cassettes/covering the standard MPO/MTP fibre-cassette and LC patch-panel shapes that pair with the MTP harness deploy form:mpo-12f-lc-cassette,mpo-24f-lc-cassette,mpo-12f-mpo-cassette,lgx-lc-12f-panel,ru1-lc-24f-panel. Files follow thenetbox-community/devicetype-libraryschema. -
load_osp_cassettesmanagement command — seeds all five cassettes idempotently:python manage.py load_osp_cassettes
Slug-keyed update_or_create, atomic per cassette, materialises
RearPortTemplate + FrontPortTemplate + PortTemplateMapping
rows. --dry-run flag for safe inspection.
- Visual core tracer (PR E) — click "Trace this core" on a Strand,
dcim.FrontPort, or dcim.Interface detail page to render an
end-to-end fibre path as a clickable dagre-d3 graph. Each hop —
interface, patch cord, cassette pass-through, MPO/MTP trunk, splice,
OSP strand — shows inline loss + length; the summary band above the
graph shows total dB used against the strand's parent FibreLink
budget (or a configurable default), colour-coded ok / warn /
fail. New JSON endpoint at
GET /api/plugins/osp/cores/<strand_id>/trace/ returns the hop list
for external tooling. dagre-d3 v0.6.4 (~700 KB minified) ships
vendored in static/netbox_osp/js/dagre-d3.min.js. Three new
PluginTemplateExtension subclasses inject the trace button onto
dcim.Interface, dcim.FrontPort, and netbox-osp Strand detail
pages. New optional config keys under PLUGINS_CONFIG["netbox_osp"]:
default_cassette_loss_db (0.5), default_patch_cord_loss_db (0.1),
default_loss_budget_db (8.0). Zero new migrations — the tracer is
read-only over the existing data model.
The 0.2.0 release tag fires once all five v0.2 PRs land. This entry
documents PRs A, B, C, D, and E. All five v0.2 features
landed; v0.2.0 is ready to tag.
0.1.1 — 2026-05-13¶
Fixed¶
- Corrected author / maintainer name in package metadata,
PluginConfig,mkdocs.ymlcopyright, and the icon SVG copyright comment from "John McKenzie" to "John McKean". 0.1.0 shipped with the wrong spelling and PyPI does not permit re-uploading a published version, so this metadata-only patch ships the correction.
0.1.0 — 2026-05-13¶
First functional release. Covers the full OSP fibre data model, the interactive plant map with online + offline base layers, REST + GraphQL APIs, bulk-import / bulk-edit, plant-boundary validation, and per-Location GPS markers.
Added¶
- Data model —
OspCable,Tube,Strand,SpliceClosure,SpliceTray,Splice,FibreLink,FibreLinkStrand,LocationGeowith TIA-598-C auto-colours, capacity / utilisation accounting, and thefibre_count == tube_count × fibres_per_tubeinvariant enforced inclean(). - Fibre-link loss budget — strand attenuation × length + per-splice loss + per-connector loss, with ok / warn / fail band against a configurable target. SVG gauge bar rendered on the FibreLink detail page.
- Network map — full-screen Leaflet at
/plugins/osp/map/, filterable by status, with 7 online base layers (OSM, HOT OSM, CartoDB Positron / Dark Matter, OpenTopoMap, CyclOSM, Esri World Imagery) plus a bundled offline MBTiles bundle. Auto-falls back to offline after three tile errors within five seconds. User's explicit choice persists across reloads vialocalStorage. - GeoJSON cable-route editor — leaflet-geoman drag-to-edit with the same base-layer machinery as the main map.
- Plant-boundary trace tool — operator drags vertices to draw the
plant outline; exports a
[lon, lat]coordinate list for theplant_boundarysetting. - Optional plant-boundary validation — set
PLUGINS_CONFIG['netbox_osp'] ['plant_boundary']andOspCable.clean()rejects any cable whoseroutefalls outside the polygon. Pure-Python ray-casting; no PostGIS required. - Per-Location GPS markers (
LocationGeo) — 1:1 side-table ondcim.Locationaddinglatitude/longitude/elevation_m/marker_color. Rendered asL.circleMarkeroverlay on the map and injected as a panel on thedcim.Locationdetail page. - Bulk-import / bulk-edit forms for
Tube,Strand,Splice,SpliceTray,SpliceClosure, andLocationGeo— closes a ~300-click data-entry gap for a 288-strand cable. - GraphQL types for all nine plugin models via
strawberry-django, registered with NetBox's/graphql/endpoint. - REST API under
/api/plugins/osp/...with full CRUD on every model, filter-sets aligned with the UI list views. - Offline-first tile proxy at
/plugins/osp/tiles/<z>/<x>/<y>.<ext>serving PNG / JPEG / WebP tiles from one or more MBTiles files, with per-tileETag+304 Not Modifiedand transparent-PNG fallback for missing tiles. - Permission-matrix tests — auto-generated coverage of GET / list / create / edit / delete and their bulk variants for the SpliceClosure view set (canary; remaining seven models follow a known pattern).
- MkDocs Material docs site at https://iamjohnnymac.github.io/netbox-osp/.
Infrastructure¶
- Public GitHub repo with PyPI Trusted Publishing via OIDC (no API tokens).
- CI matrix: Python 3.12 / 3.13 × NetBox 4.6 on Postgres 17 + Redis 7.
mkdocs.yml+ GitHub Pages auto-deploy on everymainpush..pre-commit-config.yamlwithruff(lint + format), configured to match the NetBox plugin ecosystem.- Apache-2.0 license.
Known limitations¶
- GraphQL schema registers cleanly but
osp_<model>_listquery fields don't surface in the merged globalQueryyet — being debugged against a live/graphql/endpoint. REST API is fully functional in the meantime. - Permission-matrix tests cover the SpliceClosure canary; the remaining
models will be added in a focused follow-up. REST
APIViewTestCasepermission tests are deferred until CI wiresAPI_TOKEN_PEPPERS.
0.0.1 — 2026-05-13¶
- PyPI name-reservation placeholder. Not functional.