cmd/tailscale, ipn/ipnlocal: add ts_omit_webclient

Fixes #17063
Updates #12614

Change-Id: I0a189f6a4d1c4558351e3195839867725774fa96
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-09-08 12:09:29 -07:00
committed by Brad Fitzpatrick
parent ffc82ad820
commit 3e4b0c1516
8 changed files with 63 additions and 23 deletions

View File

@@ -209,6 +209,7 @@ func noDupFlagify(c *ffcli.Command) {
var fileCmd func() *ffcli.Command
var sysPolicyCmd func() *ffcli.Command
var maybeWebCmd func() *ffcli.Command
func newRootCmd() *ffcli.Command {
rootfs := newFlagSet("tailscale")
@@ -251,7 +252,7 @@ change in the future.
funnelCmd(),
serveCmd(),
versionCmd,
webCmd,
nilOrCall(maybeWebCmd),
nilOrCall(fileCmd),
bugReportCmd,
certCmd,

View File

@@ -15,13 +15,13 @@ import (
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/client/web"
"tailscale.com/clientupdate"
"tailscale.com/cmd/tailscale/cli/ffcomplete"
"tailscale.com/ipn"
"tailscale.com/net/netutil"
"tailscale.com/net/tsaddr"
"tailscale.com/safesocket"
"tailscale.com/tsconst"
"tailscale.com/types/opt"
"tailscale.com/types/ptr"
"tailscale.com/types/views"
@@ -264,7 +264,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
}
if setArgs.runWebClient && len(st.TailscaleIPs) > 0 {
printf("\nWeb interface now running at %s:%d\n", st.TailscaleIPs[0], web.ListenPort)
printf("\nWeb interface now running at %s:%d\n", st.TailscaleIPs[0], tsconst.WebListenPort)
}
return nil

View File

@@ -1,6 +1,8 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ts_omit_webclient
package cli
import (
@@ -22,14 +24,20 @@ import (
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/client/web"
"tailscale.com/ipn"
"tailscale.com/tsconst"
)
var webCmd = &ffcli.Command{
Name: "web",
ShortUsage: "tailscale web [flags]",
ShortHelp: "Run a web server for controlling Tailscale",
func init() {
maybeWebCmd = webCmd
}
LongHelp: strings.TrimSpace(`
func webCmd() *ffcli.Command {
return &ffcli.Command{
Name: "web",
ShortUsage: "tailscale web [flags]",
ShortHelp: "Run a web server for controlling Tailscale",
LongHelp: strings.TrimSpace(`
"tailscale web" runs a webserver for controlling the Tailscale daemon.
It's primarily intended for use on Synology, QNAP, and other
@@ -37,16 +45,17 @@ NAS devices where a web interface is the natural place to control
Tailscale, as opposed to a CLI or a native app.
`),
FlagSet: (func() *flag.FlagSet {
webf := newFlagSet("web")
webf.StringVar(&webArgs.listen, "listen", "localhost:8088", "listen address; use port 0 for automatic")
webf.BoolVar(&webArgs.cgi, "cgi", false, "run as CGI script")
webf.StringVar(&webArgs.prefix, "prefix", "", "URL prefix added to requests (for cgi or reverse proxies)")
webf.BoolVar(&webArgs.readonly, "readonly", false, "run web UI in read-only mode")
webf.StringVar(&webArgs.origin, "origin", "", "origin at which the web UI is served (if behind a reverse proxy or used with cgi)")
return webf
})(),
Exec: runWeb,
FlagSet: (func() *flag.FlagSet {
webf := newFlagSet("web")
webf.StringVar(&webArgs.listen, "listen", "localhost:8088", "listen address; use port 0 for automatic")
webf.BoolVar(&webArgs.cgi, "cgi", false, "run as CGI script")
webf.StringVar(&webArgs.prefix, "prefix", "", "URL prefix added to requests (for cgi or reverse proxies)")
webf.BoolVar(&webArgs.readonly, "readonly", false, "run web UI in read-only mode")
webf.StringVar(&webArgs.origin, "origin", "", "origin at which the web UI is served (if behind a reverse proxy or used with cgi)")
return webf
})(),
Exec: runWeb,
}
}
var webArgs struct {
@@ -101,7 +110,7 @@ func runWeb(ctx context.Context, args []string) error {
var startedManagementClient bool // we started the management client
if !existingWebClient && !webArgs.readonly {
// Also start full client in tailscaled.
log.Printf("starting tailscaled web client at http://%s\n", netip.AddrPortFrom(selfIP, web.ListenPort))
log.Printf("starting tailscaled web client at http://%s\n", netip.AddrPortFrom(selfIP, tsconst.WebListenPort))
if err := setRunWebClient(ctx, true); err != nil {
return fmt.Errorf("starting web client in tailscaled: %w", err)
}

View File

@@ -4,6 +4,7 @@
package main
import (
"strings"
"testing"
"tailscale.com/tstest/deptest"
@@ -41,3 +42,22 @@ func TestOmitSyspolicy(t *testing.T) {
},
}.Check(t)
}
// Test that we can build a binary without reflect.MethodByName.
// See https://github.com/tailscale/tailscale/issues/17063
func TestOmitReflectThings(t *testing.T) {
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
Tags: "ts_include_cli,ts_omit_systray,ts_omit_debugeventbus,ts_omit_webclient",
BadDeps: map[string]string{
"text/template": "unexpected text/template usage",
"html/template": "unexpected text/template usage",
},
OnDep: func(dep string) {
if strings.Contains(dep, "systray") {
t.Errorf("unexpected systray dep %q", dep)
}
},
}.Check(t)
}