diff --git a/cmd/flux/bootstrap.go b/cmd/flux/bootstrap.go index d48ed437..c87ccf43 100644 --- a/cmd/flux/bootstrap.go +++ b/cmd/flux/bootstrap.go @@ -132,6 +132,13 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes return "", err } bootstrapArgs.version = version + } else { + if ok, err := install.ExistingVersion(bootstrapArgs.version); err != nil || !ok { + if err == nil { + err = fmt.Errorf("targeted version '%s' does not exist", bootstrapArgs.version) + } + return "", err + } } opts := install.Options{ diff --git a/cmd/flux/install.go b/cmd/flux/install.go index 8bd02327..7816023f 100644 --- a/cmd/flux/install.go +++ b/cmd/flux/install.go @@ -106,19 +106,9 @@ func installCmdRun(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) defer cancel() - tmpDir, err := ioutil.TempDir("", rootArgs.namespace) - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - if !installExport { - logger.Generatef("generating manifests") - } - components := append(installDefaultComponents, installExtraComponents...) - - if err := utils.ValidateComponents(components); err != nil { + err := utils.ValidateComponents(components) + if err != nil { return err } @@ -127,6 +117,23 @@ func installCmdRun(cmd *cobra.Command, args []string) error { if err != nil { return err } + } else { + if ok, err := install.ExistingVersion(installVersion); err != nil || !ok { + if err == nil { + err = fmt.Errorf("targeted version '%s' does not exist", installVersion) + } + return err + } + } + + tmpDir, err := ioutil.TempDir("", rootArgs.namespace) + if err != nil { + return err + } + defer os.RemoveAll(tmpDir) + + if !installExport { + logger.Generatef("generating manifests") } opts := install.Options{ diff --git a/pkg/manifestgen/install/install.go b/pkg/manifestgen/install/install.go index feb83046..f5168545 100644 --- a/pkg/manifestgen/install/install.go +++ b/pkg/manifestgen/install/install.go @@ -87,7 +87,7 @@ func GetLatestVersion() (string, error) { res, err := c.Get(ghURL) if err != nil { - return "", fmt.Errorf("calling GitHub API failed: %w", err) + return "", fmt.Errorf("GitHub API call failed: %w", err) } if res.Body != nil { @@ -104,3 +104,32 @@ func GetLatestVersion() (string, error) { return m.Tag, err } + +// ExistingVersion calls the GitHub API to confirm the given version does exist. +func ExistingVersion(version string) (bool, error) { + if !strings.HasPrefix(version, "v") { + version = "v" + version + } + + ghURL := fmt.Sprintf("https://api.github.com/repos/fluxcd/flux2/releases/tags/%s", version) + c := http.DefaultClient + c.Timeout = 15 * time.Second + + res, err := c.Get(ghURL) + if err != nil { + return false, fmt.Errorf("GitHub API call failed: %w", err) + } + + if res.Body != nil { + defer res.Body.Close() + } + + switch res.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusNotFound: + return false, nil + default: + return false, fmt.Errorf("GitHub API returned an unexpected status code (%d)", res.StatusCode) + } +}