Replace restart with in-process config reload #29
Labels
No labels
Bug
BuildIssue
Claude-fixed
Enhancement
In Progress
Low priority
On Hold
Rejected
Security
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
keyop-go/nfq_forwarder#29
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Currently we rather awkwardly rely on using systemd to restart the process when we reload configuration after changes in the UI.
We should support a config reload option, which brings running configuration in line with the stored configuration, taking down any tunnels which are no longer defined and making sure that all firewall rules are cleaned up or created as needed.
This should be used in the UI reload options as well as being available via a signal (SIGHUP is traditional for this). The systemd unit can then also be updated to support the reload option.
changed the description
Plan
Today
nfq_forwarderreads--configexactly once at startup. The web UI's config-edit feature(#25) validates and writes a new file to disk but never applies it - the only way to pick up a
change today is
POST /api/config/restart, which shells out tosystemctl --user restart --no-block nfq_forwarder.service(a full process restart). This ticket replaces that with a realin-process reload, plus SIGHUP support and a systemd
ExecReloadupdate.Design
New
connectionManagertype (internal/nfq_forwarder/connection_manager.go) tracks eachrunning connection by queue number - the stable identity issue #20's name-hash-derived
auto-assignment already establishes, and the same identity
deleteNfqIptablesRulesFunc'scrash-recovery cleanup keys on.
reload(newConns):existing teardown path -
deleteNfqIptablesRulesFunc+sshConns.closeAll()- to finish).Connectionstruct differs (jump host, network, ports, etc.) → stop andrestart with the new details.
sshConnspool and any open tunnels onit are untouched by an unrelated add/remove elsewhere in the same reload.
the web UI response.
A subtle correctness point worth calling out up front:
NFQForwarderMainneeds one blocking callthat waits for every connection goroutine to exit at shutdown, including ones started by a later
reload. A bare
sync.WaitGroup.Wait()isn't safe for that on its own, since a reload'sstop-then-start sequence can transiently drop the counter to zero before repopulating it, and
Go's WaitGroup permits
Wait()to return right at that zero-crossing. Fix:reload()refuses tostart anything once the manager's parent context is already cancelled (shutdown in progress), and
the shutdown wait blocks on that context being done before calling
wg.Wait()- so by the timewg.Wait()runs, the counter can only ever decrease. This gets a direct regression test.SIGHUP: added to
initSignalHandleralongside the existing SIGINT/SIGTERM/SIGUSR1, callingthe same reload closure the web UI uses - one reload code path, not two.
Web UI:
POST /api/config/restart(handleAPIConfigRestart,restartServiceFunc,os/exec) is removed entirely and replaced withPOST /api/config/reload, going through thesame closure. The config-edit page's "Restart service" button becomes "Reload configuration" and
shows a summary of what changed.
systemd unit:
ExecReload=changes fromsystemctl --user restart ...to the standardkill -HUP $MAINPIDidiom.danny/scripts'nfqctl reloadalready just delegates tosystemctl --user reload, so it needs no change - it'll pick up the new SIGHUP-based behaviorautomatically.
Scope boundary (documented explicitly, not just implied): reload only reconciles
connections:- added/removed/changed tunnels and their firewall rules. It does not restartthe HTTP listener even if
web_ui:settings changed in the file; that still needs a realrestart (unchanged from today).
Testing
New
connection_manager_test.gocovering add/remove/restart-in-place/no-op-when-unchanged, plusthe shutdown-guard regression test above, using this codebase's existing
initNfqueueFunc/sshDialFunc-style stubbing seams (no real iptables/netlink/SSH). SIGHUP gets areal-signal-to-this-process test matching the existing SIGUSR1/SIGTERM ones. The three
TestAPIConfigRestart*web UI tests becomeTestAPIConfigReload*equivalents. Real-hostverification (SIGHUP against an installed systemd unit; a UI reload actually removing/adding
iptables rules against live traffic) isn't exercisable in this sandbox and will be flagged as an
unverified item, matching every other privileged-network feature in this project so far.
Branch:
issue29_config_reload.