-
Notifications
You must be signed in to change notification settings - Fork 2k
[teleport-update] Support for Enterprise/FIPS migration #49451
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 all commits
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -19,7 +19,9 @@ | |||||
| package agent | ||||||
|
|
||||||
| import ( | ||||||
| "encoding/json" | ||||||
| "errors" | ||||||
| "fmt" | ||||||
| "io/fs" | ||||||
| "os" | ||||||
| "strings" | ||||||
|
|
@@ -67,12 +69,87 @@ type UpdateSpec struct { | |||||
|
|
||||||
| // UpdateStatus describes the status field in update.yaml. | ||||||
| type UpdateStatus struct { | ||||||
| // ActiveVersion is the currently active Teleport version. | ||||||
| ActiveVersion string `yaml:"active_version"` | ||||||
| // BackupVersion is the last working version of Teleport. | ||||||
| BackupVersion string `yaml:"backup_version"` | ||||||
| // SkipVersion is the last reverted version of Teleport. | ||||||
| SkipVersion string `yaml:"skip_version,omitempty"` | ||||||
| // Active is the currently active revision of Teleport. | ||||||
| Active Revision `yaml:"active"` | ||||||
| // Backup is the last working revision of Teleport. | ||||||
| Backup *Revision `yaml:"backup,omitempty"` | ||||||
| // Skip is the skipped revision of Teleport. | ||||||
| // Skipped revisions are not applied because they | ||||||
| // are known to crash. | ||||||
| Skip *Revision `yaml:"skip,omitempty"` | ||||||
| } | ||||||
|
|
||||||
| // Revision is a version and edition of Teleport. | ||||||
| type Revision struct { | ||||||
| // Version is the version of Teleport. | ||||||
| Version string `yaml:"version" json:"version"` | ||||||
| // Flags describe the edition of Teleport. | ||||||
| Flags InstallFlags `yaml:"flags,flow,omitempty" json:"flags,omitempty"` | ||||||
| } | ||||||
|
|
||||||
| // NewRevision create a Revision. | ||||||
| // If version is not set, no flags are returned. | ||||||
| // This ensures that all Revisions without versions are zero-valued. | ||||||
| func NewRevision(version string, flags InstallFlags) Revision { | ||||||
| if version != "" { | ||||||
| return Revision{ | ||||||
| Version: version, | ||||||
| Flags: flags, | ||||||
| } | ||||||
| } | ||||||
| return Revision{} | ||||||
| } | ||||||
|
|
||||||
| // NewRevisionFromDir translates a directory path containing Teleport into a Revision. | ||||||
| func NewRevisionFromDir(dir string) (Revision, error) { | ||||||
| parts := strings.Split(dir, "_") | ||||||
| var out Revision | ||||||
| if len(parts) == 0 { | ||||||
| return out, trace.Errorf("dir name empty") | ||||||
| } | ||||||
| out.Version = parts[0] | ||||||
| if out.Version == "" { | ||||||
| return out, trace.Errorf("version missing in dir %s", dir) | ||||||
| } | ||||||
| switch flags := parts[1:]; len(flags) { | ||||||
| case 2: | ||||||
| if flags[1] != FlagFIPS.DirFlag() { | ||||||
| break | ||||||
| } | ||||||
| out.Flags |= FlagFIPS | ||||||
| fallthrough | ||||||
| case 1: | ||||||
| if flags[0] != FlagEnterprise.DirFlag() { | ||||||
| break | ||||||
| } | ||||||
| out.Flags |= FlagEnterprise | ||||||
| fallthrough | ||||||
| case 0: | ||||||
| return out, nil | ||||||
| } | ||||||
| return out, trace.Errorf("invalid flag in %s", dir) | ||||||
| } | ||||||
|
|
||||||
| // Dir returns the directory path name of a Revision. | ||||||
| func (r Revision) Dir() string { | ||||||
| // Do not change the order of these statements. | ||||||
| // Otherwise, installed versions will no longer match update.yaml. | ||||||
| var suffix string | ||||||
| if r.Flags&(FlagEnterprise|FlagFIPS) != 0 { | ||||||
| suffix += "_" + FlagEnterprise.DirFlag() | ||||||
| } | ||||||
| if r.Flags&FlagFIPS != 0 { | ||||||
| suffix += "_" + FlagFIPS.DirFlag() | ||||||
| } | ||||||
| return r.Version + suffix | ||||||
| } | ||||||
|
|
||||||
| // String returns a human-readable description of a Teleport revision. | ||||||
| func (r Revision) String() string { | ||||||
| if flags := r.Flags.Strings(); len(flags) > 0 { | ||||||
| return fmt.Sprintf("%s+%s", r.Version, strings.Join(flags, "+")) | ||||||
| } | ||||||
| return r.Version | ||||||
| } | ||||||
|
|
||||||
| // readConfig reads UpdateConfig from a file. | ||||||
|
|
@@ -93,10 +170,10 @@ func readConfig(path string) (*UpdateConfig, error) { | |||||
| return nil, trace.Wrap(err, "failed to parse") | ||||||
| } | ||||||
| if k := cfg.Kind; k != updateConfigKind { | ||||||
| return nil, trace.Errorf("invalid kind %q", k) | ||||||
| return nil, trace.Errorf("invalid kind %s", k) | ||||||
| } | ||||||
| if v := cfg.Version; v != updateConfigVersion { | ||||||
| return nil, trace.Errorf("invalid version %q", v) | ||||||
| return nil, trace.Errorf("invalid version %s", v) | ||||||
| } | ||||||
| return &cfg, nil | ||||||
| } | ||||||
|
|
@@ -155,10 +232,8 @@ type Status struct { | |||||
|
|
||||||
| // FindResp summarizes the auto-update status response from cluster. | ||||||
| type FindResp struct { | ||||||
| // Version of Teleport to install | ||||||
| TargetVersion string `yaml:"target_version"` | ||||||
| // Flags describing the edition of Teleport | ||||||
| Flags InstallFlags `yaml:"flags"` | ||||||
| // Target revision of Teleport to install | ||||||
| Target Revision `yaml:"target"` | ||||||
| // InWindow is true when the install should happen now. | ||||||
| InWindow bool `yaml:"in_window"` | ||||||
| // Jitter duration before an automated install | ||||||
|
|
@@ -175,10 +250,23 @@ const ( | |||||
| FlagFIPS | ||||||
| ) | ||||||
|
|
||||||
| func (i InstallFlags) MarshalYAML() (any, error) { | ||||||
| return i.Strings(), nil | ||||||
| // NewInstallFlagsFromStrings returns InstallFlags given a slice of human-readable strings. | ||||||
| func NewInstallFlagsFromStrings(s []string) InstallFlags { | ||||||
| var out InstallFlags | ||||||
| for _, f := range s { | ||||||
| for _, flag := range []InstallFlags{ | ||||||
| FlagEnterprise, | ||||||
| FlagFIPS, | ||||||
| } { | ||||||
| if f == flag.String() { | ||||||
| out |= flag | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| return out | ||||||
| } | ||||||
|
|
||||||
| // Strings converts InstallFlags to a slice of human-readable strings. | ||||||
| func (i InstallFlags) Strings() []string { | ||||||
| var out []string | ||||||
| for _, flag := range []InstallFlags{ | ||||||
|
|
@@ -192,6 +280,7 @@ func (i InstallFlags) Strings() []string { | |||||
| return out | ||||||
| } | ||||||
|
|
||||||
| // String returns the string representation of a single InstallFlag flag, or "Unknown". | ||||||
| func (i InstallFlags) String() string { | ||||||
| switch i { | ||||||
| case 0: | ||||||
|
|
@@ -203,3 +292,36 @@ func (i InstallFlags) String() string { | |||||
| } | ||||||
| return "Unknown" | ||||||
| } | ||||||
|
|
||||||
| // DirFlag returns the directory path representation of a single InstallFlag flag, or "unknown". | ||||||
| func (i InstallFlags) DirFlag() string { | ||||||
| switch i { | ||||||
| case 0: | ||||||
| return "" | ||||||
| case FlagEnterprise: | ||||||
| return "ent" | ||||||
| case FlagFIPS: | ||||||
|
Collaborator
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. Are these bit flags? Any risk of us converting to "unknown" if both
Suggested change
Member
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. These are bit flags. This method is just intended for single-bit contexts, similar to |
||||||
| return "fips" | ||||||
| } | ||||||
| return "unknown" | ||||||
| } | ||||||
|
|
||||||
| func (i InstallFlags) MarshalYAML() (any, error) { | ||||||
| return i.Strings(), nil | ||||||
| } | ||||||
|
|
||||||
| func (i InstallFlags) MarshalJSON() ([]byte, error) { | ||||||
| return json.Marshal(i.Strings()) | ||||||
| } | ||||||
|
|
||||||
| func (i *InstallFlags) UnmarshalYAML(n *yaml.Node) error { | ||||||
| var s []string | ||||||
| if err := n.Decode(&s); err != nil { | ||||||
| return trace.Wrap(err) | ||||||
| } | ||||||
| if i == nil { | ||||||
| return trace.BadParameter("nil install flags while parsing YAML") | ||||||
| } | ||||||
| *i = NewInstallFlagsFromStrings(s) | ||||||
| return nil | ||||||
| } | ||||||
Uh oh!
There was an error while loading. Please reload this page.