v3.x summary — Device sync, VLAN sub-interfaces, Static Routes¶
This page summarizes the capability arc from v3.0 → v3.4.1. For the
per-release detail (every hotfix, regression guard, and PII audit
finding), see the canonical CHANGELOG.md
in the repo.
What v3.x adds¶
The v2.x line stabilized bidirectional sync for firewall objects + wireless config + NAT VIPs + policies. The v3.x line expands the project's surface beyond config-objects to DCIM: the FortiGate itself, its interfaces (physical + aggregate + VLAN sub-interfaces), its IP assignments, and its static routes.
Job count: 5 → 7¶
v3.x added 2 new Jobs:
| Job | Direction | First shipped |
|---|---|---|
| FortiGate → Nautobot (device + interfaces) | pull | v3.0 (2026.05.18.11) |
| Nautobot → FortiGate (device + interfaces) | push | v3.3+v3.4 (2026.05.19.0/.1) |
Plus the existing 5 (firewall pull/push, wireless pull/push, live status) — total 7 Jobs registered.
New capabilities by release¶
v3.0 — Device + Interface sync (pull)¶
The FortiGate appears as a dcim.Device with its operator-meaningful
interfaces (physical / aggregate / hard-switch / switch) and IP
assignments synced from system.interface. Operator pre-creates the
DeviceType + Role + Location + Status; the sync attaches.
v3.1 — VLAN sub-interfaces + Static Routes (pull)¶
VLAN sub-interfaces (FortiOS type: vlan with a real vlanid and
interface parent — not the auto-quarantine wqtn.* ones) sync as
dcim.Interface records with parent_interface resolution.
Static routes (FortiOS cmdb/router/static) sync to a new app-owned
Django model: FortinetStaticRoute, anchored to the FortiGate's
dcim.Device. Browse them at /plugins/ssot-fortinet/static-routes/.
Why an app-owned model: Nautobot core doesn't have a first-class Route model. The
FortinetStaticRoutelives in this app's namespace and references the synced Device, the next-hop IP, the destination (prefix or named AddressObject), and the FortiOS metadata (distance,priority,blackhole, etc.).
v3.2 — FortiOS shape coverage from Kevin's prod sync¶
Real production FortiOS data revealed shape variations our dev-only testing hadn't surfaced:
- MAC / dynamic / geography address types — synced as placeholder
FQDNs (e.g.
vpn_users.dynamic.fortios.invalid) with the actual FortiOS value annotated in the description. Operators can see them in Nautobot's UI without losing the FortiOS-side context. dstaddrshape varies by FortiOS version — plain string on 7.0.x, list-of-dict on 7.2+. Normalized in the pull adapter.- DHCP-acquired default routes appear in the routing table but NOT
in
cmdb/router/static— our static-route sync deliberately covers only operator config-intent (the cmdb view), not the active RIB.
v3.3 — VLAN sub-interface PUSH¶
Operators can now author VLAN sub-interfaces in Nautobot's UI and push them to FortiGate. New "Nautobot → FortiGate (device + interfaces)" Job.
Caveat: FortiOS silently truncates interface names to 15 characters. Keep your VLAN sub-interface names short or the round-trip drifts.
v3.4 — Static route PUSH¶
Authoring static routes in Nautobot now propagates to FortiOS via the
same push Job. Includes blackhole routes, named-AddressObject
destinations (with the allow-routing: enable flag set automatically),
and explicit ECMP via priority / distance.
v3.4.1 — Module-import smoke-test framework¶
Tiny tests that import every shipped module catch the bug class where
a top-level statement raises (e.g. v3.3's NavMenuGroup type error
that broke ALL 7 Jobs on import). Runs in <1s; catches the kind of
issue that would otherwise need a full Nautobot startup to surface.
Same-day hotfixes captured in CHANGELOG¶
The 2026.05.18.13.1 through .6 series (5 same-day fixes) are
documented in CHANGELOG.md.
Highlights:
.1—NavMenuGrouptype error fix (regression on Nautobot 3.x nav API).2—blackholefield treated as string, not bool (would have flipped every non-blackhole route to blackhole).3/.4— PII audit findings + scrub.5—Device.serialextraction (closes v3.0's carryover bug).6— named-AddressObject route resolution (closes v3.1 deferral)
Live-validated against real hardware¶
Every v3.x capability has at least one e2e test in
development/scripts/. The dev stack runs against a FortiWiFi-61E,
and Kevin's production environment (a FortiGate-100F cluster) surfaced
the v3.2 shape variations. Both targets converge on the same Nautobot
schema.
Upgrade path¶
pip install --upgrade nautobot-ssot-fortinet
nautobot-server collectstatic --no-input
sudo systemctl restart nautobot nautobot-worker
If you were on a v2.x release, run the pull Jobs once after upgrade —
the v2.5 /32 ipmask normalization migrates pre-v2.5 records to the
new classification on first pull.
What's queued for v3.5+¶
- Push direction for the
FortinetStaticRouteUI workflow (operators editing routes in Nautobot and pushing) — most of v3.4 is the underlying machinery; v3.5 adds the UI-driven workflow polish - VPN sync (Nautobot has
vpn.VPN/vpn.VPNTunnelmodels, FortiOS has phase1/phase2 data) firewall.schedule— currently we hardcodeschedule: "always"on policy push; time-based rules need this
See the maintainer's notes (CLAUDE.md in the repo) for the full queue.