Adapter Overview
Adapters are FreeSDN’s typed, auditable drivers that translate platform operations into vendor-specific API calls. All 13 adapters auto-register at startup. Every adapter follows the same safety contract so you interact with switches, firewalls, cameras, and hypervisors in a consistent way regardless of vendor.
How the registry works
Section titled “How the registry works”All 13 adapters are registered at startup by adapter_registry.discover_adapters(), which explicitly imports each adapter by name. No configuration flag is needed - adapters are registered when the registry module is imported. Adding a new adapter package requires a corresponding entry in discover_adapters(); the function does not scan the filesystem. Each adapter declares its capabilities in an AdapterManifest registered in the adapter registry. The registry looks up the manifest at request time using the controller’s vendor type - nothing extra is stored in the Controller record.
The frontend reads capabilities via GET /api/v1/controllers/{id}/capabilities. Tabs, buttons, and dialogs are hidden when the adapter has not declared the matching Capability constant. You will never see a “Firmware Upgrade” button on a Controller whose adapter does not support firmware management.
The staged dual-gate
Section titled “The staged dual-gate”The most important property of any FreeSDN adapter: a live device is never written to by accident. Every mutation travels through a two-stage pipeline:
-
Stage - the change is recorded as a
pending_changesrow in the database. No packet is sent to the device. The staging endpoint validates input, checks tenant scope, and verifies the caller’s permission against the exact feature domain. -
Apply - the operator reviews the pending row in the Pending Changes page and confirms. Apply only succeeds when both conditions are true:
- The environment variable
ADAPTER_READ_ONLYisfalse. - The apply request body carries
force: true.
- The environment variable
Either gate alone refuses the apply. A stray API call cannot accidentally push a change if the environment is still set to read-only.
Apply is atomic: the pending row is claimed with SELECT ... FOR UPDATE inside the same database transaction that flips it to "applying", so two concurrent workers can never double-apply the same change. If a worker crashes mid-apply, a Celery beat janitor reverts rows stuck in "applying" for more than five minutes back to "failed", keeping the queue drainable.
Maturity tiers
Section titled “Maturity tiers”The full honest matrix lives in the table below and in docs/SUPPORTED_VENDORS.md in the repository.
| Tier | What it means |
|---|---|
| Production | Gold-standard contract enforced and verified. Suitable for evaluated production use after your own testing. File bugs as severity-1. |
| Beta | Functional and covered by the automated test suite, but lacks field miles or one contract item. Use it; do not put it on the critical path of a paying customer without testing first. |
| Preview / Foundation | Partial or unaudited implementation. Treat as a developer preview; expect gaps. |
The gold-standard contract requires all six checks to pass: dual-gate writes (DG), tagged circuit breaker (CB), read-path secret redaction (RR), tenant scoping on reads (TS), SSRF guard on outbound URLs (SSRF), and role gates on destructive operations (RG).
Supported vendors matrix
Section titled “Supported vendors matrix”| Adapter | Category | Maturity | DG | CB | RR | TS | SSRF | RG | |
|---|---|---|---|---|---|---|---|---|---|
| Omada (TP-Link) | Network | Production | 12,807 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| OPNsense | Firewall | Production | 7,761 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| pfSense | Firewall | Production | 2,176 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| MikroTik / RouterOS | Firewall / Router | Production | 4,653 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Proxmox VE | Hypervisor | Production | 4,591 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Hikvision | Cameras / NVR | Production | 4,640 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| FreePBX / Asterisk | VoIP | Beta | 5,268 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Grandstream | VoIP phones | Beta | 2,855 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| UniFi (Ubiquiti) | Network | Beta | 2,230 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| OpenWrt | Router / AP | Preview | 3,666 | - | - | - | - | - | - |
| ONVIF (generic shim) | Cameras | - | 2,558 | - | - | - | - | - | - |
| TrueNAS | Storage | Preview | 1,722 | - | - | - | - | - | - |
| UniFi Protect | Cameras | Preview | 511 | - | - | - | - | - | - |
How the contract is enforced
Section titled “How the contract is enforced”Every adapter must satisfy the FreeSDN adapter contract rubric before it ships. The checklist covers 14 sections: production safety, tenant isolation, permission boundaries, input validation, resilience (rate limiter + retry + circuit breaker), observability (Prometheus metrics + structured logging + health endpoint), audit trail, sensitive-data redaction, DoS hardening, capability advertisement, frontend contract, and test coverage. Each “MUST” item is a release-block.
The Omada adapter is the reference implementation every new adapter is graded against.
Adding a Controller
Section titled “Adding a Controller”All adapters are accessed through a Controller record. Add one via the Setup wizard in the UI, or via the API:
# 1. Create the Controller (credentials are supplied inline)curl -X POST https://<host>/api/v1/controllers \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "name": "my-controller", "controller_type": "<vendor>", "host": "https://controller.lan", "port": 443, "site_id": "<site_id>", "username": "admin", "password": "<password>" }'
# 2. Trigger device discoverycurl -X POST https://<host>/api/v1/discovery/controllers/<controller_id> \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>"Replace <vendor> with the lowercase adapter name: omada, opnsense, pfsense, mikrotik, unifi, openwrt, hikvision, freepbx, grandstream, proxmox, truenas.
Per-adapter pages
Section titled “Per-adapter pages”- Omada (TP-Link) - gold-standard reference, switches + APs
- UniFi (Ubiquiti) - Beta; 18 read methods + 8 dual-gated writes, unverified against real hardware
- OPNsense - production firewall brain, 13 domains
- pfSense - production firewall, shares OPNsense client plumbing
- MikroTik RouterOS - production router/switch/VPN, 13 domains
- OpenWrt - preview; ubus/UCI client, unaudited
All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.