Skip to content

Commit

Permalink
cmd/tailscale/cli: make 'tailscale update' support Debian/Ubuntu apt
Browse files Browse the repository at this point in the history
Updates #6995

Change-Id: I3355435db583755e0fc73d76347f6423b8939dfb
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
  • Loading branch information
bradfitz committed Jan 20, 2023
1 parent 6793685 commit 34be0f6
Showing 1 changed file with 88 additions and 6 deletions.
94 changes: 88 additions & 6 deletions cmd/tailscale/cli/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package cli

import (
"bufio"
"bytes"
"context"
"crypto/sha256"
Expand All @@ -20,6 +21,7 @@ import (
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
Expand Down Expand Up @@ -222,13 +224,93 @@ func (up *updater) updateDebLike() error {
if up.currentOrDryRun(ver) {
return nil
}
url := fmt.Sprintf("https://pkgs.tailscale.com/%s/debian/pool/tailscale_%s_%s.deb", up.track, ver, runtime.GOARCH)
// TODO(bradfitz): require root/sudo
// TODO(bradfitz): check https://pkgs.tailscale.com/stable/debian/dists/sid/InRelease, check gpg, get sha256
// And https://pkgs.tailscale.com/stable/debian/dists/sid/main/binary-amd64/Packages.gz and sha256 of it
//

return errors.New("TODO: Debian/Ubuntu deb download of " + url)
track := "unstable"
if stable, ok := versionIsStable(ver); !ok {
return fmt.Errorf("malformed version %q", ver)
} else if stable {
track = "stable"
}

if os.Geteuid() != 0 {
return errors.New("must be root; use sudo")
}

if updated, err := updateDebianAptSourcesList(track); err != nil {
return err
} else if updated {
fmt.Printf("Updated /etc/apt/sources.list.d/tailscale.list to use the %s track\n", track)
}

cmd := exec.Command("apt-get", "update",
// Only update the tailscale repo, not the other ones, treating
// the tailscale.list file as the main "sources.list" file.
"-o", "Dir::Etc::SourceList=sources.list.d/tailscale.list",
// Disable the "sources.list.d" directory:
"-o", "Dir::Etc::SourceParts=-",
// Don't forget about packages in the other repos just because
// we're not updating them:
"-o", "APT::Get::List-Cleanup=0",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}

cmd = exec.Command("apt-get", "install", "--yes", "--allow-downgrades", "tailscale="+ver)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}

return nil
}

// updateDebianAptSourcesList updates the /etc/apt/sources.list.d/tailscale.list
// file to make sure it has the provided track (stable or unstable) in it.
//
// If it already has the right track (including containing both stable and
// unstable), it does nothing.
func updateDebianAptSourcesList(dstTrack string) (rewrote bool, err error) {
const file = "/etc/apt/sources.list.d/tailscale.list"
was, err := os.ReadFile(file)
if err != nil {
return false, err
}
trackURLPrefix := []byte("https://pkgs.tailscale.com/" + dstTrack + "/")
var buf bytes.Buffer
var changes int
bs := bufio.NewScanner(bytes.NewReader(was))
hadCorrect := false
commentLine := regexp.MustCompile(`^\s*\#`)
pkgsURL := regexp.MustCompile(`\bhttps://pkgs.tailscale.com/((un)?stable)/`)
for bs.Scan() {
line := bs.Bytes()
if !commentLine.Match(line) {
line = pkgsURL.ReplaceAllFunc(line, func(m []byte) []byte {
if bytes.Equal(m, trackURLPrefix) {
hadCorrect = true
} else {
changes++
}
return trackURLPrefix
})
}
buf.Write(line)
buf.WriteByte('\n')
}
if hadCorrect || bytes.Equal(bytes.TrimSpace(was), bytes.TrimSpace(buf.Bytes())) {
// Unchanged or close enough.
return false, nil
}
if changes != 1 {
// No changes, or an unexpected number of changes (what?). Bail.
// They probably editted it by hand and we don't know what to do.
return false, fmt.Errorf("unexpected/unsupported %s contents", file)
}
return true, os.WriteFile(file, buf.Bytes(), 0644)
}

func (up *updater) updateMacSys() error {
Expand Down

0 comments on commit 34be0f6

Please sign in to comment.