Skip to content

Commit

Permalink
cmd/tailscale,ipn: add auto-update flags and prefs
Browse files Browse the repository at this point in the history
The flags are hidden for now. Adding propagation to tailscaled and
persistence only. The prefs field is wrapped in a struct to allow for
future expansion (like update schedule).

Updates #6907

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
  • Loading branch information
awly committed Sep 1, 2023
1 parent ce1e020 commit eff21ba
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 16 deletions.
24 changes: 24 additions & 0 deletions cmd/tailscale/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
NetfilterMode: preftype.NetfilterOn,
CorpDNS: true,
AllowSingleHosts: true,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand All @@ -569,6 +573,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
AllowSingleHosts: true,
RouteAll: true,
NetfilterMode: preftype.NetfilterOn,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand All @@ -584,6 +592,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
netip.MustParsePrefix("::/0"),
},
NetfilterMode: preftype.NetfilterOn,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand Down Expand Up @@ -670,6 +682,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
WantRunning: true,
NetfilterMode: preftype.NetfilterNoDivert,
NoSNAT: true,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand All @@ -683,6 +699,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
WantRunning: true,
NetfilterMode: preftype.NetfilterOff,
NoSNAT: true,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand All @@ -698,6 +718,10 @@ func TestPrefsFromUpArgs(t *testing.T) {
AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
},
AutoUpdate: ipn.AutoUpdatePrefs{
Check: true,
Apply: false,
},
},
},
{
Expand Down
15 changes: 15 additions & 0 deletions cmd/tailscale/cli/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/netip"

"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/clientupdate"
"tailscale.com/ipn"
"tailscale.com/net/netutil"
"tailscale.com/net/tsaddr"
Expand Down Expand Up @@ -46,6 +47,8 @@ type setArgsT struct {
acceptedRisks string
profileName string
forceDaemon bool
updateCheck bool
updateApply bool
}

func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
Expand All @@ -61,6 +64,8 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
setf.StringVar(&setArgs.hostname, "hostname", "", "hostname to use instead of the one provided by the OS")
setf.StringVar(&setArgs.advertiseRoutes, "advertise-routes", "", "routes to advertise to other nodes (comma-separated, e.g. \"10.0.0.0/8,192.168.0.0/24\") or empty string to not advertise routes")
setf.BoolVar(&setArgs.advertiseDefaultRoute, "advertise-exit-node", false, "offer to be an exit node for internet traffic for the tailnet")
setf.BoolVar(&setArgs.updateCheck, "update-check", true, "HIDDEN: notify about available Tailscale updates")
setf.BoolVar(&setArgs.updateApply, "auto-update", false, "HIDDEN: automatically update to the latest available version")
if safesocket.GOOSUsesPeerCreds(goos) {
setf.StringVar(&setArgs.opUser, "operator", "", "Unix username to allow to operate on tailscaled without sudo")
}
Expand Down Expand Up @@ -99,6 +104,10 @@ func runSet(ctx context.Context, args []string) (retErr error) {
Hostname: setArgs.hostname,
OperatorUser: setArgs.opUser,
ForceDaemon: setArgs.forceDaemon,
AutoUpdate: ipn.AutoUpdatePrefs{
Check: setArgs.updateCheck,
Apply: setArgs.updateApply,
},
},
}

Expand Down Expand Up @@ -143,6 +152,12 @@ func runSet(ctx context.Context, args []string) (retErr error) {
return err
}
}
if maskedPrefs.AutoUpdateSet {
_, err := clientupdate.NewUpdater(clientupdate.Arguments{})
if errors.Is(err, errors.ErrUnsupported) {
return errors.New("automatic updates are not supported on this platform")
}
}
checkPrefs := curPrefs.Clone()
checkPrefs.ApplyEdits(maskedPrefs)
if err := localClient.CheckPrefs(ctx, checkPrefs); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions cmd/tailscale/cli/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet {
}
upf := newFlagSet(cmd)

// When adding new flags, prefer to put them under "tailscale set" instead
// of here. Setting preferences via "tailscale up" is deprecated.
upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs")
upf.StringVar(&upArgs.authKeyOrFile, "auth-key", "", `node authorization key; if it begins with "file:", then it's a path to a file containing the authkey`)

Expand Down Expand Up @@ -712,6 +714,8 @@ func init() {
addPrefFlagMapping("operator", "OperatorUser")
addPrefFlagMapping("ssh", "RunSSH")
addPrefFlagMapping("nickname", "ProfileName")
addPrefFlagMapping("update-check", "AutoUpdate")
addPrefFlagMapping("auto-update", "AutoUpdate")
}

func addPrefFlagMapping(flagName string, prefNames ...string) {
Expand Down
1 change: 1 addition & 0 deletions ipn/ipn_clone.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ipn/ipn_view.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ipn/ipnlocal/c2n.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ func (b *LocalBackend) handleC2NUpdate(w http.ResponseWriter, r *http.Request) {
//
// Note that we create the Updater solely to check for errors; we do not
// invoke it here. For this purpose, it is ok to pass it a zero Arguments.
prefs := b.Prefs().AutoUpdate()
_, err := clientupdate.NewUpdater(clientupdate.Arguments{})
res := tailcfg.C2NUpdateResponse{
Enabled: envknob.AllowsRemoteUpdate(),
Enabled: envknob.AllowsRemoteUpdate() || prefs.Apply,
Supported: err == nil && !version.IsMacSysExt(),
}

Expand Down
39 changes: 38 additions & 1 deletion ipn/prefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ type Prefs struct {
// and CLI.
ProfileName string `json:",omitempty"`

// AutoUpdate sets the auto-update preferences for the node agent. See
// AutoUpdatePrefs docs for more details.
AutoUpdate AutoUpdatePrefs

// The Persist field is named 'Config' in the file for backward
// compatibility with earlier versions.
// TODO(apenwarr): We should move this out of here, it's not a pref.
Expand All @@ -204,6 +208,18 @@ type Prefs struct {
Persist *persist.Persist `json:"Config"`
}

// AutoUpdatePrefs are the auto update settings for the node agent.
type AutoUpdatePrefs struct {
// Check specifies whether background checks for updates are enabled. When
// enabled, tailscaled will periodically check for available and notify the
// user about them.
Check bool
// Apply specifies whether background auto-updates are enabled. When
// enabled, tailscaled will apply available updates in the background as
// soon as they are available. Check must also be set when Apply is set.
Apply bool
}

// MaskedPrefs is a Prefs with an associated bitmask of which fields are set.
type MaskedPrefs struct {
Prefs
Expand All @@ -229,6 +245,7 @@ type MaskedPrefs struct {
NetfilterModeSet bool `json:",omitempty"`
OperatorUserSet bool `json:",omitempty"`
ProfileNameSet bool `json:",omitempty"`
AutoUpdateSet bool `json:",omitempty"`
}

// ApplyEdits mutates p, assigning fields from m.Prefs for each MaskedPrefs
Expand Down Expand Up @@ -284,6 +301,12 @@ func (m *MaskedPrefs) Pretty() string {
if v.Type().Elem().Kind() == reflect.String {
return "%s=%q"
}
case reflect.Struct:
return "%s=%+v"
case reflect.Pointer:
if v.Type().Elem().Kind() == reflect.Struct {
return "%s=%+v"
}
}
return "%s=%v"
}
Expand Down Expand Up @@ -360,6 +383,7 @@ func (p *Prefs) pretty(goos string) string {
if p.OperatorUser != "" {
fmt.Fprintf(&sb, "op=%q ", p.OperatorUser)
}
sb.WriteString(p.AutoUpdate.Pretty())
if p.Persist != nil {
sb.WriteString(p.Persist.Pretty())
} else {
Expand Down Expand Up @@ -414,7 +438,16 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
compareIPNets(p.AdvertiseRoutes, p2.AdvertiseRoutes) &&
compareStrings(p.AdvertiseTags, p2.AdvertiseTags) &&
p.Persist.Equals(p2.Persist) &&
p.ProfileName == p2.ProfileName
p.ProfileName == p2.ProfileName &&
p.AutoUpdate.Equals(p2.AutoUpdate)
}

func (au AutoUpdatePrefs) Equals(au2 AutoUpdatePrefs) bool {
return au == au2
}

func (au AutoUpdatePrefs) Pretty() string {
return fmt.Sprintf("AutoUpdatePrefs{check=%v apply=%v} ", au.Check, au.Apply)
}

func compareIPNets(a, b []netip.Prefix) bool {
Expand Down Expand Up @@ -459,6 +492,10 @@ func NewPrefs() *Prefs {
CorpDNS: true,
WantRunning: false,
NetfilterMode: preftype.NetfilterOn,
AutoUpdate: AutoUpdatePrefs{
Check: true,
Apply: false,
},
}
}

Expand Down
Loading

0 comments on commit eff21ba

Please sign in to comment.