-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
feat: Add upgrade proposal plan validation to CLI #10379
Merged
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
ac64aa1
[10286]: Create planinfo.go to house some validation pieces related t…
dwedul-figure 22886b7
[10286]: Update the cli software-upgrade process to have a --no-valid…
dwedul-figure 7cfac32
[10286]: Refactor the new planinfo.go stuff to make it hopefully hand…
dwedul-figure 4ce1a17
[10286]: Switch up the --daemon-name flag a bit. Just use the DAEMON_…
dwedul-figure 5c869f5
[10286]: Add github.com/hashicorp/go-getter v1.4.1 to the main go.mod…
dwedul-figure 04d2f54
[10286]: Move the planinfo.go file into a new planinfo folder/package…
dwedul-figure 161fff8
[10286]: Prep and plan some new unit tests on the new stuff.
dwedul-figure 581e32b
[10286]: Update the flag descriptions of the new flags.
dwedul-figure b67858d
[10286]: Start work on some unit tests.
dwedul-figure 65b84a8
[10286]: Require a checksum query parameter in the URLs.
dwedul-figure 6f3175b
[10286]: For the binaries map URLs, use make sure there's a checksum …
dwedul-figure b646d58
[10286]: Finish up unit tests on download.go.
dwedul-figure 0b835f8
[10286]: Fix wording of no-validate flag.
dwedul-figure 7a7f795
[10286]: Fix some wording on the daemon-name flag.
dwedul-figure 71abcf6
[10286]: Move the makeFileURL out of the function it's in so it can b…
dwedul-figure 8d5cec9
[10286]: Create plan info unit tests.
dwedul-figure 604a5be
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure aecbdda
[10286]: gofmt the new unit test files.
dwedul-figure 3ad28b4
[10286]: Add changelog line for issue 10286.
dwedul-figure 2d727d1
[10286]: Get rid of the package global osArchRx and make it just a va…
dwedul-figure 0860283
[10286]: Rename planinfo.go to plan_info.go
dwedul-figure b7ec6b7
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 3faff93
[10286]: Fail validation if the plan.info string is blank.
dwedul-figure 13a6cea
[10286]: Add unit test for new blank infoStr error.
dwedul-figure 4d7384a
[10286]: Update the usage string for the --upgrade-info flag.
dwedul-figure fbc8e65
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 233beb3
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 73ae27a
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 71f1ba1
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 7acb128
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure fda7d0c
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 2f1dfaa
[10286]: Add a little description of the default for the --daemon-nam…
dwedul-figure 5a39cad
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 1fa8830
[10286]: Add comment on the binary operation done to check executable…
dwedul-figure fff68d4
[10286]: Update comment on DownloadUpgrade to provide more information.
dwedul-figure 5176c9d
[10286]: Update the comment on EnsureBinary to have more details.
dwedul-figure 89efbb1
[10286]: Rename checkURL to validateIsURLWithChecksum to be clearer a…
dwedul-figure 236af7d
[10286]: Rename downloadUpgradeAsDir to downloadUpgradeAsArchive sinc…
dwedul-figure 34781f8
[10286]: Rename DownloadPlanInfoFromURL to DownloadURLWithChecksum an…
dwedul-figure 4cdeb58
[10286]: Update error message from 'plan info cannot be blank' to 'pl…
dwedul-figure 482c9f1
[10286]: Move the x/upgrade/types/planinfo stuff into x/upgrade/plan …
dwedul-figure 716bc54
[10286]: Remove the punctuation at the end of the new software-upgrad…
dwedul-figure 26093e8
[10286]: Add a little more to the --daemon-name description to hopefu…
dwedul-figure 61706d7
[10286]: Make validateIsURLWithChecksum public since it's now named b…
dwedul-figure 2641576
[10286]: Fix unit test that broke due to change.
dwedul-figure 320d49f
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure 382a137
Merge branch 'master' into dwedul/10286-upgrade-prop-validation
dwedul-figure File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package plan | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
neturl "net/url" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-getter" | ||
) | ||
|
||
// DownloadUpgrade downloads the given url into the provided directory and ensures it's valid. | ||
// The provided url must contain a checksum parameter that matches the file being downloaded. | ||
// If this returns nil, the download was successful, and {dstRoot}/bin/{daemonName} is a regular executable file. | ||
// This is an opinionated directory structure that corresponds with Cosmovisor requirements. | ||
// If the url is not an archive, it is downloaded and saved to {dstRoot}/bin/{daemonName}. | ||
// If the url is an archive, it is downloaded and unpacked to {dstRoot}. | ||
// If the archive does not contain a /bin/{daemonName} file, then this will attempt to move /{daemonName} to /bin/{daemonName}. | ||
// If the archive does not contain either /bin/{daemonName} or /{daemonName}, an error is returned. | ||
// Note: Because a checksum is required, this function cannot be used to download non-archive directories. | ||
// If dstRoot already exists, some or all of its contents might be updated. | ||
func DownloadUpgrade(dstRoot, url, daemonName string) error { | ||
if err := ValidateIsURLWithChecksum(url); err != nil { | ||
return err | ||
} | ||
target := filepath.Join(dstRoot, "bin", daemonName) | ||
// First try to download it as a single file. If there's no error, it's okay and we're done. | ||
if err := getter.GetFile(target, url); err != nil { | ||
// If it was a checksum error, no need to try as directory. | ||
if _, ok := err.(*getter.ChecksumError); ok { | ||
return err | ||
} | ||
// File download didn't work, try it as an archive. | ||
if err = downloadUpgradeAsArchive(dstRoot, url, daemonName); err != nil { | ||
// Out of options, send back the error. | ||
return err | ||
} | ||
} | ||
return EnsureBinary(target) | ||
} | ||
|
||
// downloadUpgradeAsArchive tries to download the given url as an archive. | ||
// The archive is unpacked and saved in dstDir. | ||
// If the archive contains /{daemonName} and not /bin/{daemonName}, then /{daemonName} will be moved to /bin/{daemonName}. | ||
// If this returns nil, the download was successful, and {dstDir}/bin/{daemonName} is a regular executable file. | ||
func downloadUpgradeAsArchive(dstDir, url, daemonName string) error { | ||
err := getter.Get(dstDir, url) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// If bin/{daemonName} exists, we're done. | ||
dstDirBinFile := filepath.Join(dstDir, "bin", daemonName) | ||
err = EnsureBinary(dstDirBinFile) | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
// Otherwise, check for a root {daemonName} file and move it to the bin/ directory if found. | ||
dstDirFile := filepath.Join(dstDir, daemonName) | ||
err = EnsureBinary(dstDirFile) | ||
if err == nil { | ||
err = os.Rename(dstDirFile, dstDirBinFile) | ||
if err != nil { | ||
return fmt.Errorf("could not move %s to the bin directory: %w", daemonName, err) | ||
} | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("url \"%s\" result does not contain a bin/%s or %s file", url, daemonName, daemonName) | ||
} | ||
|
||
// EnsureBinary checks that the given file exists as a regular file and is executable. | ||
// An error is returned if: | ||
// - The file does not exist. | ||
// - The path exists, but is one of: Dir, Symlink, NamedPipe, Socket, Device, CharDevice, or Irregular. | ||
// - The file exists, is not executable by all three of User, Group, and Other, and cannot be made executable. | ||
func EnsureBinary(path string) error { | ||
info, err := os.Stat(path) | ||
if err != nil { | ||
return err | ||
} | ||
if !info.Mode().IsRegular() { | ||
_, f := filepath.Split(path) | ||
return fmt.Errorf("%s is not a regular file", f) | ||
} | ||
// Make sure all executable bits are set. | ||
oldMode := info.Mode().Perm() | ||
newMode := oldMode | 0111 // Set the three execute bits to on (a+x). | ||
if oldMode != newMode { | ||
return os.Chmod(path, newMode) | ||
} | ||
return nil | ||
} | ||
|
||
// DownloadURLWithChecksum gets the contents of the given url, ensuring the checksum is correct. | ||
// The provided url must contain a checksum parameter that matches the file being downloaded. | ||
// If there isn't an error, the content returned by the url will be returned as a string. | ||
// Returns an error if: | ||
// - The url is not a URL or does not contain a checksum parameter. | ||
// - Downloading the URL fails. | ||
// - The checksum does not match what is returned by the URL. | ||
// - The URL does not return a regular file. | ||
// - The downloaded file is empty or only whitespace. | ||
func DownloadURLWithChecksum(url string) (string, error) { | ||
if err := ValidateIsURLWithChecksum(url); err != nil { | ||
return "", err | ||
} | ||
tempDir, err := os.MkdirTemp("", "reference") | ||
if err != nil { | ||
return "", fmt.Errorf("could not create temp directory: %w", err) | ||
} | ||
defer os.RemoveAll(tempDir) | ||
tempFile := filepath.Join(tempDir, "content") | ||
if err = getter.GetFile(tempFile, url); err != nil { | ||
return "", fmt.Errorf("could not download url \"%s\": %w", url, err) | ||
} | ||
tempFileBz, rerr := os.ReadFile(tempFile) | ||
if rerr != nil { | ||
return "", fmt.Errorf("could not read downloaded temporary file: %w", rerr) | ||
} | ||
tempFileStr := strings.TrimSpace(string(tempFileBz)) | ||
if len(tempFileStr) == 0 { | ||
return "", fmt.Errorf("no content returned by \"%s\"", url) | ||
} | ||
return tempFileStr, nil | ||
} | ||
|
||
// ValidateIsURLWithChecksum checks that the given string is a url and contains a checksum query parameter. | ||
func ValidateIsURLWithChecksum(urlStr string) error { | ||
url, err := neturl.Parse(urlStr) | ||
if err != nil { | ||
return err | ||
} | ||
if len(url.Query().Get("checksum")) == 0 { | ||
return errors.New("missing checksum query parameter") | ||
} | ||
return nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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: typically, I think env vars take precedence over flags.
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.
Nope. Flags take top priority. Environment variables aren't obvious when executing a command, but flags and options are. Having an env var take precedence over a flag would cause confusion. For reference, the
Viper
library uses this order of precedence: flag > env var > config file value > default.