From 87481282ebee54823703529760cdc5a4e89289d7 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sun, 11 Jul 2021 21:46:50 -0700 Subject: [PATCH] ipn: another controlplane synonym This one doesn't bother me so much, as long term we want a synonym here. Fixes #2384 Fixes #2386 Signed-off-by: David Crawshaw --- cmd/tailscale/cli/cli_test.go | 19 +++++++++++++++++-- cmd/tailscale/cli/up.go | 11 ++++------- ipn/handle.go | 2 +- ipn/prefs.go | 18 +++++++++++++++++- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/cmd/tailscale/cli/cli_test.go b/cmd/tailscale/cli/cli_test.go index 9b3888052..4ab7c5e8e 100644 --- a/cmd/tailscale/cli/cli_test.go +++ b/cmd/tailscale/cli/cli_test.go @@ -735,7 +735,7 @@ func TestUpdatePrefs(t *testing.T) { wantSimpleUp: true, wantJustEditMP: &ipn.MaskedPrefs{WantRunningSet: true}, }, - /* TODO(crawshaw): fix, #2384 { + { name: "control_synonym", flags: []string{}, curPrefs: &ipn.Prefs{ @@ -745,7 +745,22 @@ func TestUpdatePrefs(t *testing.T) { env: upCheckEnv{backendState: "Running"}, wantSimpleUp: true, wantJustEditMP: &ipn.MaskedPrefs{WantRunningSet: true}, - },*/ + }, + { + name: "change_login_server", + flags: []string{"--login-server=https://localhost:1000"}, + curPrefs: &ipn.Prefs{ + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{LoginName: "crawshaw.github"}, + AllowSingleHosts: true, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + }, + env: upCheckEnv{backendState: "Running"}, + wantSimpleUp: true, + wantJustEditMP: &ipn.MaskedPrefs{WantRunningSet: true}, + wantErrSubtr: "can't change --login-server without --force-reauth", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index fae65e2e8..8c39bbd44 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -259,7 +259,8 @@ func updatePrefs(prefs, curPrefs *ipn.Prefs, env upCheckEnv) (simpleUp bool, jus } } - controlURLChanged := curPrefs.ControlURL != prefs.ControlURL + controlURLChanged := curPrefs.ControlURL != prefs.ControlURL && + !(ipn.IsLoginServerSynonym(curPrefs.ControlURL) && ipn.IsLoginServerSynonym(prefs.ControlURL)) if controlURLChanged && env.backendState == ipn.Running.String() && !env.upArgs.forceReauth { return false, nil, fmt.Errorf("can't change --login-server without --force-reauth") } @@ -399,7 +400,7 @@ func runUp(ctx context.Context, args []string) error { startLoginInteractive() case ipn.NeedsMachineAuth: printed = true - fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s/admin/machines\n\n", upArgs.server) + fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s\n\n", prefs.AdminPageURL()) case ipn.Starting, ipn.Running: // Done full authentication process if printed { @@ -608,7 +609,7 @@ func checkForAccidentalSettingReverts(newPrefs, curPrefs *ipn.Prefs, env upCheck if reflect.DeepEqual(valCur, valNew) { continue } - if flagName == "login-server" && isLoginServerSynonym(valCur) && isLoginServerSynonym(valNew) { + if flagName == "login-server" && ipn.IsLoginServerSynonym(valCur) && ipn.IsLoginServerSynonym(valNew) { continue } missing = append(missing, fmtFlagValueArg(flagName, valCur)) @@ -657,10 +658,6 @@ func applyImplicitPrefs(prefs, oldPrefs *ipn.Prefs, curUser string) { } } -func isLoginServerSynonym(val interface{}) bool { - return val == "https://login.tailscale.com" || val == "https://controlplane.tailscale.com" -} - func flagAppliesToOS(flag, goos string) bool { switch flag { case "netfilter-mode", "snat-subnet-routes": diff --git a/ipn/handle.go b/ipn/handle.go index 7f1eb8ea3..e19080ce4 100644 --- a/ipn/handle.go +++ b/ipn/handle.go @@ -156,7 +156,7 @@ func (h *Handle) Expiry() time.Time { } func (h *Handle) AdminPageURL() string { - return h.prefsCache.ControlURLOrDefault() + "/admin/machines" + return h.prefsCache.AdminPageURL() } func (h *Handle) StartLoginInteractive() { diff --git a/ipn/prefs.go b/ipn/prefs.go index 4b8d359f6..02e1ffc42 100644 --- a/ipn/prefs.go +++ b/ipn/prefs.go @@ -25,11 +25,17 @@ import ( //go:generate go run tailscale.com/cmd/cloner -type=Prefs -output=prefs_clone.go -// DefaultControlURL returns the URL base of the control plane +// DefaultControlURL is the URL base of the control plane // ("coordination server") for use when no explicit one is configured. // The default control plane is the hosted version run by Tailscale.com. const DefaultControlURL = "https://controlplane.tailscale.com" +// IsLoginServerSynonym reports whether a URL is a drop-in replacement +// for the primary Tailscale login server. +func IsLoginServerSynonym(val interface{}) bool { + return val == "https://login.tailscale.com" || val == "https://controlplane.tailscale.com" +} + // Prefs are the user modifiable settings of the Tailscale node agent. type Prefs struct { // ControlURL is the URL of the control server to use. @@ -405,6 +411,16 @@ func (p *Prefs) ControlURLOrDefault() string { return DefaultControlURL } +// AdminPageURL returns the admin web site URL for the current ControlURL. +func (p *Prefs) AdminPageURL() string { + url := p.ControlURLOrDefault() + if IsLoginServerSynonym(url) { + // TODO(crawshaw): In future release, make this https://console.tailscale.com + url = "https://login.tailscale.com" + } + return url + "/admin/machines" +} + // PrefsFromBytes deserializes Prefs from a JSON blob. If // enforceDefaults is true, Prefs.RouteAll and Prefs.AllowSingleHosts // are forced on.