Skip to content

Configuration

The values that change what Reactor observes or how it behaves. Every value the chart takes, with the note written above it in values.yaml, is in the Chart values reference:

ValueDefaultDescription
crds.installtrueinstall and upgrade the Automation CRD with the release
crds.adopttrueon the first upgrade from chart 0.3.0 or earlier, take the CRD that packaging left owned by no release into this one
unifi.urlUniFi console base URL; the provider stays disabled until this is set
unifi.sitedefaultUniFi Network site
unifi.pollInterval30show often WAN, internet and UPS state are observed
unifi.maxObservationAge""how old the observed state may get before every automation reports ObservationStale and says so. Empty is unbounded — and silent (above)
unifi.insecureSkipVerifytrueaccept the console’s self-signed certificate
unifi.existingSecretunifi-reactor-credentialsSecret holding UNIFI_API_KEY; re-read on every poll, so rotating the key needs no restart
log.levelinfodebug adds the per-observation lines used to work out why an automation did not fire
unifi.ups.lowBatteryPercent30charge at or below this reports ups.battery: low
unifi.ups.criticalBatteryPercent10charge at or below this reports ups.battery: critical
unifi.ups.shortRuntimeSeconds600remaining runtime at or below this reports ups.runtime: short
unifi.ups.criticalRuntimeSeconds180remaining runtime at or below this reports ups.runtime: critical
unifi.ups.highLoadPercent80draw at or above this share of the power budget reports ups.load: high
unifi.wan.quality.minAvailabilityPercent99availability below this reports wan.quality: degraded
unifi.wan.quality.maxLatencyMs150average latency above this reports wan.quality: degraded
unifi.temperature.highCelsius75hottest adopted device at or above this reports temperature: high
unifi.poe.maxUtilizationPercent90a switch delivering at or above this share of its PoE budget reports poe: insufficient
unifi.devices.perDeviceKeysfalsealso publish a device.<name> key per adopted device — one more series per device
unifi.webhook.enabledfalsewebhook fast path (below)
actions.allowedDestinations[]where outbound actions may go. Empty refuses all of them, and withholds the operator’s read access to Secrets (why)
metrics.enabledfalseserve /metrics on :8443 over HTTPS behind the API server’s authn/authz filter (above)
metrics.serviceMonitor.enabledfalsescrape it with the Prometheus Operator
metrics.rules.enabledfalseship the alert rules, ReactorObservationStale first
metrics.dashboard.enabledfalseship the overview dashboard as a grafana-operator GrafanaDashboard
rbac.clusterWidetruewhen false, restricts the operator to its own namespace
safety.dryRunfalseevaluate and report everything, write nothing, and withhold the permissions that could (above)
safety.detectHPAfalsenotice a HorizontalPodAutoscaler driving a target and decline it rather than fight (above)

Automation resources are namespaced. An action targets its own namespace by default; naming a different one in target.namespace requires rbac.clusterWide: true.

log.level takes debug, info (the default), error, or a V-level number. debug turns on the per-observation lines — what each poll saw, and why a transition did or did not happen — which is what you want when an automation did not fire:

Terminal window
helm upgrade reactor oci://ghcr.io/robbeverhelst/charts/reactor \
--namespace reactor-system --reuse-values --set log.level=debug

log.format: json switches the encoder for a log collector.

Charts up to 0.3.0 hardcoded the manager’s arguments and ran at debug; the default is now info. --set log.level=debug restores the previous output.

The key is mounted from unifi.existingSecret and re-read on every poll, so rotation takes effect on its own — no restart, no second controller, nothing for anyone to remember:

Terminal window
kubectl -n reactor-system create secret generic unifi-reactor-credentials \
--from-literal=UNIFI_API_KEY=<new key> \
--dry-run=client -o yaml | kubectl -n reactor-system apply -f -

The kubelet refreshes the mounted file within its sync period (about a minute by default) and the next poll authenticates with the new key. Revoke the old key in the UniFi UI once you see polling continue. If the file is ever unreadable or empty, that poll fails and is logged; the next one retries.

If you would rather have the pod restart on change — because you already run reloader, say — annotate the Deployment instead:

annotations:
secret.reloader.stakater.com/reload: unifi-reactor-credentials

Off by default, because with one replica a budget cannot protect anything: minAvailable: 1 turns a node drain into a hang. Run two replicas and enable it — leader election keeps exactly one instance acting, so the second is a warm standby:

replicaCount: 2
podDisruptionBudget:
enabled: true
minAvailable: 1