clientupdate: add explicit Track to Arguments (#10548)

Instead of overloading the Version field, add an explicit Track field.

This fixes a bug where passing a track name in `args.Version` would keep
the track name in `updater.Version` and pass it down the code path to
commands like `apt-get install`. Now, `updater.Version` should always be
a version (or empty string).

Updates #cleanup

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
pull/10552/head
Andrew Lytvynov 6 months ago committed by GitHub
parent 1b1b6bb634
commit d8493d4bd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -63,16 +63,19 @@ func versionToTrack(v string) (string, error) {
// Arguments contains arguments needed to run an update. // Arguments contains arguments needed to run an update.
type Arguments struct { type Arguments struct {
// Version can be a specific version number or one of the predefined track // Version is the specific version to install.
// constants: // Mutually exclusive with Track.
Version string
// Track is the release track to use:
// //
// - CurrentTrack will use the latest version from the same track as the // - CurrentTrack will use the latest version from the same track as the
// running binary // running binary
// - StableTrack and UnstableTrack will use the latest versions of the // - StableTrack and UnstableTrack will use the latest versions of the
// corresponding tracks // corresponding tracks
// //
// Leaving this empty is the same as using CurrentTrack. // Leaving this empty will use Version or fall back to CurrentTrack if both
Version string // Track and Version are empty.
Track string
// Logf is a logger for update progress messages. // Logf is a logger for update progress messages.
Logf logger.Logf Logf logger.Logf
// Stdout and Stderr should be used for output instead of os.Stdout and // Stdout and Stderr should be used for output instead of os.Stdout and
@ -99,12 +102,20 @@ func (args Arguments) validate() error {
if args.Logf == nil { if args.Logf == nil {
return errors.New("missing Logf callback in Arguments") return errors.New("missing Logf callback in Arguments")
} }
if args.Version != "" && args.Track != "" {
return fmt.Errorf("only one of Version(%q) or Track(%q) can be set", args.Version, args.Track)
}
switch args.Track {
case StableTrack, UnstableTrack, CurrentTrack:
// All valid values.
default:
return fmt.Errorf("unsupported track %q", args.Track)
}
return nil return nil
} }
type Updater struct { type Updater struct {
Arguments Arguments
track string
// Update is a platform-specific method that updates the installation. May be // Update is a platform-specific method that updates the installation. May be
// nil (not all platforms support updates from within Tailscale). // nil (not all platforms support updates from within Tailscale).
Update func() error Update func() error
@ -128,20 +139,18 @@ func NewUpdater(args Arguments) (*Updater, error) {
if args.ForAutoUpdate && !canAutoUpdate { if args.ForAutoUpdate && !canAutoUpdate {
return nil, errors.ErrUnsupported return nil, errors.ErrUnsupported
} }
switch up.Version { if up.Track == CurrentTrack {
case StableTrack, UnstableTrack: switch {
up.track = up.Version case up.Version != "":
case CurrentTrack: var err error
if version.IsUnstableBuild() { up.Track, err = versionToTrack(args.Version)
up.track = UnstableTrack if err != nil {
} else { return nil, err
up.track = StableTrack }
} case version.IsUnstableBuild():
default: up.Track = UnstableTrack
var err error default:
up.track, err = versionToTrack(args.Version) up.Track = StableTrack
if err != nil {
return nil, err
} }
} }
if up.Arguments.PkgsAddr == "" { if up.Arguments.PkgsAddr == "" {
@ -248,10 +257,10 @@ func Update(args Arguments) error {
func (up *Updater) confirm(ver string) bool { func (up *Updater) confirm(ver string) bool {
switch cmpver.Compare(version.Short(), ver) { switch cmpver.Compare(version.Short(), ver) {
case 0: case 0:
up.Logf("already running %v version %v; no update needed", up.track, ver) up.Logf("already running %v version %v; no update needed", up.Track, ver)
return false return false
case 1: case 1:
up.Logf("installed %v version %v is newer than the latest available version %v; no update needed", up.track, version.Short(), ver) up.Logf("installed %v version %v is newer than the latest available version %v; no update needed", up.Track, version.Short(), ver)
return false return false
} }
if up.Confirm != nil { if up.Confirm != nil {
@ -277,7 +286,7 @@ func (up *Updater) updateSynology() error {
if err != nil { if err != nil {
return err return err
} }
latest, err := latestPackages(up.track) latest, err := latestPackages(up.Track)
if err != nil { if err != nil {
return err return err
} }
@ -296,7 +305,7 @@ func (up *Updater) updateSynology() error {
if err != nil { if err != nil {
return err return err
} }
pkgsPath := fmt.Sprintf("%s/%s", up.track, spkName) pkgsPath := fmt.Sprintf("%s/%s", up.Track, spkName)
spkPath := filepath.Join(spkDir, path.Base(pkgsPath)) spkPath := filepath.Join(spkDir, path.Base(pkgsPath))
if err := up.downloadURLToFile(pkgsPath, spkPath); err != nil { if err := up.downloadURLToFile(pkgsPath, spkPath); err != nil {
return err return err
@ -395,7 +404,7 @@ func (up *Updater) updateDebLike() error {
// instead. // instead.
return up.updateLinuxBinary() return up.updateLinuxBinary()
} }
ver, err := requestedTailscaleVersion(up.Version, up.track) ver, err := requestedTailscaleVersion(up.Version, up.Track)
if err != nil { if err != nil {
return err return err
} }
@ -403,10 +412,10 @@ func (up *Updater) updateDebLike() error {
return nil return nil
} }
if updated, err := updateDebianAptSourcesList(up.track); err != nil { if updated, err := updateDebianAptSourcesList(up.Track); err != nil {
return err return err
} else if updated { } else if updated {
up.Logf("Updated %s to use the %s track", aptSourcesFile, up.track) up.Logf("Updated %s to use the %s track", aptSourcesFile, up.Track)
} }
cmd := exec.Command("apt-get", "update", cmd := exec.Command("apt-get", "update",
@ -534,7 +543,7 @@ func (up *Updater) updateFedoraLike(packageManager string) func() error {
} }
}() }()
ver, err := requestedTailscaleVersion(up.Version, up.track) ver, err := requestedTailscaleVersion(up.Version, up.Track)
if err != nil { if err != nil {
return err return err
} }
@ -542,10 +551,10 @@ func (up *Updater) updateFedoraLike(packageManager string) func() error {
return nil return nil
} }
if updated, err := updateYUMRepoTrack(yumRepoConfigFile, up.track); err != nil { if updated, err := updateYUMRepoTrack(yumRepoConfigFile, up.Track); err != nil {
return err return err
} else if updated { } else if updated {
up.Logf("Updated %s to use the %s track", yumRepoConfigFile, up.track) up.Logf("Updated %s to use the %s track", yumRepoConfigFile, up.Track)
} }
cmd := exec.Command(packageManager, "install", "--assumeyes", fmt.Sprintf("tailscale-%s-1", ver)) cmd := exec.Command(packageManager, "install", "--assumeyes", fmt.Sprintf("tailscale-%s-1", ver))
@ -691,8 +700,8 @@ const (
) )
var ( var (
verifyAuthenticode func(string) error // or nil on non-Windows verifyAuthenticode func(string) error // set non-nil only on Windows
markTempFileFunc func(string) error // or nil on non-Windows markTempFileFunc func(string) error // set non-nil only on Windows
) )
func (up *Updater) updateWindows() error { func (up *Updater) updateWindows() error {
@ -725,7 +734,7 @@ you can run the command prompt as Administrator one of these ways:
* press Windows+x, then press a * press Windows+x, then press a
* press Windows+r, type in "cmd", then press Ctrl+Shift+Enter`) * press Windows+r, type in "cmd", then press Ctrl+Shift+Enter`)
} }
ver, err := requestedTailscaleVersion(up.Version, up.track) ver, err := requestedTailscaleVersion(up.Version, up.Track)
if err != nil { if err != nil {
return err return err
} }
@ -748,7 +757,7 @@ you can run the command prompt as Administrator one of these ways:
return err return err
} }
up.cleanupOldDownloads(filepath.Join(msiDir, "*.msi")) up.cleanupOldDownloads(filepath.Join(msiDir, "*.msi"))
pkgsPath := fmt.Sprintf("%s/tailscale-setup-%s-%s.msi", up.track, ver, arch) pkgsPath := fmt.Sprintf("%s/tailscale-setup-%s-%s.msi", up.Track, ver, arch)
msiTarget := filepath.Join(msiDir, path.Base(pkgsPath)) msiTarget := filepath.Join(msiDir, path.Base(pkgsPath))
if err := up.downloadURLToFile(pkgsPath, msiTarget); err != nil { if err := up.downloadURLToFile(pkgsPath, msiTarget); err != nil {
return err return err
@ -958,7 +967,7 @@ func (up *Updater) updateLinuxBinary() error {
if err := requireRoot(); err != nil { if err := requireRoot(); err != nil {
return err return err
} }
ver, err := requestedTailscaleVersion(up.Version, up.track) ver, err := requestedTailscaleVersion(up.Version, up.Track)
if err != nil { if err != nil {
return err return err
} }
@ -999,7 +1008,7 @@ func (up *Updater) downloadLinuxTarball(ver string) (string, error) {
if err := os.MkdirAll(dlDir, 0700); err != nil { if err := os.MkdirAll(dlDir, 0700); err != nil {
return "", err return "", err
} }
pkgsPath := fmt.Sprintf("%s/tailscale_%s_%s.tgz", up.track, ver, runtime.GOARCH) pkgsPath := fmt.Sprintf("%s/tailscale_%s_%s.tgz", up.Track, ver, runtime.GOARCH)
dlPath := filepath.Join(dlDir, path.Base(pkgsPath)) dlPath := filepath.Join(dlDir, path.Base(pkgsPath))
if err := up.downloadURLToFile(pkgsPath, dlPath); err != nil { if err := up.downloadURLToFile(pkgsPath, dlPath); err != nil {
return "", err return "", err

@ -59,12 +59,9 @@ func runUpdate(ctx context.Context, args []string) error {
if updateArgs.version != "" && updateArgs.track != "" { if updateArgs.version != "" && updateArgs.track != "" {
return errors.New("cannot specify both --version and --track") return errors.New("cannot specify both --version and --track")
} }
ver := updateArgs.version
if updateArgs.track != "" {
ver = updateArgs.track
}
err := clientupdate.Update(clientupdate.Arguments{ err := clientupdate.Update(clientupdate.Arguments{
Version: ver, Version: updateArgs.version,
Track: updateArgs.track,
Logf: func(f string, a ...any) { printf(f+"\n", a...) }, Logf: func(f string, a ...any) { printf(f+"\n", a...) },
Stdout: Stdout, Stdout: Stdout,
Stderr: Stderr, Stderr: Stderr,

Loading…
Cancel
Save