From f7bf7eb08656c142152dbc3eef2ba67bf6dda20c Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Thu, 5 Dec 2024 15:00:09 -0500 Subject: [PATCH] [teleport-update] update --now (#49807) * update --now * testdata --- .../updates_enabled_now.golden | 13 +++++++++ lib/autoupdate/agent/updater.go | 20 +++++++++----- lib/autoupdate/agent/updater_test.go | 27 ++++++++++++++++++- tool/teleport-update/main.go | 6 ++++- 4 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 lib/autoupdate/agent/testdata/TestUpdater_Update/updates_enabled_now.golden diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Update/updates_enabled_now.golden b/lib/autoupdate/agent/testdata/TestUpdater_Update/updates_enabled_now.golden new file mode 100644 index 00000000000..66e2695c2fd --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestUpdater_Update/updates_enabled_now.golden @@ -0,0 +1,13 @@ +version: v1 +kind: update_config +spec: + proxy: localhost + group: group + url_template: https://example.com + enabled: true + pinned: false +status: + active: + version: 16.3.0 + backup: + version: old-version diff --git a/lib/autoupdate/agent/updater.go b/lib/autoupdate/agent/updater.go index f9053da8225..b77d33dac7b 100644 --- a/lib/autoupdate/agent/updater.go +++ b/lib/autoupdate/agent/updater.go @@ -501,7 +501,7 @@ func (u *Updater) Unpin(ctx context.Context) error { // Otherwise, the auto-updates configuration is not changed. // Unlike Enable, Update will not validate or repair the current version. // This function is idempotent. -func (u *Updater) Update(ctx context.Context) error { +func (u *Updater) Update(ctx context.Context, now bool) error { // Read configuration from update.yaml and override any new values passed as flags. cfg, err := readConfig(u.ConfigPath) if err != nil { @@ -536,7 +536,7 @@ func (u *Updater) Update(ctx context.Context) error { // If a version fails and is marked skip, we ignore any edition changes as well. // If a cluster is broadcasting a version that failed to start, changing ent/fips is unlikely to fix the issue. - if !resp.InWindow { + if !resp.InWindow && !now { switch { case target.Version == "": u.Log.WarnContext(ctx, "Cannot determine target agent version. Waiting for both version and update window.") @@ -552,18 +552,26 @@ func (u *Updater) Update(ctx context.Context) error { switch { case target.Version == "": - u.Log.ErrorContext(ctx, "Update window is active, but target version is not available.", activeKey, active) + if resp.InWindow { + u.Log.ErrorContext(ctx, "Update window is active, but target version is not available.", activeKey, active) + } return trace.Errorf("target version missing") case target == active: - u.Log.InfoContext(ctx, "Teleport is up-to-date. Update window is active, but no action is needed.", activeKey, active) + if resp.InWindow { + u.Log.InfoContext(ctx, "Teleport is up-to-date. Update window is active, but no action is needed.", activeKey, active) + } else { + u.Log.InfoContext(ctx, "Teleport is up-to-date. No action is needed.", activeKey, active) + } return nil case target.Version == skip.Version: - u.Log.InfoContext(ctx, "Update available, but the new version is marked as broken. Skipping update during the update window.", targetKey, target, activeKey, active) + u.Log.InfoContext(ctx, "Update available, but the new version is marked as broken. Skipping update.", targetKey, target, activeKey, active) return nil default: u.Log.InfoContext(ctx, "Update available. Initiating update.", targetKey, target, activeKey, active) } - time.Sleep(resp.Jitter) + if !now { + time.Sleep(resp.Jitter) + } updateErr := u.update(ctx, cfg, target) writeErr := writeConfig(u.ConfigPath, cfg) diff --git a/lib/autoupdate/agent/updater_test.go b/lib/autoupdate/agent/updater_test.go index db6ffdd930c..c52117ea449 100644 --- a/lib/autoupdate/agent/updater_test.go +++ b/lib/autoupdate/agent/updater_test.go @@ -223,6 +223,7 @@ func TestUpdater_Update(t *testing.T) { cfg *UpdateConfig // nil -> file not present flags InstallFlags inWindow bool + now bool installErr error setupErr error reloadErr error @@ -261,6 +262,30 @@ func TestUpdater_Update(t *testing.T) { reloadCalls: 1, setupCalls: 1, }, + { + name: "updates enabled now", + cfg: &UpdateConfig{ + Version: updateConfigVersion, + Kind: updateConfigKind, + Spec: UpdateSpec{ + Group: "group", + URLTemplate: "https://example.com", + Enabled: true, + }, + Status: UpdateStatus{ + Active: NewRevision("old-version", 0), + }, + }, + now: true, + + removedRevisions: []Revision{NewRevision("unknown-version", 0)}, + installedRevision: NewRevision("16.3.0", 0), + installedTemplate: "https://example.com", + linkedRevision: NewRevision("16.3.0", 0), + requestGroup: "group", + reloadCalls: 1, + setupCalls: 1, + }, { name: "updates disabled during window", cfg: &UpdateConfig{ @@ -627,7 +652,7 @@ func TestUpdater_Update(t *testing.T) { } ctx := context.Background() - err = updater.Update(ctx) + err = updater.Update(ctx, tt.now) if tt.errMatch != "" { require.Error(t, err) assert.Contains(t, err.Error(), tt.errMatch) diff --git a/tool/teleport-update/main.go b/tool/teleport-update/main.go index ecd4dc72682..aa01952a1db 100644 --- a/tool/teleport-update/main.go +++ b/tool/teleport-update/main.go @@ -80,6 +80,8 @@ type cliConfig struct { InstallSuffix string // SelfSetup mode for using the current version of the teleport-update to setup the update service. SelfSetup bool + // UpdateNow forces an immediate update. + UpdateNow bool } func Run(args []string) int { @@ -136,6 +138,8 @@ func Run(args []string) int { unpinCmd := app.Command("unpin", "Unpin the current version, allowing it to be updated.") updateCmd := app.Command("update", "Update the agent to the latest version, if a new version is available.") + updateCmd.Flag("now", "Force immediate update even if update window is not active."). + Short('n').BoolVar(&ccfg.UpdateNow) updateCmd.Flag("self-setup", "Use the current teleport-update binary to create systemd service config for auto-updates."). Short('s').Hidden().BoolVar(&ccfg.SelfSetup) @@ -345,7 +349,7 @@ func cmdUpdate(ctx context.Context, ccfg *cliConfig) error { } }() - if err := updater.Update(ctx); err != nil { + if err := updater.Update(ctx, ccfg.UpdateNow); err != nil { return trace.Wrap(err) } return nil