cmd/tailscale/cli,version/distro: update support for Alpine (#8701)
Similar to Arch support, use the latest version info from the official `apk` repo and don't offer explicit track or version switching. Add detection for Alpine Linux in version/distro along the way. Updates #6995 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
@@ -45,9 +45,10 @@ var updateCmd = &ffcli.Command{
|
||||
fs.BoolVar(&updateArgs.yes, "yes", false, "update without interactive prompts")
|
||||
fs.BoolVar(&updateArgs.dryRun, "dry-run", false, "print what update would do without doing it, or prompts")
|
||||
fs.BoolVar(&updateArgs.appStore, "app-store", false, "HIDDEN: check the App Store for updates, even if this is not an App Store install (for testing only)")
|
||||
// These flags are not supported on Arch-based installs. Arch only
|
||||
// offers one variant of tailscale and it's always the latest version.
|
||||
if distro.Get() != distro.Arch {
|
||||
// These flags are not supported on Arch or Alpine-based installs.
|
||||
// Package repos on these distros only offer one variant of tailscale
|
||||
// and it's always the latest version.
|
||||
if distro.Get() != distro.Arch && distro.Get() != distro.Alpine {
|
||||
fs.StringVar(&updateArgs.track, "track", "", `which track to check for updates: "stable" or "unstable" (dev); empty means same as current`)
|
||||
fs.StringVar(&updateArgs.version, "version", "", `explicit version to update/downgrade to`)
|
||||
}
|
||||
@@ -145,6 +146,8 @@ func newUpdater() (*updater, error) {
|
||||
up.update = up.updateDebLike
|
||||
case distro.Arch:
|
||||
up.update = up.updateArchLike
|
||||
case distro.Alpine:
|
||||
up.update = up.updateAlpineLike
|
||||
}
|
||||
// TODO(awly): add support for Alpine
|
||||
switch {
|
||||
@@ -158,6 +161,8 @@ func newUpdater() (*updater, error) {
|
||||
up.update = up.updateFedoraLike("dnf")
|
||||
case haveExecutable("yum"):
|
||||
up.update = up.updateFedoraLike("yum")
|
||||
case haveExecutable("apk"):
|
||||
up.update = up.updateAlpineLike
|
||||
}
|
||||
case "darwin":
|
||||
switch {
|
||||
@@ -462,6 +467,63 @@ func updateYUMRepoTrack(repoFile, dstTrack string) (rewrote bool, err error) {
|
||||
return true, os.WriteFile(repoFile, newContent.Bytes(), 0644)
|
||||
}
|
||||
|
||||
func (up *updater) updateAlpineLike() (err error) {
|
||||
if err := requireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil && !errors.Is(err, errUserAborted) {
|
||||
err = fmt.Errorf(`%w; you can try updating using "apk upgrade tailscale"`, err)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err := exec.Command("apk", "update").CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed refresh apk repository indexes: %w, output: %q", err, out)
|
||||
}
|
||||
out, err = exec.Command("apk", "info", "tailscale").CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed checking apk for latest tailscale version: %w, output: %q", err, out)
|
||||
}
|
||||
ver, err := parseAlpinePackageVersion(out)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`failed to parse latest version from "apk info tailscale": %w`, err)
|
||||
}
|
||||
if up.currentOrDryRun(ver) {
|
||||
return nil
|
||||
}
|
||||
if err := up.confirm(ver); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("apk", "upgrade", "tailscale")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed tailscale update using apk: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseAlpinePackageVersion(out []byte) (string, error) {
|
||||
s := bufio.NewScanner(bytes.NewReader(out))
|
||||
for s.Scan() {
|
||||
// The line should look like this:
|
||||
// tailscale-1.44.2-r0 description:
|
||||
line := strings.TrimSpace(s.Text())
|
||||
if !strings.HasPrefix(line, "tailscale-") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "-", 3)
|
||||
if len(parts) < 3 {
|
||||
return "", fmt.Errorf("malformed info line: %q", line)
|
||||
}
|
||||
return parts[1], nil
|
||||
}
|
||||
return "", errors.New("tailscale version not found in output")
|
||||
}
|
||||
|
||||
func (up *updater) updateMacSys() error {
|
||||
// use sparkle? do we have permissions from this context? does sudo help?
|
||||
// We can at least fail with a command they can run to update from the shell.
|
||||
|
||||
Reference in New Issue
Block a user