cmd/tailscaled, ipn/localapi, util/eventbus: don't link in regexp when debug is omitted

Saves 442 KB. Lock it with a new min test.

Updates #12614

Change-Id: Ia7bf6f797b6cbf08ea65419ade2f359d390f8e91
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-09-30 11:54:16 -07:00
committed by Brad Fitzpatrick
parent 840c7668e2
commit 9386a101d8
11 changed files with 100 additions and 78 deletions

View File

@@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build go1.19
//go:build !ts_omit_debug
package main
@@ -16,6 +16,7 @@ import (
"log"
"net/http"
"net/http/httptrace"
"net/http/pprof"
"net/url"
"os"
"time"
@@ -39,7 +40,23 @@ var debugArgs struct {
portmap bool
}
var debugModeFunc = debugMode // so it can be addressable
func init() {
debugModeFunc := debugMode // to be addressable
subCommands["debug"] = &debugModeFunc
hookNewDebugMux.Set(newDebugMux)
}
func newDebugMux() *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/debug/metrics", servePrometheusMetrics)
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
return mux
}
func debugMode(args []string) error {
fs := flag.NewFlagSet("debug", flag.ExitOnError)

View File

@@ -48,7 +48,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/control/controlknobs from tailscale.com/control/controlclient+
tailscale.com/derp from tailscale.com/derp/derphttp+
tailscale.com/derp/derpconst from tailscale.com/derp/derphttp+
tailscale.com/derp/derphttp from tailscale.com/cmd/tailscaled+
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+
tailscale.com/disco from tailscale.com/net/tstun+
tailscale.com/drive from tailscale.com/ipn+
tailscale.com/envknob from tailscale.com/cmd/tailscaled+
@@ -58,7 +58,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/feature/condregister from tailscale.com/cmd/tailscaled
tailscale.com/feature/condregister/portmapper from tailscale.com/feature/condregister
tailscale.com/feature/condregister/useproxy from tailscale.com/feature/condregister
tailscale.com/health from tailscale.com/cmd/tailscaled+
tailscale.com/health from tailscale.com/control/controlclient+
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal+
tailscale.com/hostinfo from tailscale.com/cmd/tailscaled+
tailscale.com/internal/noiseconn from tailscale.com/control/controlclient
@@ -127,14 +127,13 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/tstime from tailscale.com/control/controlclient+
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
tailscale.com/tsweb from tailscale.com/util/eventbus
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal
tailscale.com/types/dnstype from tailscale.com/client/tailscale/apitype+
tailscale.com/types/empty from tailscale.com/ipn+
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled
tailscale.com/types/ipproto from tailscale.com/ipn+
tailscale.com/types/key from tailscale.com/cmd/tailscaled+
tailscale.com/types/key from tailscale.com/control/controlbase+
tailscale.com/types/lazy from tailscale.com/hostinfo+
tailscale.com/types/logger from tailscale.com/appc+
tailscale.com/types/logid from tailscale.com/cmd/tailscaled+
@@ -158,7 +157,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/util/dirwalk from tailscale.com/metrics
tailscale.com/util/dnsname from tailscale.com/appc+
tailscale.com/util/eventbus from tailscale.com/cmd/tailscaled+
tailscale.com/util/eventbus from tailscale.com/control/controlclient+
tailscale.com/util/execqueue from tailscale.com/appc+
tailscale.com/util/goroutines from tailscale.com/ipn/ipnlocal
tailscale.com/util/groupmember from tailscale.com/ipn/ipnauth
@@ -326,7 +325,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
hash from crypto+
hash/crc32 from compress/gzip+
hash/maphash from go4.org/mem
html from net/http/pprof+
html from tailscale.com/ipn/ipnlocal+
internal/abi from hash/maphash+
internal/asan from internal/runtime/maps+
internal/bisect from internal/godebug
@@ -347,7 +346,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
internal/nettrace from net+
internal/oserror from io/fs+
internal/poll from net+
internal/profile from net/http/pprof
internal/profilerecord from runtime+
internal/race from internal/runtime/maps+
internal/reflectlite from context+
@@ -367,7 +365,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
internal/syscall/execenv from os+
internal/syscall/unix from crypto/internal/sysrand+
internal/testlog from os
internal/trace/tracev2 from runtime+
internal/trace/tracev2 from runtime
internal/unsafeheader from internal/reflectlite+
io from bufio+
io/fs from crypto/x509+
@@ -389,7 +387,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
net/http/internal from net/http
net/http/internal/ascii from net/http
net/http/internal/httpcommon from net/http
net/http/pprof from tailscale.com/cmd/tailscaled+
net/netip from crypto/x509+
net/textproto from golang.org/x/net/http/httpguts+
net/url from crypto/x509+
@@ -400,12 +397,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
path from io/fs+
path/filepath from crypto/x509+
reflect from crypto/x509+
regexp from internal/profile+
regexp/syntax from regexp
runtime from crypto/internal/fips140+
runtime/debug from github.com/klauspost/compress/zstd+
runtime/pprof from net/http/pprof+
runtime/trace from net/http/pprof
runtime/pprof from tailscale.com/ipn/ipnlocal+
slices from crypto/tls+
sort from compress/flate+
strconv from compress/flate+

View File

@@ -68,7 +68,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/control/controlknobs from tailscale.com/control/controlclient+
tailscale.com/derp from tailscale.com/derp/derphttp+
tailscale.com/derp/derpconst from tailscale.com/derp/derphttp+
tailscale.com/derp/derphttp from tailscale.com/cmd/tailscaled+
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+
tailscale.com/disco from tailscale.com/net/tstun+
tailscale.com/drive from tailscale.com/ipn+
tailscale.com/envknob from tailscale.com/cmd/tailscaled+
@@ -79,7 +79,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/feature/condregister/oauthkey from tailscale.com/cmd/tailscale/cli
tailscale.com/feature/condregister/portmapper from tailscale.com/feature/condregister+
tailscale.com/feature/condregister/useproxy from tailscale.com/cmd/tailscale/cli+
tailscale.com/health from tailscale.com/cmd/tailscaled+
tailscale.com/health from tailscale.com/control/controlclient+
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal+
tailscale.com/hostinfo from tailscale.com/cmd/tailscaled+
tailscale.com/internal/client/tailscale from tailscale.com/cmd/tailscale/cli
@@ -152,14 +152,13 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/tstime from tailscale.com/control/controlclient+
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
tailscale.com/tsweb from tailscale.com/util/eventbus
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal
tailscale.com/types/dnstype from tailscale.com/client/tailscale/apitype+
tailscale.com/types/empty from tailscale.com/ipn+
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled
tailscale.com/types/ipproto from tailscale.com/ipn+
tailscale.com/types/key from tailscale.com/cmd/tailscaled+
tailscale.com/types/key from tailscale.com/client/local+
tailscale.com/types/lazy from tailscale.com/hostinfo+
tailscale.com/types/logger from tailscale.com/appc+
tailscale.com/types/logid from tailscale.com/cmd/tailscaled+
@@ -184,7 +183,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/util/dirwalk from tailscale.com/metrics
tailscale.com/util/dnsname from tailscale.com/appc+
tailscale.com/util/eventbus from tailscale.com/cmd/tailscaled+
tailscale.com/util/eventbus from tailscale.com/client/local+
tailscale.com/util/execqueue from tailscale.com/appc+
tailscale.com/util/goroutines from tailscale.com/ipn/ipnlocal
tailscale.com/util/groupmember from tailscale.com/ipn/ipnauth
@@ -356,7 +355,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
hash/adler32 from compress/zlib
hash/crc32 from compress/gzip+
hash/maphash from go4.org/mem
html from net/http/pprof+
html from tailscale.com/ipn/ipnlocal+
image from github.com/skip2/go-qrcode+
image/color from github.com/skip2/go-qrcode+
image/png from github.com/skip2/go-qrcode
@@ -380,7 +379,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
internal/nettrace from net+
internal/oserror from io/fs+
internal/poll from net+
internal/profile from net/http/pprof
internal/profilerecord from runtime+
internal/race from internal/runtime/maps+
internal/reflectlite from context+
@@ -400,7 +398,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
internal/syscall/execenv from os+
internal/syscall/unix from crypto/internal/sysrand+
internal/testlog from os
internal/trace/tracev2 from runtime+
internal/trace/tracev2 from runtime
internal/unsafeheader from internal/reflectlite+
io from bufio+
io/fs from crypto/x509+
@@ -424,7 +422,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
net/http/internal from net/http+
net/http/internal/ascii from net/http+
net/http/internal/httpcommon from net/http
net/http/pprof from tailscale.com/cmd/tailscaled+
net/netip from crypto/x509+
net/textproto from golang.org/x/net/http/httpguts+
net/url from crypto/x509+
@@ -435,12 +432,11 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
path from io/fs+
path/filepath from crypto/x509+
reflect from crypto/x509+
regexp from internal/profile+
regexp from tailscale.com/clientupdate
regexp/syntax from regexp
runtime from crypto/internal/fips140+
runtime/debug from github.com/klauspost/compress/zstd+
runtime/pprof from net/http/pprof+
runtime/trace from net/http/pprof
runtime/pprof from tailscale.com/ipn/ipnlocal+
slices from crypto/tls+
sort from compress/flate+
strconv from compress/flate+

View File

@@ -4,9 +4,12 @@
package main
import (
"maps"
"slices"
"strings"
"testing"
"tailscale.com/feature/featuretags"
"tailscale.com/tstest/deptest"
)
@@ -90,19 +93,6 @@ func TestOmitDrive(t *testing.T) {
}.Check(t)
}
func TestOmitTailnetLock(t *testing.T) {
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
Tags: "ts_omit_tailnetlock,ts_include_cli",
OnDep: func(dep string) {
if strings.Contains(dep, "cbor") {
t.Errorf("unexpected dep with ts_omit_tailnetlock: %q", dep)
}
},
}.Check(t)
}
func TestOmitPortmapper(t *testing.T) {
deptest.DepChecker{
GOOS: "linux",
@@ -235,3 +225,42 @@ func TestOmitUseProxy(t *testing.T) {
},
}.Check(t)
}
func minTags() string {
var tags []string
for _, f := range slices.Sorted(maps.Keys(featuretags.Features)) {
if f.IsOmittable() {
tags = append(tags, f.OmitTag())
}
}
return strings.Join(tags, ",")
}
func TestMinTailscaledNoCLI(t *testing.T) {
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
Tags: minTags(),
OnDep: func(dep string) {
if strings.Contains(dep, "regexp") {
t.Errorf("unexpected dep: %q", dep)
}
if strings.Contains(dep, "cbor") {
t.Errorf("unexpected dep: %q", dep)
}
},
}.Check(t)
}
func TestMinTailscaledWithCLI(t *testing.T) {
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
Tags: minTags() + ",ts_include_cli",
OnDep: func(dep string) {
if strings.Contains(dep, "cbor") {
t.Errorf("unexpected dep: %q", dep)
}
},
}.Check(t)
}

View File

@@ -18,7 +18,6 @@ import (
"log"
"net"
"net/http"
"net/http/pprof"
"os"
"os/signal"
"path/filepath"
@@ -145,7 +144,6 @@ var (
var subCommands = map[string]*func([]string) error{
"install-system-daemon": &installSystemDaemon,
"uninstall-system-daemon": &uninstallSystemDaemon,
"debug": &debugModeFunc,
"be-child": &beChildFunc,
}
@@ -194,7 +192,9 @@ func main() {
printVersion := false
flag.IntVar(&args.verbose, "verbose", defaultVerbosity(), "log verbosity level; 0 is default, 1 or higher are increasingly verbose")
flag.BoolVar(&args.cleanUp, "cleanup", false, "clean up system state and exit")
if buildfeatures.HasDebug {
flag.StringVar(&args.debug, "debug", "", "listen address ([ip]:port) of optional debug server")
}
flag.StringVar(&args.tunname, "tun", defaultTunName(), `tunnel interface name; use "userspace-networking" (beta) to not use TUN`)
flag.Var(flagtype.PortValue(&args.port, defaultPort()), "port", "UDP port to listen on for WireGuard and peer-to-peer traffic; 0 means automatically select")
flag.StringVar(&args.statepath, "state", "", "absolute path of state file; use 'kube:<secret-name>' to use Kubernetes secrets or 'arn:aws:ssm:...' to store in AWS SSM; use 'mem:' to not store state and register as an ephemeral node. If empty and --statedir is provided, the default is <statedir>/tailscaled.state. Default: "+paths.DefaultTailscaledStateFile())
@@ -485,8 +485,8 @@ func run() (err error) {
log.Printf("error in synology migration: %v", err)
}
if args.debug != "" {
debugMux = newDebugMux()
if buildfeatures.HasDebug && args.debug != "" {
debugMux = hookNewDebugMux.Get()()
}
if f, ok := hookSetSysDrive.GetOk(); ok {
@@ -550,7 +550,7 @@ func startIPNServer(ctx context.Context, logf logger.Logf, logID logid.PublicID,
}()
srv := ipnserver.New(logf, logID, sys.Bus.Get(), sys.NetMon.Get())
if debugMux != nil {
if buildfeatures.HasDebug && debugMux != nil {
debugMux.HandleFunc("/debug/ipn", srv.ServeHTMLStatus)
}
var lbErr syncs.AtomicValue[error]
@@ -626,7 +626,7 @@ func getLocalBackend(ctx context.Context, logf logger.Logf, logID logid.PublicID
if onlyNetstack && !buildfeatures.HasNetstack {
return nil, errors.New("userspace-networking support is not compiled in to this binary")
}
if debugMux != nil {
if buildfeatures.HasDebug && debugMux != nil {
if ms, ok := sys.MagicSock.GetOK(); ok {
debugMux.HandleFunc("/debug/magicsock", ms.ServeHTTPDebug)
}
@@ -820,16 +820,7 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
return onlyNetstack, nil
}
func newDebugMux() *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/debug/metrics", servePrometheusMetrics)
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
return mux
}
var hookNewDebugMux feature.Hook[func() *http.ServeMux]
func servePrometheusMetrics(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
@@ -838,6 +829,9 @@ func servePrometheusMetrics(w http.ResponseWriter, r *http.Request) {
}
func runDebugServer(logf logger.Logf, mux *http.ServeMux, addr string) {
if !buildfeatures.HasDebug {
return
}
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("debug server: %v", err)

View File

@@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ios && !android && !js
//go:build !ios && !android && !js && !ts_omit_debug
// We don't include it on mobile where we're more memory constrained and
// there's no CLI to get at the results anyway.

View File

@@ -222,7 +222,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
tailscale.com/tstime from tailscale.com/control/controlclient+
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
tailscale.com/tsweb from tailscale.com/util/eventbus
LDW tailscale.com/tsweb from tailscale.com/util/eventbus
tailscale.com/tsweb/varz from tailscale.com/tsweb+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal
tailscale.com/types/bools from tailscale.com/tsnet
@@ -478,7 +478,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
internal/nettrace from net+
internal/oserror from io/fs+
internal/poll from net+
internal/profile from net/http/pprof
LDW internal/profile from net/http/pprof
internal/profilerecord from runtime+
internal/race from internal/poll+
internal/reflectlite from context+
@@ -527,7 +527,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
net/http/internal from net/http+
net/http/internal/ascii from net/http+
net/http/internal/httpcommon from net/http
net/http/pprof from tailscale.com/ipn/localapi+
LDW net/http/pprof from tailscale.com/ipn/localapi+
net/netip from crypto/x509+
net/textproto from github.com/coder/websocket+
net/url from crypto/x509+
@@ -542,7 +542,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
runtime from crypto/internal/fips140+
runtime/debug from github.com/coder/websocket/internal/xsync+
runtime/pprof from net/http/pprof+
runtime/trace from net/http/pprof
LDW runtime/trace from net/http/pprof
slices from crypto/tls+
sort from compress/flate+
strconv from compress/flate+

View File

@@ -14,12 +14,16 @@ import (
"net/netip"
"time"
"tailscale.com/feature/buildfeatures"
"tailscale.com/tsweb"
"tailscale.com/types/key"
"tailscale.com/util/eventbus"
)
func main() {
if !buildfeatures.HasDebugEventBus {
log.Fatalf("debug-demo requires the \"debugeventbus\" feature enabled")
}
b := eventbus.New()
c := b.Client("RouteMonitor")
go testPub[RouteAdded](c, 5*time.Second)

View File

@@ -10,8 +10,6 @@ import (
"slices"
"sync"
"sync/atomic"
"tailscale.com/tsweb"
)
// A Debugger offers access to a bus's privileged introspection and
@@ -137,8 +135,6 @@ func (d *Debugger) SubscribeTypes(client *Client) []reflect.Type {
return client.subscribeTypes()
}
func (d *Debugger) RegisterHTTP(td *tsweb.DebugHandler) { registerHTTPDebugger(d, td) }
// A hook collects hook functions that can be run as a group.
type hook[T any] struct {
sync.Mutex

View File

@@ -29,7 +29,7 @@ type httpDebugger struct {
*Debugger
}
func registerHTTPDebugger(d *Debugger, td *tsweb.DebugHandler) {
func (d *Debugger) RegisterHTTP(td *tsweb.DebugHandler) {
dh := httpDebugger{d}
td.Handle("bus", "Event bus", dh)
td.HandleSilent("bus/monitor", http.HandlerFunc(dh.serveMonitor))

View File

@@ -5,14 +5,6 @@
package eventbus
func registerHTTPDebugger(d *Debugger, tsWebDebugHandler any) {
// The event bus debugging UI uses html/template, which uses
// reflection for method lookups. This forces the compiler to
// retain a lot more code and information to make dynamic method
// dispatch work, which is unacceptable bloat for the iOS build.
// We also disable it on Android while we're at it, as nobody
// is debugging Tailscale internals on Android.
//
// TODO: https://github.com/tailscale/tailscale/issues/15297 to
// bring the debug UI back to iOS somehow.
}
type tswebDebugHandler = any // actually *tsweb.DebugHandler; any to avoid import tsweb with ts_omit_debugeventbus
func (*Debugger) RegisterHTTP(td tswebDebugHandler) {}