openwrt-iac / uapi / docs / 2.5.1 / Non-uci state: what uapi covers and what it doesn't

Non-uci state: what uapi covers and what it doesn't

uapi's design contract is "uci is the source of truth". Almost every resource translates HTTP REST verbs into uci_set / uci_commit followed by a daemon reload. That model covers most of OpenWrt's configuration surface, but not all of it. This document inventories the small set of state that lives outside uci, in two categories:

  1. In-scope, non-uci resources. Things uapi exposes anyway, with deliberately documented deviations from the standard transaction recipe.
  2. Out-of-scope state. Things uapi explicitly does NOT cover, with the recommended out-of-band path for each.

The bar for adding to category 1 is high. New non-uci resources should justify themselves against three questions: is the underlying daemon's uci surface genuinely missing this? would the right long-term fix be to add a uci option upstream rather than carry workaround state in uapi? does the resource fit a curated CRUD shape, or is it a one-shot action better handled by an operator tool?

In-scope non-uci resources

Resource Source of truth Lock Reload Notes
packages/installed apk DB (apk add/del shell-out) with_lock on global none postinst runs as root; package's responsibility to wire its own uci/init scripts
packages/feeds /etc/apk/repositories.d/*.list + apk update with_lock on global none url-validated, name-validated
dhcp/leases /tmp/dhcp.leases (parse) none (read-only) n/a dnsmasq IPv4 leases
dhcp/leases6 /tmp/hosts/odhcpd (parse), fallback /tmp/odhcpd.leases none (read-only) n/a odhcpd IPv6 leases
system/password /bin/busybox passwd <user> (stdin pipe) with_lock on global none write-only; audit logs token+user, never the password
system/authorized_keys /etc/dropbear/authorized_keys (mode 0600) with_lock on global for writes; reads lock-free none dropbear re-reads the file per connection

Each entry below expands on its lock semantics, audit shape, the file/process it touches, and why the standard uci-transaction recipe doesn't apply.

Adding a non-uci resource means adding a row above. The bar is high: prefer driving the underlying daemon's uci surface if the option exists, or upstreaming the option to OpenWrt uci if it doesn't, before adding non-uci state to uapi.

packages/installed

packages/feeds

dhcp/leases (read-only)

dhcp/leases6 (read-only)

system/password (write-only)

system/authorized_keys

Out-of-scope state

The following items are real configuration concerns that uapi deliberately does NOT cover. For each, the recommended out-of-band path is listed. An IaC orchestrator typically wires these once at image-bake time (cloud-init / /etc/uci-defaults/) rather than reaching for them on every reconcile.

Unbound listen-address binding

Serial console / inittab

Wake-on-LAN packets

Certificate regeneration via px5g_x509

FreeBSD sysctl tunables from an OPNsense-style migration

RRD / NetFlow history

When you find a new gap

If your real-world configuration needs something uapi can't currently express, the first question to ask is: does the underlying OpenWrt package expose this via uci? If yes, the curated resource is undercurated; file an issue. If no, the right fix is usually to upstream a uci option, not to add another non-uci resource to uapi.

If, after weighing those, a new non-uci resource really IS the right answer, it needs to ship together with: