-
Notifications
You must be signed in to change notification settings - Fork 204
Fix Elastic Agent non-fleet broken upgrade between 8.3.x releases #701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
da44852
57025b3
ed8393b
5d89a4d
574395a
a73437d
88157ca
56a5001
d797de1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -80,23 +80,25 @@ func Create(key string, opts ...OptionFunc) error { | |||||
| CreatedOn: time.Now().UTC(), | ||||||
| } | ||||||
|
|
||||||
| b, err := json.Marshal(secret) | ||||||
| if err != nil { | ||||||
| return err | ||||||
| } | ||||||
|
|
||||||
| return v.Set(key, b) | ||||||
| return set(v, key, secret) | ||||||
| } | ||||||
|
|
||||||
| // GetAgentSecret read the agent secret from the vault | ||||||
| func GetAgentSecret(opts ...OptionFunc) (secret Secret, err error) { | ||||||
| return Get(agentSecretKey, opts...) | ||||||
| } | ||||||
|
|
||||||
| // SetAgentSecret saves the agent secret from the vault | ||||||
| // This is needed for migration from 8.3.0-8.3.2 to higher versions | ||||||
| func SetAgentSecret(secret Secret, opts ...OptionFunc) error { | ||||||
| return Set(agentSecretKey, secret, opts...) | ||||||
| } | ||||||
|
|
||||||
| // Get reads the secret key from the vault | ||||||
| func Get(key string, opts ...OptionFunc) (secret Secret, err error) { | ||||||
| options := applyOptions(opts...) | ||||||
| v, err := vault.New(options.vaultPath) | ||||||
| // open vault readonly, will not create the vault directory or the seed it was not created before | ||||||
| v, err := vault.New(options.vaultPath, vault.WithReadonly(true)) | ||||||
| if err != nil { | ||||||
| return secret, err | ||||||
| } | ||||||
|
|
@@ -111,6 +113,26 @@ func Get(key string, opts ...OptionFunc) (secret Secret, err error) { | |||||
| return secret, err | ||||||
| } | ||||||
|
|
||||||
| // Set saves the secret key to the vault | ||||||
| func Set(key string, secret Secret, opts ...OptionFunc) error { | ||||||
| options := applyOptions(opts...) | ||||||
| v, err := vault.New(options.vaultPath) | ||||||
| if err != nil { | ||||||
| return err | ||||||
|
||||||
| return err | |
| return fmt.Errorf("could not create new vault: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion]
Wrap the error to add more context
| return err | |
| return fmt.Errorf("could not marshal secret: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ import ( | |
| "github.com/elastic/elastic-agent/internal/pkg/agent/configuration" | ||
| "github.com/elastic/elastic-agent/internal/pkg/agent/control/server" | ||
| "github.com/elastic/elastic-agent/internal/pkg/agent/errors" | ||
| "github.com/elastic/elastic-agent/internal/pkg/agent/migration" | ||
| "github.com/elastic/elastic-agent/internal/pkg/agent/storage" | ||
| "github.com/elastic/elastic-agent/internal/pkg/cli" | ||
| "github.com/elastic/elastic-agent/internal/pkg/config" | ||
|
|
@@ -121,6 +122,21 @@ func run(override cfgOverrider) error { | |
| createAgentID = false | ||
| } | ||
|
|
||
| // This is specific for the agent upgrade from 8.3.0 - 8.3.2 to 8.x and above on Linux and Windows platforms. | ||
| // Addresses the issue: https://github.com/elastic/elastic-agent/issues/682 | ||
| // The vault directory was located in the hash versioned "Home" directory of the agent. | ||
| // This moves the vault directory two levels up into the "Config" directory next to fleet.enc file | ||
| // in order to be able to "upgrade" the agent from deb/rpm that is not invoking the upgrade handle and | ||
| // doesn't perform the migration of the state or vault. | ||
| // If the agent secret doesn't exist, then search for the newest agent secret in the agent data directories | ||
| // and migrate it into the new vault location. | ||
| err = migration.MigrateAgentSecret(logger) | ||
| logger.Debug("migration of agent secret completed, err: %v", err) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it need to be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think it's fine, it's noop on Darwin and would only do this kind of migration if the 8.3.0-8.3.2 agents where previously installed. |
||
| if err != nil { | ||
| logger.Error(err) | ||
AndersonQ marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return err | ||
| } | ||
|
|
||
| // Ensure we have the agent secret created. | ||
| // The secret is not created here if it exists already from the previous enrollment. | ||
| // This is needed for compatibility with agent running in standalone mode, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,136 @@ | ||||||||||||||
| // Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||||||||||||||
| // or more contributor license agreements. Licensed under the Elastic License; | ||||||||||||||
| // you may not use this file except in compliance with the Elastic License. | ||||||||||||||
|
|
||||||||||||||
| package migration | ||||||||||||||
|
|
||||||||||||||
| import ( | ||||||||||||||
| "errors" | ||||||||||||||
| "io/fs" | ||||||||||||||
| "os" | ||||||||||||||
| "path/filepath" | ||||||||||||||
| "runtime" | ||||||||||||||
| "strings" | ||||||||||||||
|
|
||||||||||||||
| "github.com/elastic/elastic-agent-libs/logp" | ||||||||||||||
| "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" | ||||||||||||||
| "github.com/elastic/elastic-agent/internal/pkg/agent/application/secret" | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| const ( | ||||||||||||||
| darwin = "darwin" | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| // MigrateAgentSecret migrates agent secret if the secret doesn't exists agent upgrade from 8.3.0 - 8.3.2 to 8.x and above on Linux and Windows platforms. | ||||||||||||||
| func MigrateAgentSecret(log *logp.Logger) error { | ||||||||||||||
| // Nothing to migrate for darwin | ||||||||||||||
| if runtime.GOOS == darwin { | ||||||||||||||
| return nil | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // Check if the secret already exists | ||||||||||||||
| log.Debug("migrate agent secret, check if secret already exists") | ||||||||||||||
| _, err := secret.GetAgentSecret() | ||||||||||||||
| if err != nil { | ||||||||||||||
| if errors.Is(err, fs.ErrNotExist) { | ||||||||||||||
| // The secret doesn't exists, perform migration below | ||||||||||||||
| log.Debug("agent secret doesn't exists, perform migration") | ||||||||||||||
| } else { | ||||||||||||||
| log.Errorf("failed read the agent secret: %v", err) | ||||||||||||||
| return err | ||||||||||||||
|
||||||||||||||
| log.Errorf("failed read the agent secret: %v", err) | |
| return err | |
| log.Errorf() | |
| return fmt.Errorf("failed read the agent secret: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Blocker]
It's important to add more context to the error, also, I'd avoid the double logging and would just wrap the error instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Blocker]
It's important to add more context to the error, also, I'd avoid the double logging and would just wrap the error instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
AndersonQ marked this conversation as resolved.
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a wee confused here. The comment says it'll ignore the error, but you handle it and return on error. Is it "ignore fs.ErrNotExist errors only"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated the comment and location
AndersonQ marked this conversation as resolved.
Show resolved
Hide resolved
AndersonQ marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Nit]
Keep it consistent with the function name
| func getLegacyVaultPathFromPath(homePath string) string { | |
| return filepath.Join(homePath, "vault") | |
| } | |
| func getLegacyVaultPathFromPath(path string) string { | |
| return filepath.Join(path, "vault") | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo?