envknob: add new package for all the strconv.ParseBool(os.Getenv(..))

A new package can also later record/report which knobs are checked and
set. It also makes the code cleaner & easier to grep for env knobs.

Change-Id: Id8a123ab7539f1fadbd27e0cbeac79c2e4f09751
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2022-01-24 10:52:57 -08:00 committed by Brad Fitzpatrick
parent 6feb8f4c51
commit 41fd4eab5c
39 changed files with 195 additions and 128 deletions

View File

@ -16,7 +16,6 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"unicode/utf8"
@ -26,6 +25,7 @@ import (
"inet.af/netaddr"
"tailscale.com/client/tailscale"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
@ -148,7 +148,7 @@ func runCp(ctx context.Context, args []string) error {
name = filepath.Base(fileArg)
}
if slow, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_SLOW_PUSH")); slow {
if envknob.Bool("TS_DEBUG_SLOW_PUSH") {
fileContents = &slowReader{r: fileContents}
}
}

View File

@ -13,13 +13,13 @@ import (
"io/ioutil"
"log"
"net/http"
"os"
"sort"
"strings"
"time"
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/client/tailscale"
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/net/netcheck"
"tailscale.com/net/portmapper"
@ -49,7 +49,7 @@ var netcheckArgs struct {
func runNetcheck(ctx context.Context, args []string) error {
c := &netcheck.Client{
UDPBindAddr: os.Getenv("TS_DEBUG_NETCHECK_UDP_BIND"),
UDPBindAddr: envknob.String("TS_DEBUG_NETCHECK_UDP_BIND"),
PortMapper: portmapper.NewClient(logger.WithPrefix(log.Printf, "portmap: "), nil),
}
if netcheckArgs.verbose {

View File

@ -38,6 +38,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/derp/derphttp from tailscale.com/net/netcheck
L tailscale.com/derp/wsconn from tailscale.com/derp/derphttp
tailscale.com/disco from tailscale.com/derp
tailscale.com/envknob from tailscale.com/cmd/tailscale/cli+
tailscale.com/hostinfo from tailscale.com/net/interfaces
tailscale.com/ipn from tailscale.com/cmd/tailscale/cli+
tailscale.com/ipn/ipnstate from tailscale.com/cmd/tailscale/cli+

View File

@ -24,6 +24,7 @@ import (
"inet.af/netaddr"
"tailscale.com/derp/derphttp"
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/net/interfaces"
"tailscale.com/net/portmapper"
@ -224,7 +225,7 @@ func debugPortmap(ctx context.Context) error {
defer cancel()
portmapper.VerboseLogs = true
switch os.Getenv("TS_DEBUG_PORTMAP_TYPE") {
switch envknob.String("TS_DEBUG_PORTMAP_TYPE") {
case "":
case "pmp":
portmapper.DisablePCP = true

View File

@ -171,6 +171,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/derp/derphttp from tailscale.com/cmd/tailscaled+
L tailscale.com/derp/wsconn from tailscale.com/derp/derphttp
tailscale.com/disco from tailscale.com/derp+
tailscale.com/envknob from tailscale.com/cmd/tailscaled+
tailscale.com/health from tailscale.com/control/controlclient+
tailscale.com/hostinfo from tailscale.com/control/controlclient+
tailscale.com/ipn from tailscale.com/client/tailscale+

View File

@ -23,12 +23,12 @@ import (
"path/filepath"
"runtime"
"runtime/debug"
"strconv"
"strings"
"syscall"
"time"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnserver"
"tailscale.com/logpolicy"
@ -224,7 +224,7 @@ func statePathOrDefault() string {
func ipnServerOpts() (o ipnserver.Options) {
// Allow changing the OS-specific IPN behavior for tests
// so we can e.g. test Windows-specific behaviors on Linux.
goos := os.Getenv("TS_DEBUG_TAILSCALED_IPN_GOOS")
goos := envknob.String("TS_DEBUG_TAILSCALED_IPN_GOOS")
if goos == "" {
goos = runtime.GOOS
}
@ -272,13 +272,13 @@ func run() error {
}
var logf logger.Logf = log.Printf
if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_MEMORY")); v {
if envknob.Bool("TS_DEBUG_MEMORY") {
logf = logger.RusagePrefixLog(logf)
}
logf = logger.RateLimitedFn(logf, 5*time.Second, 5, 100)
if args.cleanup {
if os.Getenv("TS_PLEASE_PANIC") != "" {
if envknob.Bool("TS_PLEASE_PANIC") {
panic("TS_PLEASE_PANIC asked us to panic")
}
dns.Cleanup(logf, args.tunname)
@ -431,11 +431,7 @@ func createEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer)
var wrapNetstack = shouldWrapNetstack()
func shouldWrapNetstack() bool {
if e := os.Getenv("TS_DEBUG_WRAP_NETSTACK"); e != "" {
v, err := strconv.ParseBool(e)
if err != nil {
log.Fatalf("invalid TS_DEBUG_WRAP_NETSTACK value: %v", err)
}
if v, ok := envknob.LookupBool("TS_DEBUG_WRAP_NETSTACK"); ok {
return v
}
if distro.Get() == distro.Synology {

View File

@ -29,6 +29,7 @@ import (
"golang.org/x/sys/windows/svc"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/ipn/ipnserver"
"tailscale.com/logpolicy"
"tailscale.com/net/dns"
@ -314,7 +315,7 @@ func startIPNServer(ctx context.Context, logid string) error {
// not called concurrently and is not called again once it
// successfully returns an engine.
getEngine := func() (wgengine.Engine, error) {
if msg := os.Getenv("TS_DEBUG_WIN_FAIL"); msg != "" {
if msg := envknob.String("TS_DEBUG_WIN_FAIL"); msg != "" {
return nil, fmt.Errorf("pretending to be a service failure: %v", msg)
}
for {

View File

@ -21,7 +21,6 @@ import (
"os/exec"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
@ -30,6 +29,7 @@ import (
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/control/controlknobs"
"tailscale.com/envknob"
"tailscale.com/health"
"tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate"
@ -874,8 +874,8 @@ func decode(res *http.Response, v interface{}, serverKey key.MachinePublic, mkey
}
var (
debugMap, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_MAP"))
debugRegister, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_REGISTER"))
debugMap = envknob.Bool("TS_DEBUG_MAP")
debugRegister = envknob.Bool("TS_DEBUG_REGISTER")
)
var jsonEscapedZero = []byte(`\u0000`)
@ -985,26 +985,14 @@ type debug struct {
func initDebug() debug {
return debug{
NetMap: envBool("TS_DEBUG_NETMAP"),
ProxyDNS: envBool("TS_DEBUG_PROXY_DNS"),
StripEndpoints: envBool("TS_DEBUG_STRIP_ENDPOINTS"),
StripCaps: envBool("TS_DEBUG_STRIP_CAPS"),
Disco: os.Getenv("TS_DEBUG_USE_DISCO") == "" || envBool("TS_DEBUG_USE_DISCO"),
NetMap: envknob.Bool("TS_DEBUG_NETMAP"),
ProxyDNS: envknob.Bool("TS_DEBUG_PROXY_DNS"),
StripEndpoints: envknob.Bool("TS_DEBUG_STRIP_ENDPOINTS"),
StripCaps: envknob.Bool("TS_DEBUG_STRIP_CAPS"),
Disco: envknob.BoolDefaultTrue("TS_DEBUG_USE_DISCO"),
}
}
func envBool(k string) bool {
e := os.Getenv(k)
if e == "" {
return false
}
v, err := strconv.ParseBool(e)
if err != nil {
panic(fmt.Sprintf("invalid non-bool %q for env var %q", e, k))
}
return v
}
var clockNow = time.Now
// opt.Bool configs from control.

View File

@ -6,11 +6,10 @@ package controlclient
import (
"log"
"os"
"sort"
"strconv"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/tailcfg"
"tailscale.com/types/key"
"tailscale.com/types/logger"
@ -289,7 +288,7 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
return v2
}
var debugSelfIPv6Only, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_SELF_V6_ONLY"))
var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY")
func filterSelfAddresses(in []netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
switch {

View File

@ -7,9 +7,7 @@
package controlknobs
import (
"os"
"strconv"
"tailscale.com/envknob"
"tailscale.com/syncs"
)
@ -17,8 +15,7 @@ import (
var disableUPnP syncs.AtomicBool
func init() {
v, _ := strconv.ParseBool(os.Getenv("TS_DISABLE_UPNP"))
SetDisableUPnP(v)
SetDisableUPnP(envknob.Bool("TS_DISABLE_UPNP"))
}
// DisableUPnP reports the last reported value from control

View File

@ -25,7 +25,6 @@ import (
"math/rand"
"net"
"net/http"
"os"
"os/exec"
"runtime"
"strconv"
@ -40,6 +39,7 @@ import (
"inet.af/netaddr"
"tailscale.com/client/tailscale"
"tailscale.com/disco"
"tailscale.com/envknob"
"tailscale.com/metrics"
"tailscale.com/syncs"
"tailscale.com/types/key"
@ -48,14 +48,14 @@ import (
"tailscale.com/version"
)
var debug, _ = strconv.ParseBool(os.Getenv("DERP_DEBUG_LOGS"))
var debug = envknob.Bool("DERP_DEBUG_LOGS")
// verboseDropKeys is the set of destination public keys that should
// verbosely log whenever DERP drops a packet.
var verboseDropKeys = map[key.NodePublic]bool{}
func init() {
keys := os.Getenv("TS_DEBUG_VERBOSE_DROPS")
keys := envknob.String("TS_DEBUG_VERBOSE_DROPS")
if keys == "" {
return
}

View File

@ -23,9 +23,7 @@ import (
"net"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
@ -33,6 +31,7 @@ import (
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/derp"
"tailscale.com/envknob"
"tailscale.com/net/dnscache"
"tailscale.com/net/netns"
"tailscale.com/net/tlsdial"
@ -190,8 +189,7 @@ func useWebsockets() bool {
return true
}
if dialWebsocketFunc != nil {
v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_DERP_WS_CLIENT"))
return v
return envknob.Bool("TS_DEBUG_DERP_WS_CLIENT")
}
return false
}

102
envknob/envknob.go Normal file
View File

@ -0,0 +1,102 @@
// 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 environment variable %s value %q: %v", envVar, val, err)
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 environment variable %s value %q: %v", envVar, val, err)
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 environment variable %s value %q: %v", envVar, val, err)
panic("unreachable")
}

View File

@ -10,13 +10,13 @@ import (
"errors"
"fmt"
"net/http"
"os"
"runtime"
"sort"
"sync"
"sync/atomic"
"time"
"tailscale.com/envknob"
"tailscale.com/tailcfg"
"tailscale.com/util/multierr"
)
@ -308,7 +308,7 @@ func OverallError() error {
return overallErrorLocked()
}
var fakeErrForTesting = os.Getenv("TS_DEBUG_FAKE_HEALTH_ERROR")
var fakeErrForTesting = envknob.String("TS_DEBUG_FAKE_HEALTH_ERROR")
func overallErrorLocked() error {
if !anyInterfaceUp {

View File

@ -27,6 +27,7 @@ import (
"inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
"tailscale.com/health"
"tailscale.com/hostinfo"
"tailscale.com/ipn"
@ -64,7 +65,7 @@ import (
var controlDebugFlags = getControlDebugFlags()
func getControlDebugFlags() []string {
if e := os.Getenv("TS_DEBUG_CONTROL_FLAGS"); e != "" {
if e := envknob.String("TS_DEBUG_CONTROL_FLAGS"); e != "" {
return strings.Split(e, ",")
}
return nil
@ -1349,7 +1350,7 @@ func (b *LocalBackend) popBrowserAuthNow() {
}
// For testing lazy machine key generation.
var panicOnMachineKeyGeneration, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_PANIC_MACHINE_KEY"))
var panicOnMachineKeyGeneration = envknob.Bool("TS_DEBUG_PANIC_MACHINE_KEY")
func (b *LocalBackend) createGetMachinePrivateKeyFunc() func() (key.MachinePrivate, error) {
var cache atomic.Value

View File

@ -29,12 +29,12 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/crypto/acme"
"tailscale.com/envknob"
"tailscale.com/ipn/ipnstate"
"tailscale.com/types/logger"
)
@ -63,7 +63,7 @@ func (h *Handler) certDir() (string, error) {
return full, nil
}
var acmeDebug, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_ACME"))
var acmeDebug = envknob.Bool("TS_DEBUG_ACME")
func (h *Handler) serveCert(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite {

View File

@ -25,13 +25,13 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/term"
"tailscale.com/atomicfile"
"tailscale.com/envknob"
"tailscale.com/log/filelogger"
"tailscale.com/logtail"
"tailscale.com/logtail/filch"
@ -227,7 +227,7 @@ func runningUnderSystemd() bool {
}
func redirectStderrToLogPanics() bool {
return runningUnderSystemd() || os.Getenv("TS_PLEASE_PANIC") != ""
return runningUnderSystemd() || envknob.Bool("TS_PLEASE_PANIC")
}
// winProgramDataAccessible reports whether the directory (assumed to
@ -405,7 +405,7 @@ func New(collection string) *Policy {
} else {
lflags = log.LstdFlags
}
if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_LOG_TIME")); v {
if envknob.Bool("TS_DEBUG_LOG_TIME") {
lflags = log.LstdFlags | log.Lmicroseconds
}
if runningUnderSystemd() {
@ -670,7 +670,7 @@ func NewLogtailTransport(host string) *http.Transport {
// TODO(bradfitz): remove this debug knob once we've decided
// to upload via HTTP/1 or HTTP/2 (probably HTTP/1). Or we might just enforce
// it server-side.
if h1, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_FORCE_H1_LOGS")); h1 {
if envknob.Bool("TS_DEBUG_FORCE_H1_LOGS") {
tr.TLSClientConfig = nil // DefaultTransport's was already initialized w/ h2
tr.ForceAttemptHTTP2 = false
tr.TLSNextProto = map[string]func(authority string, c *tls.Conn) http.RoundTripper{}

View File

@ -7,10 +7,8 @@ package dns
import (
"errors"
"fmt"
"os"
"os/exec"
"sort"
"strconv"
"strings"
"syscall"
"time"
@ -19,6 +17,7 @@ import (
"golang.org/x/sys/windows/registry"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
)
@ -36,7 +35,7 @@ const (
versionKey = `SOFTWARE\Microsoft\Windows NT\CurrentVersion`
)
var configureWSL, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_CONFIGURE_WSL"))
var configureWSL = envknob.Bool("TS_DEBUG_CONFIGURE_WSL")
type windowsManager struct {
logf logger.Logf

View File

@ -15,14 +15,13 @@ import (
"fmt"
"log"
"net"
"os"
"runtime"
"strconv"
"sync"
"time"
"golang.org/x/sync/singleflight"
"inet.af/netaddr"
"tailscale.com/envknob"
)
var single = &Resolver{
@ -100,7 +99,7 @@ func (r *Resolver) ttl() time.Duration {
return 10 * time.Minute
}
var debug, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DNS_CACHE"))
var debug = envknob.Bool("TS_DEBUG_DNS_CACHE")
// LookupIP returns the host's primary IP address (either IPv4 or
// IPv6, but preferring IPv4) and optionally its IPv6 address, if

View File

@ -16,16 +16,15 @@ import (
"log"
"net"
"net/http"
"os"
"runtime"
"sort"
"strconv"
"sync"
"time"
"github.com/tcnksm/go-httpstat"
"inet.af/netaddr"
"tailscale.com/derp/derphttp"
"tailscale.com/envknob"
"tailscale.com/net/interfaces"
"tailscale.com/net/neterror"
"tailscale.com/net/netns"
@ -40,7 +39,7 @@ import (
// Debugging and experimentation tweakables.
var (
debugNetcheck, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_NETCHECK"))
debugNetcheck = envknob.Bool("TS_DEBUG_NETCHECK")
)
// The various default timeouts for things.

View File

@ -17,10 +17,11 @@ import (
"errors"
"log"
"os"
"strconv"
"sync"
"sync/atomic"
"time"
"tailscale.com/envknob"
)
var counterFallbackOK int32 // atomic
@ -31,7 +32,7 @@ var counterFallbackOK int32 // atomic
// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
var sslKeyLogFile = os.Getenv("SSLKEYLOGFILE")
var debug, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_TLS_DIAL"))
var debug = envknob.Bool("TS_DEBUG_TLS_DIAL")
// Config returns a tls.Config for connecting to a server.
// If base is non-nil, it's cloned as the base config before

View File

@ -11,13 +11,12 @@ package tstun
import (
"errors"
"os"
"runtime"
"strconv"
"strings"
"time"
"golang.zx2c4.com/wireguard/tun"
"tailscale.com/envknob"
"tailscale.com/types/logger"
)
@ -32,7 +31,7 @@ import (
var tunMTU = 1280
func init() {
if mtu, _ := strconv.Atoi(os.Getenv("TS_DEBUG_MTU")); mtu != 0 {
if mtu, ok := envknob.LookupInt("TS_DEBUG_MTU"); ok {
tunMTU = mtu
}
}

View File

@ -6,10 +6,10 @@ package portlist
import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"tailscale.com/envknob"
)
// Port is a listening port on the machine.
@ -74,7 +74,7 @@ func (pl List) String() string {
return strings.TrimRight(sb.String(), "\n")
}
var debugDisablePortlist, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DISABLE_PORTLIST"))
var debugDisablePortlist = envknob.Bool("TS_DEBUG_DISABLE_PORTLIST")
func GetList(prev List) (List, error) {
if debugDisablePortlist {

View File

@ -10,7 +10,7 @@
check_file() {
got=$1
for year in `seq 2019 2021`; do
for year in `seq 2019 2022`; do
want=$(cat <<EOF
// Copyright (c) $year Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style

View File

@ -14,6 +14,7 @@ import (
_ "inet.af/netaddr"
_ "tailscale.com/chirp"
_ "tailscale.com/derp/derphttp"
_ "tailscale.com/envknob"
_ "tailscale.com/ipn"
_ "tailscale.com/ipn/ipnserver"
_ "tailscale.com/logpolicy"

View File

@ -14,6 +14,7 @@ import (
_ "inet.af/netaddr"
_ "tailscale.com/chirp"
_ "tailscale.com/derp/derphttp"
_ "tailscale.com/envknob"
_ "tailscale.com/ipn"
_ "tailscale.com/ipn/ipnserver"
_ "tailscale.com/logpolicy"

View File

@ -14,6 +14,7 @@ import (
_ "inet.af/netaddr"
_ "tailscale.com/chirp"
_ "tailscale.com/derp/derphttp"
_ "tailscale.com/envknob"
_ "tailscale.com/ipn"
_ "tailscale.com/ipn/ipnserver"
_ "tailscale.com/logpolicy"

View File

@ -14,6 +14,7 @@ import (
_ "inet.af/netaddr"
_ "tailscale.com/chirp"
_ "tailscale.com/derp/derphttp"
_ "tailscale.com/envknob"
_ "tailscale.com/ipn"
_ "tailscale.com/ipn/ipnserver"
_ "tailscale.com/logpolicy"

View File

@ -17,6 +17,7 @@ import (
_ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
_ "inet.af/netaddr"
_ "tailscale.com/derp/derphttp"
_ "tailscale.com/envknob"
_ "tailscale.com/ipn"
_ "tailscale.com/ipn/ipnserver"
_ "tailscale.com/logpolicy"

View File

@ -25,6 +25,7 @@ import (
"time"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/metrics"
"tailscale.com/net/tsaddr"
"tailscale.com/types/logger"
@ -70,12 +71,12 @@ func AllowDebugAccess(r *http.Request) bool {
if err != nil {
return false
}
if tsaddr.IsTailscaleIP(ip) || ip.IsLoopback() || ipStr == os.Getenv("TS_ALLOW_DEBUG_IP") {
if tsaddr.IsTailscaleIP(ip) || ip.IsLoopback() || ipStr == envknob.String("TS_ALLOW_DEBUG_IP") {
return true
}
if r.Method == "GET" {
urlKey := r.FormValue("debugkey")
keyPath := os.Getenv("TS_DEBUG_KEY_PATH")
keyPath := envknob.String("TS_DEBUG_KEY_PATH")
if urlKey != "" && keyPath != "" {
slurp, err := ioutil.ReadFile(keyPath)
if err == nil && string(bytes.TrimSpace(slurp)) == urlKey {

View File

@ -14,12 +14,13 @@ import (
"io"
"io/ioutil"
"log"
"os"
"strings"
"sync"
"time"
"context"
"tailscale.com/envknob"
)
// Logf is the basic Tailscale logger type: a printf-like func.
@ -83,7 +84,7 @@ type limitData struct {
ele *list.Element // list element used to access this string in the cache
}
var disableRateLimit = os.Getenv("TS_DEBUG_LOG_RATE") == "all"
var disableRateLimit = envknob.String("TS_DEBUG_LOG_RATE") == "all"
// rateFree are format string substrings that are exempt from rate limiting.
// Things should not be added to this unless they're already limited otherwise

View File

@ -7,11 +7,11 @@ package filter
import (
"fmt"
"os"
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/net/flowtrack"
"tailscale.com/net/packet"
"tailscale.com/tstime/rate"
@ -225,7 +225,7 @@ var dropBucket = rate.NewLimiter(rate.Every(5*time.Second), 10)
// effectively disable the limits on the log rate by setting the limit
// to 1 millisecond. This should capture everything.
func init() {
if os.Getenv("TS_DEBUG_FILTER_RATE_LIMIT_LOGS") != "all" {
if envknob.String("TS_DEBUG_FILTER_RATE_LIMIT_LOGS") != "all" {
return
}

View File

@ -8,8 +8,7 @@
package magicsock
import (
"os"
"strconv"
"tailscale.com/envknob"
)
// Various debugging and experimental tweakables, set by environment
@ -17,25 +16,23 @@ import (
var (
// debugDisco prints verbose logs of active discovery events as
// they happen.
debugDisco, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DISCO"))
debugDisco = envknob.Bool("TS_DEBUG_DISCO")
// debugOmitLocalAddresses removes all local interface addresses
// from magicsock's discovered local endpoints. Used in some tests.
debugOmitLocalAddresses, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_OMIT_LOCAL_ADDRS"))
debugOmitLocalAddresses = envknob.Bool("TS_DEBUG_OMIT_LOCAL_ADDRS")
// debugUseDerpRoute temporarily (2020-03-22) controls whether DERP
// reverse routing is enabled (Issue 150). It will become always true
// later.
debugUseDerpRouteEnv = os.Getenv("TS_DEBUG_ENABLE_DERP_ROUTE")
debugUseDerpRoute, _ = strconv.ParseBool(debugUseDerpRouteEnv)
// reverse routing is enabled (Issue 150).
debugUseDerpRoute = envknob.OptBool("TS_DEBUG_ENABLE_DERP_ROUTE")
// logDerpVerbose logs all received DERP packets, including their
// full payload.
logDerpVerbose, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DERP"))
logDerpVerbose = envknob.Bool("TS_DEBUG_DERP")
// debugReSTUNStopOnIdle unconditionally enables the "shut down
// STUN if magicsock is idle" behavior that normally only triggers
// on mobile devices, lowers the shutdown interval, and logs more
// verbosely about idle measurements.
debugReSTUNStopOnIdle, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_RESTUN_STOP_ON_IDLE"))
debugReSTUNStopOnIdle = envknob.Bool("TS_DEBUG_RESTUN_STOP_ON_IDLE")
// debugAlwaysDERP disables the use of UDP, forcing all peer communication over DERP.
debugAlwaysDERP, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_ALWAYS_USE_DERP"))
debugAlwaysDERP = envknob.Bool("TS_DEBUG_ALWAYS_USE_DERP")
)
// inTest reports whether the running program is a test that set the
@ -44,7 +41,4 @@ var (
// Unlike the other debug tweakables above, this one needs to be
// checked every time at runtime, because tests set this after program
// startup.
func inTest() bool {
inTest, _ := strconv.ParseBool(os.Getenv("IN_TS_TEST"))
return inTest
}
func inTest() bool { return envknob.Bool("IN_TS_TEST") }

View File

@ -61,8 +61,8 @@ import (
// useDerpRoute reports whether magicsock should enable the DERP
// return path optimization (Issue 150).
func useDerpRoute() bool {
if debugUseDerpRouteEnv != "" {
return debugUseDerpRoute
if b, ok := debugUseDerpRoute.Get(); ok {
return b
}
ob := controlclient.DERPRouteFlag()
if v, ok := ob.Get(); ok {

View File

@ -34,6 +34,7 @@ import (
"inet.af/netstack/tcpip/transport/tcp"
"inet.af/netstack/tcpip/transport/udp"
"inet.af/netstack/waiter"
"tailscale.com/envknob"
"tailscale.com/net/packet"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial"
@ -49,7 +50,7 @@ import (
const debugPackets = false
var debugNetstack, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_NETSTACK"))
var debugNetstack = envknob.Bool("TS_DEBUG_NETSTACK")
// Impl contains the state for the netstack implementation,
// and implements wgengine.FakeImpl to act as a userspace network

View File

@ -6,9 +6,7 @@ package wgengine
import (
"fmt"
"os"
"runtime"
"strconv"
"time"
"tailscale.com/ipn/ipnstate"
@ -22,17 +20,6 @@ import (
const tcpTimeoutBeforeDebug = 5 * time.Second
// debugConnectFailures reports whether the local node should track
// outgoing TCP connections and log which ones fail and why.
func debugConnectFailures() bool {
s := os.Getenv("TS_DEBUG_CONNECT_FAILURES")
if s == "" {
return true
}
v, _ := strconv.ParseBool(s)
return v
}
type pendingOpenFlow struct {
timer *time.Timer // until giving up on the flow

View File

@ -22,6 +22,7 @@ import (
"golang.org/x/time/rate"
"golang.zx2c4.com/wireguard/tun"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/net/tsaddr"
"tailscale.com/syncs"
"tailscale.com/types/logger"
@ -188,7 +189,7 @@ func useAmbientCaps() bool {
return v >= 7
}
var forceIPCommand, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_USE_IP_COMMAND"))
var forceIPCommand = envknob.Bool("TS_DEBUG_USE_IP_COMMAND")
// useIPCommand reports whether r should use the "ip" command (or its
// fake commandRunner for tests) instead of netlink.

View File

@ -11,10 +11,8 @@ import (
"errors"
"fmt"
"io"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
@ -25,6 +23,7 @@ import (
"golang.zx2c4.com/wireguard/tun"
"inet.af/netaddr"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
"tailscale.com/health"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns"
@ -366,7 +365,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
}
e.tundev.PreFilterOut = e.handleLocalPackets
if debugConnectFailures() {
if envknob.BoolDefaultTrue("TS_DEBUG_CONNECT_FAILURES") {
if e.tundev.PreFilterIn != nil {
return nil, errors.New("unexpected PreFilterIn already set")
}
@ -550,10 +549,7 @@ func (e *userspaceEngine) pollResolver() {
}
}
var (
debugTrimWireguardEnv = os.Getenv("TS_DEBUG_TRIM_WIREGUARD")
debugTrimWireguard, _ = strconv.ParseBool(debugTrimWireguardEnv)
)
var debugTrimWireguard = envknob.OptBool("TS_DEBUG_TRIM_WIREGUARD")
// forceFullWireguardConfig reports whether we should give wireguard
// our full network map, even for inactive peers
@ -563,8 +559,8 @@ var (
// and we haven't got enough time testing it.
func forceFullWireguardConfig(numPeers int) bool {
// Did the user explicitly enable trimmming via the environment variable knob?
if debugTrimWireguardEnv != "" {
return !debugTrimWireguard
if b, ok := debugTrimWireguard.Get(); ok {
return !b
}
if opt := controlclient.TrimWGConfig(); opt != "" {
return !opt.EqualBool(true)

View File

@ -6,13 +6,12 @@ package wgengine
import (
"log"
"os"
"runtime/pprof"
"strconv"
"strings"
"time"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns"
"tailscale.com/net/dns/resolver"
@ -32,7 +31,7 @@ import (
//
// If they do not, the watchdog crashes the process.
func NewWatchdog(e Engine) Engine {
if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_DISABLE_WATCHDOG")); v {
if envknob.Bool("TS_DEBUG_DISABLE_WATCHDOG") {
return e
}
return &watchdogEngine{