diff --git a/integrations/terraform/go.mod b/integrations/terraform/go.mod index bc6b5fb8f4df1..0f248045cc81b 100644 --- a/integrations/terraform/go.mod +++ b/integrations/terraform/go.mod @@ -180,6 +180,7 @@ require ( github.com/google/go-tpm-tools v0.4.4 // indirect github.com/google/go-tspi v0.3.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/renameio/v2 v2.0.0 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect diff --git a/integrations/terraform/go.sum b/integrations/terraform/go.sum index 03c8fc34ff45b..2e396be5c6465 100644 --- a/integrations/terraform/go.sum +++ b/integrations/terraform/go.sum @@ -1259,7 +1259,6 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= diff --git a/tool/common/update/integration/main.go b/tool/common/update/integration/main.go index 0f051cb0fa246..ac67fca48f657 100644 --- a/tool/common/update/integration/main.go +++ b/tool/common/update/integration/main.go @@ -40,7 +40,7 @@ func main() { // is required if the user passed in the TELEPORT_TOOLS_VERSION // explicitly. err := update.Download(toolsVersion) - if errors.Is(err, update.ErrCancelled) { + if errors.Is(err, update.ErrCanceled) { os.Exit(0) return } diff --git a/tool/common/update/progress.go b/tool/common/update/progress.go index 150d589f6e86c..a1ce6f66a5d4d 100644 --- a/tool/common/update/progress.go +++ b/tool/common/update/progress.go @@ -27,7 +27,7 @@ import ( ) var ( - ErrCancelled = fmt.Errorf("cancelled") + ErrCanceled = fmt.Errorf("canceled") ) // cancelableTeeReader is a copy of TeeReader with ability to react on signal notifier @@ -48,7 +48,7 @@ type teeReader struct { func (t *teeReader) Read(p []byte) (n int, err error) { select { case <-t.sigs: - return 0, ErrCancelled + return 0, ErrCanceled default: n, err = t.r.Read(p) if n > 0 { diff --git a/tool/common/update/update.go b/tool/common/update/update.go index cda87328c7556..3a4f97ce6800e 100644 --- a/tool/common/update/update.go +++ b/tool/common/update/update.go @@ -77,6 +77,9 @@ func CheckLocal() (string, bool) { // The user has turned off any form of automatic updates. case requestedVersion == "off": return "", false + // Requested version already the same as client version. + case teleport.Version == requestedVersion: + return requestedVersion, false // The user has requested a specific version of client tools. case requestedVersion != "" && requestedVersion != toolsVersion: return requestedVersion, true @@ -88,13 +91,6 @@ func CheckLocal() (string, bool) { // CheckRemote will check against Proxy Service if client tools need to be // updated. func CheckRemote(ctx context.Context, proxyAddr string) (string, bool, error) { - // If a version of client tools has already been downloaded to - // $TELEPORT_HOME/bin, return that. - toolsVersion, err := version() - if err != nil { - return "", false, nil - } - certPool, err := x509.SystemCertPool() if err != nil { return "", false, trace.Wrap(err) @@ -109,20 +105,32 @@ func CheckRemote(ctx context.Context, proxyAddr string) (string, bool, error) { return "", false, trace.Wrap(err) } + // If a version of client tools has already been downloaded to + // $TELEPORT_HOME/bin, return that. + toolsVersion, err := version() + if err != nil { + return "", false, nil + } + requestedVersion := os.Getenv(teleportToolsVersion) switch { // The user has turned off any form of automatic updates. case requestedVersion == "off": return "", false, nil + // Requested version already the same as client version. + case teleport.Version == requestedVersion: + return requestedVersion, false, nil case requestedVersion != "" && requestedVersion != toolsVersion: return requestedVersion, true, nil case !resp.ToolsAutoupdate || resp.ToolsVersion == "": return "", false, nil + case teleport.Version == resp.ToolsVersion: + return resp.ToolsVersion, false, nil case resp.ToolsVersion != toolsVersion: return resp.ToolsVersion, true, nil } - return "", false, nil + return toolsVersion, false, nil } // Download downloads requested version package, unarchive and replace existing one. @@ -319,6 +327,8 @@ func Exec() (int, error) { cmd := exec.Command(path, os.Args[1:]...) cmd.Env = os.Environ() + // To prevent re-execution loop we have to disable update logic for re-execution. + cmd.Env = append(cmd.Env, teleportToolsVersion+"=off") cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/tool/common/update/update_linux.go b/tool/common/update/update_linux.go index f3acc5975b96a..8e02b9bc407e5 100644 --- a/tool/common/update/update_linux.go +++ b/tool/common/update/update_linux.go @@ -23,6 +23,7 @@ package update import ( "archive/tar" "compress/gzip" + "errors" "io" "os" "path/filepath" @@ -53,7 +54,7 @@ func replace(path string, _ string) error { tarReader := tar.NewReader(gzipReader) for { header, err := tarReader.Next() - if err == io.EOF { + if errors.Is(err, io.EOF) { break } // Skip over any files in the archive that are not {tsh, tctl}. diff --git a/tool/common/update/update_test.go b/tool/common/update/update_test.go index 3a617ffee78b4..ac7cda653a3f5 100644 --- a/tool/common/update/update_test.go +++ b/tool/common/update/update_test.go @@ -41,7 +41,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/stretchr/testify/require" ) @@ -122,6 +121,7 @@ func TestUpdateInterruptSignal(t *testing.T) { ) err = cmd.Start() require.NoError(t, err, "failed to start updater") + pid := cmd.Process.Pid errChan := make(chan error) go func() { @@ -142,7 +142,7 @@ func TestUpdateInterruptSignal(t *testing.T) { t.Errorf("failed to wait till the download is started") case <-lock: time.Sleep(100 * time.Millisecond) - require.NoError(t, sendInterrupt(cmd)) + require.NoError(t, sendInterrupt(pid)) lock <- struct{}{} } @@ -257,6 +257,9 @@ func generateZipFile(filePath, destPath string) error { defer zipWriter.Close() return filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if info.IsDir() { return nil } @@ -292,6 +295,9 @@ func generateTarGzFile(filePath, destPath string) error { defer tarWriter.Close() return filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if info.IsDir() { return nil } diff --git a/tool/common/update/update_unix.go b/tool/common/update/update_unix.go index 2c30884f2af30..dc51d964baddd 100644 --- a/tool/common/update/update_unix.go +++ b/tool/common/update/update_unix.go @@ -4,14 +4,14 @@ package update import ( "context" - "golang.org/x/sys/unix" + "errors" "log/slog" "os" - "os/exec" "path/filepath" "syscall" "github.com/gravitational/trace" + "golang.org/x/sys/unix" ) func lock(dir string) (func(), error) { @@ -56,8 +56,12 @@ func lock(dir string) (func(), error) { } // sendInterrupt sends a SIGINT to the process. -func sendInterrupt(cmd *exec.Cmd) error { - return trace.Wrap(cmd.Process.Signal(syscall.SIGINT)) +func sendInterrupt(pid int) error { + err := syscall.Kill(pid, syscall.SIGINT) + if errors.Is(err, syscall.ESRCH) { + return trace.BadParameter("can't find the process: %v", pid) + } + return trace.Wrap(err) } // freeDiskWithReserve returns the available disk space. diff --git a/tool/common/update/update_windows.go b/tool/common/update/update_windows.go index 07af13492b18c..66c2a68093c8b 100644 --- a/tool/common/update/update_windows.go +++ b/tool/common/update/update_windows.go @@ -26,7 +26,6 @@ import ( "io" "log/slog" "os" - "os/exec" "path/filepath" "syscall" "time" @@ -146,8 +145,8 @@ func lock(dir string) (func(), error) { } // sendInterrupt sends a Ctrl-Break event to the process. -func sendInterrupt(cmd *exec.Cmd) error { - r, _, err := ctrlEvent.Call(uintptr(syscall.CTRL_BREAK_EVENT), uintptr(cmd.Process.Pid)) +func sendInterrupt(pid int) error { + r, _, err := ctrlEvent.Call(uintptr(syscall.CTRL_BREAK_EVENT), uintptr(pid)) if r == 0 { return trace.Wrap(err) }