Skip to content

Commit

Permalink
Fix auto-update re-exec arguments modified by aliases (#50228) (#51183)
Browse files Browse the repository at this point in the history
* Fix auto-update re-exec arguments modified by aliases

* Make arguments to be required to set

* Restore progress bar show before request

* Improve integration tests to execute with `tsh` and `tctl`

Added a full-cycle integration test to verify client tools
auto-updates within a test cluster by modifying AutoUpdateConfig
and AutoUpdateVersion resources. The test executes the login
command using alias configurations to ensure no recursive
re-execution occurs.

The updater binary used in integration tests has been replaced
with the `Run` logic of tctl and tsh.

* Set generated test password by env variable instead of constant value

* Restore priority of env check over remote check

In case of double re-execution case we should stop second one to prevent loop re-execution
Drop localDir set during compilation
  • Loading branch information
vapopov authored Jan 18, 2025
1 parent 32ad497 commit c2f92b6
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 120 deletions.
14 changes: 7 additions & 7 deletions integration/autoupdate/tools/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func buildAndArchiveApps(ctx context.Context, path string, toolsDir string, vers
case constants.DarwinOS:
output = filepath.Join(versionPath, app+".app", "Contents", "MacOS", app)
}
if err := buildBinary(output, toolsDir, version, baseURL); err != nil {
if err := buildBinary(output, toolsDir, version, baseURL, app); err != nil {
return trace.Wrap(err)
}
}
Expand All @@ -156,16 +156,16 @@ func buildAndArchiveApps(ctx context.Context, path string, toolsDir string, vers
}
}

// buildBinary executes command to build binary with updater logic only for testing.
func buildBinary(output string, toolsDir string, version string, baseURL string) error {
// buildBinary executes command to build client tool binary with updater logic for testing.
func buildBinary(output string, toolsDir string, version string, baseURL string, app string) error {
cmd := exec.Command(
"go", "build", "-o", output,
"-ldflags", strings.Join([]string{
fmt.Sprintf("-X 'main.toolsDir=%s'", toolsDir),
fmt.Sprintf("-X 'main.version=%s'", version),
fmt.Sprintf("-X 'main.baseURL=%s'", baseURL),
fmt.Sprintf("-X 'github.com/gravitational/teleport/integration/autoupdate/tools/updater.version=%s'", version),
fmt.Sprintf("-X 'github.com/gravitational/teleport/lib/autoupdate/tools.version=%s'", version),
fmt.Sprintf("-X 'github.com/gravitational/teleport/lib/autoupdate/tools.baseURL=%s'", baseURL),
}, " "),
"./updater",
fmt.Sprintf("./updater/%s", app),
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand Down
78 changes: 0 additions & 78 deletions integration/autoupdate/tools/updater/main.go

This file was deleted.

104 changes: 104 additions & 0 deletions integration/autoupdate/tools/updater/modules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package updater

import (
"context"
"crypto"
"fmt"
"time"

"github.com/gravitational/trace"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/accesslist"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/modules"
"github.com/gravitational/teleport/lib/tlsca"
)

// TestPassword is password generated during the test to login in test cluster.
const TestPassword = "UPDATER_TEST_PASSWORD"

var (
version = teleport.Version
)

type TestModules struct{}

func (p *TestModules) GenerateAccessRequestPromotions(context.Context, modules.AccessResourcesGetter, types.AccessRequest) (*types.AccessRequestAllowedPromotions, error) {
return &types.AccessRequestAllowedPromotions{}, nil
}

func (p *TestModules) GetSuggestedAccessLists(ctx context.Context, identity *tlsca.Identity, clt modules.AccessListSuggestionClient, accessListGetter modules.AccessListGetter, requestID string) ([]*accesslist.AccessList, error) {
return []*accesslist.AccessList{}, nil
}

// BuildType returns build type (OSS or Enterprise)
func (p *TestModules) BuildType() string {
return "CLI"
}

// IsEnterpriseBuild returns false for [TestModules].
func (p *TestModules) IsEnterpriseBuild() bool {
return false
}

// IsOSSBuild returns false for [TestModules].
func (p *TestModules) IsOSSBuild() bool {
return false
}

// LicenseExpiry returns the expiry date of the enterprise license, if applicable.
func (p *TestModules) LicenseExpiry() time.Time {
return time.Time{}
}

// PrintVersion prints the Teleport version.
func (p *TestModules) PrintVersion() {
fmt.Printf("Teleport v%v git\n", version)
}

// Features returns supported features
func (p *TestModules) Features() modules.Features {
return modules.Features{
AdvancedAccessWorkflows: true,
}
}

// IsBoringBinary checks if the binary was compiled with BoringCrypto.
func (p *TestModules) IsBoringBinary() bool {
return false
}

// AttestHardwareKey attests a hardware key.
func (p *TestModules) AttestHardwareKey(context.Context, interface{}, *keys.AttestationStatement, crypto.PublicKey, time.Duration) (*keys.AttestationData, error) {
return nil, trace.NotFound("no attestation data for the given key")
}

func (p *TestModules) EnableRecoveryCodes() {}

func (p *TestModules) EnablePlugins() {}

func (p *TestModules) SetFeatures(f modules.Features) {}

func (p *TestModules) EnableAccessGraph() {}

func (p *TestModules) EnableAccessMonitoring() {}
37 changes: 37 additions & 0 deletions integration/autoupdate/tools/updater/tctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package main

import (
"context"

"github.com/gravitational/teleport/integration/autoupdate/tools/updater"
"github.com/gravitational/teleport/lib/modules"
stacksignal "github.com/gravitational/teleport/lib/utils/signal"
tctl "github.com/gravitational/teleport/tool/tctl/common"
)

func main() {
ctx, cancel := stacksignal.GetSignalHandler().NotifyContext(context.Background())
defer cancel()

modules.SetModules(&updater.TestModules{})

tctl.Run(ctx, tctl.Commands())
}
44 changes: 44 additions & 0 deletions integration/autoupdate/tools/updater/tsh/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package main

import (
"context"
"os"

"github.com/gravitational/teleport/api/utils/prompt"
"github.com/gravitational/teleport/integration/autoupdate/tools/updater"
"github.com/gravitational/teleport/lib/modules"
"github.com/gravitational/teleport/lib/utils"
stacksignal "github.com/gravitational/teleport/lib/utils/signal"
tsh "github.com/gravitational/teleport/tool/tsh/common"
)

func main() {
ctx, cancel := stacksignal.GetSignalHandler().NotifyContext(context.Background())
defer cancel()

modules.SetModules(&updater.TestModules{})
prompt.SetStdin(prompt.NewFakeReader().AddString(os.Getenv(updater.TestPassword)))

err := tsh.Run(ctx, os.Args[1:])
if err != nil {
utils.FatalError(err)
}
}
15 changes: 8 additions & 7 deletions integration/autoupdate/tools/updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/autoupdate/tools"
)

Expand All @@ -44,8 +45,8 @@ var (
// TestUpdate verifies the basic update logic. We first download a lower version, then request
// an update to a newer version, expecting it to re-execute with the updated version.
func TestUpdate(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
t.Setenv(types.HomeEnvVar, t.TempDir())
ctx := context.Background()

// Fetch compiled test binary with updater logic and install to $TELEPORT_HOME.
updater := tools.NewUpdater(
Expand All @@ -57,7 +58,7 @@ func TestUpdate(t *testing.T) {
require.NoError(t, err)

// Verify that the installed version is equal to requested one.
cmd := exec.CommandContext(ctx, filepath.Join(toolsDir, "tsh"), "version")
cmd := exec.CommandContext(ctx, filepath.Join(toolsDir, "tctl"), "version")
out, err := cmd.Output()
require.NoError(t, err)

Expand Down Expand Up @@ -85,8 +86,8 @@ func TestUpdate(t *testing.T) {
// first update is complete, other processes should acquire the lock one by one and re-execute
// the command with the updated version without any new downloads.
func TestParallelUpdate(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
t.Setenv(types.HomeEnvVar, t.TempDir())
ctx := context.Background()

// Initial fetch the updater binary un-archive and replace.
updater := tools.NewUpdater(
Expand Down Expand Up @@ -158,8 +159,8 @@ func TestParallelUpdate(t *testing.T) {

// TestUpdateInterruptSignal verifies the interrupt signal send to the process must stop downloading.
func TestUpdateInterruptSignal(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
t.Setenv(types.HomeEnvVar, t.TempDir())
ctx := context.Background()

// Initial fetch the updater binary un-archive and replace.
updater := tools.NewUpdater(
Expand Down
Loading

0 comments on commit c2f92b6

Please sign in to comment.