Description
When staticManifestPath is configured (i.e. staticManifestMode is not "off"), main() calls both staticRun() and run() sequentially. Both functions call ctrl.SetupSignalHandler(). The controller-runtime signal handler uses a package-level sync.Once and panics on the second call with panic: close of closed channel.
Reproduction
Configure spire-controller-manager with staticManifestPath set (any non-empty value). After the static reconcilers complete, the manager starts briefly then panics:
panic: close of closed channel
goroutine 1 [running]:
sigs.k8s.io/controller-runtime/pkg/manager/signals.SetupSignalHandler()
.../controller-runtime@v0.22.4/pkg/manager/signals/signal.go:31 +0x1e
main.run(...)
/workspace/cmd/main.go:274 +0xa5
main.main()
/workspace/cmd/main.go:107 +0xfd
Root Cause
In cmd/main.go:
// line 101
if mainConfig.ctrlConfig.StaticManifestPath != nil {
if err := staticRun(mainConfig); err != nil { // calls SetupSignalHandler() at line 495
os.Exit(1)
}
}
if err := run(mainConfig); err != nil { // calls SetupSignalHandler() again at line 274
os.Exit(1)
}
staticRun completes its full reconciliation and returns, then run is called and hits SetupSignalHandler a second time.
Potential Fix
Since staticRun and run appear to be mutually exclusive lifecycle paths, main() could exit after staticRun returns rather than falling through to run():
if mainConfig.ctrlConfig.StaticManifestPath != nil {
if err := staticRun(mainConfig); err != nil {
os.Exit(1)
}
os.Exit(0)
}
Happy to submit a PR if this approach looks reasonable to maintainers.
Observed Behaviour
- Controller-manager reconciles all static entries successfully
- Manager starts, briefly binds metrics (
:8082) and health (:8083) ports
- Immediately panics, process exits with code 2
- Pod enters a crash loop (every ~3 minutes in our environment with ~10k entries)
Version
v0.6.4 (latest). Same code present in main branch.
Description
When
staticManifestPathis configured (i.e.staticManifestModeis not"off"),main()calls bothstaticRun()andrun()sequentially. Both functions callctrl.SetupSignalHandler(). Thecontroller-runtimesignal handler uses a package-levelsync.Onceand panics on the second call withpanic: close of closed channel.Reproduction
Configure
spire-controller-managerwithstaticManifestPathset (any non-empty value). After the static reconcilers complete, the manager starts briefly then panics:Root Cause
In
cmd/main.go:staticRuncompletes its full reconciliation and returns, thenrunis called and hitsSetupSignalHandlera second time.Potential Fix
Since
staticRunandrunappear to be mutually exclusive lifecycle paths,main()could exit afterstaticRunreturns rather than falling through torun():Happy to submit a PR if this approach looks reasonable to maintainers.
Observed Behaviour
:8082) and health (:8083) portsVersion
v0.6.4(latest). Same code present inmainbranch.