summaryrefslogtreecommitdiffhomepage
path: root/control/controlknobs/controlknobs.go
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2025-01-26 18:23:38 +0000
committerBrad Fitzpatrick <brad@danga.com>2025-01-26 18:49:11 +0000
commite701fde6b389a4a69b4d33aace8969530b25de8d (patch)
treec61e69301d643816bb7c794ff1827b6988345099 /control/controlknobs/controlknobs.go
parent66b2e9fd07f2c635b809aa82d657fd82de3f9323 (diff)
downloadtailscale-e701fde6b389a4a69b4d33aace8969530b25de8d.tar.xz
tailscale-e701fde6b389a4a69b4d33aace8969530b25de8d.zip
control/controlknobs: make Knobs.AsDebugJSON automatic, not require maintenance
The AsDebugJSON method (used only for a LocalAPI debug call) always needed to be updated whenever a new controlknob was added. We had a test for it, which was nice, but it was a tedious step we don't need to do. Use reflect instead. Updates #14788 Change-Id: If59cd776920f3ce7c748f86ed2eddd9323039a0b Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'control/controlknobs/controlknobs.go')
-rw-r--r--control/controlknobs/controlknobs.go37
1 files changed, 16 insertions, 21 deletions
diff --git a/control/controlknobs/controlknobs.go b/control/controlknobs/controlknobs.go
index c7933be5a..a86f0af53 100644
--- a/control/controlknobs/controlknobs.go
+++ b/control/controlknobs/controlknobs.go
@@ -6,6 +6,8 @@
package controlknobs
import (
+ "fmt"
+ "reflect"
"sync/atomic"
"tailscale.com/syncs"
@@ -174,26 +176,19 @@ func (k *Knobs) AsDebugJSON() map[string]any {
if k == nil {
return nil
}
- return map[string]any{
- "DisableUPnP": k.DisableUPnP.Load(),
- "KeepFullWGConfig": k.KeepFullWGConfig.Load(),
- "RandomizeClientPort": k.RandomizeClientPort.Load(),
- "OneCGNAT": k.OneCGNAT.Load(),
- "ForceBackgroundSTUN": k.ForceBackgroundSTUN.Load(),
- "DisableDeltaUpdates": k.DisableDeltaUpdates.Load(),
- "PeerMTUEnable": k.PeerMTUEnable.Load(),
- "DisableDNSForwarderTCPRetries": k.DisableDNSForwarderTCPRetries.Load(),
- "SilentDisco": k.SilentDisco.Load(),
- "LinuxForceIPTables": k.LinuxForceIPTables.Load(),
- "LinuxForceNfTables": k.LinuxForceNfTables.Load(),
- "SeamlessKeyRenewal": k.SeamlessKeyRenewal.Load(),
- "ProbeUDPLifetime": k.ProbeUDPLifetime.Load(),
- "AppCStoreRoutes": k.AppCStoreRoutes.Load(),
- "UserDialUseRoutes": k.UserDialUseRoutes.Load(),
- "DisableSplitDNSWhenNoCustomResolvers": k.DisableSplitDNSWhenNoCustomResolvers.Load(),
- "DisableLocalDNSOverrideViaNRPT": k.DisableLocalDNSOverrideViaNRPT.Load(),
- "DisableCryptorouting": k.DisableCryptorouting.Load(),
- "DisableCaptivePortalDetection": k.DisableCaptivePortalDetection.Load(),
- "DisableSkipStatusQueue": k.DisableSkipStatusQueue.Load(),
+ ret := map[string]any{}
+ rt := reflect.TypeFor[Knobs]()
+ rv := reflect.ValueOf(k).Elem() // of *k
+ for i := 0; i < rt.NumField(); i++ {
+ name := rt.Field(i).Name
+ switch v := rv.Field(i).Addr().Interface().(type) {
+ case *atomic.Bool:
+ ret[name] = v.Load()
+ case *syncs.AtomicValue[opt.Bool]:
+ ret[name] = v.Load()
+ default:
+ panic(fmt.Sprintf("unknown field type %T for %v", v, name))
+ }
}
+ return ret
}