// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package envknob provides access to environment-variable tweakable // debug settings. // // These are primarily knobs used by Tailscale developers during // development or by users when instructed to by Tailscale developers // when debugging something. They are not a stable interface and may // be removed or any time. // // A related package, control/controlknobs, are knobs that can be // changed at runtime by the control plane. Sometimes both are used: // an envknob for the default/explicit value, else falling back // to the controlknob value. package envknob import ( "log" "os" "strconv" "tailscale.com/types/opt" ) // String returns the named environment variable, using os.Getenv. // // In the future it will also track usage for reporting on debug pages. func String(envVar string) string { return os.Getenv(envVar) } // Bool returns the boolean value of the named environment variable. // If the variable is not set, it returns false. // An invalid value exits the binary with a failure. func Bool(envVar string) bool { return boolOr(envVar, false) } // BoolDefaultTrue is like Bool, but returns true by default if the // environment variable isn't present. func BoolDefaultTrue(envVar string) bool { return boolOr(envVar, true) } func boolOr(envVar string, implicitValue bool) bool { val := os.Getenv(envVar) if val == "" { return implicitValue } b, err := strconv.ParseBool(val) if err == nil { return b } log.Fatalf("invalid boolean environment variable %s value %q", envVar, val) panic("unreachable") } // LookupBool returns the boolean value of the named environment value. // The ok result is whether a value was set. // If the value isn't a valid int, it exits the program with a failure. func LookupBool(envVar string) (v bool, ok bool) { val := os.Getenv(envVar) if val == "" { return false, false } b, err := strconv.ParseBool(val) if err == nil { return b, true } log.Fatalf("invalid boolean environment variable %s value %q", envVar, val) panic("unreachable") } // OptBool is like Bool, but returns an opt.Bool, so the caller can // distinguish between implicitly and explicitly false. func OptBool(envVar string) opt.Bool { b, ok := LookupBool(envVar) if !ok { return "" } var ret opt.Bool ret.Set(b) return ret } // LookupInt returns the integer value of the named environment value. // The ok result is whether a value was set. // If the value isn't a valid int, it exits the program with a failure. func LookupInt(envVar string) (v int, ok bool) { val := os.Getenv(envVar) if val == "" { return 0, false } v, err := strconv.Atoi(val) if err == nil { return v, true } log.Fatalf("invalid integer environment variable %s: %v", envVar, val) panic("unreachable") } // UseWIPCode is whether TAILSCALE_USE_WIP_CODE is set to permit use // of Work-In-Progress code. func UseWIPCode() bool { return Bool("TAILSCALE_USE_WIP_CODE") }