From 68e68441673e6086eae6f023cc13aa98b0d7e51b Mon Sep 17 00:00:00 2001 From: michaeljguarino Date: Tue, 12 Sep 2023 23:33:21 -0400 Subject: [PATCH] Add semver validation for required bootstrap tf/helm modules on migration (#445) There are now some requirements for performing a migration tied to our helm/tf. This will at least guarantee they're installed at migrate time. --- cmd/plural/clusters.go | 10 +++- go.mod | 1 + pkg/bootstrap/validation/migration.go | 69 +++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 pkg/bootstrap/validation/migration.go diff --git a/cmd/plural/clusters.go b/cmd/plural/clusters.go index 78160c4e..91fa2624 100644 --- a/cmd/plural/clusters.go +++ b/cmd/plural/clusters.go @@ -9,6 +9,7 @@ import ( "github.com/pluralsh/plural/pkg/api" "github.com/pluralsh/plural/pkg/bootstrap" "github.com/pluralsh/plural/pkg/bootstrap/aws" + "github.com/pluralsh/plural/pkg/bootstrap/validation" "github.com/pluralsh/plural/pkg/cluster" "github.com/pluralsh/plural/pkg/config" "github.com/pluralsh/plural/pkg/exp" @@ -84,7 +85,7 @@ func (p *Plural) clusterCommands() []cli.Command { { Name: "migrate", Usage: "migrate to Cluster API", - Action: latestVersion(rooted(initKubeconfig(handleMigration))), + Action: latestVersion(rooted(initKubeconfig(p.handleMigration))), Category: "Publishing", Hidden: !exp.IsFeatureEnabled(exp.EXP_PLURAL_CAPI), }, @@ -96,7 +97,12 @@ func (p *Plural) clusterCommands() []cli.Command { } } -func handleMigration(_ *cli.Context) error { +func (p *Plural) handleMigration(_ *cli.Context) error { + p.InitPluralClient() + if err := validation.ValidateMigration(p); err != nil { + return err + } + project, err := manifest.FetchProject() if err != nil { return err diff --git a/go.mod b/go.mod index 83246c11..e3547919 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/Azure/azure-storage-blob-go v0.15.0 github.com/Azure/azure-workload-identity v1.1.0 github.com/Azure/go-autorest/autorest v0.11.29 + github.com/Masterminds/semver v1.5.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/Yamashou/gqlgenc v0.14.0 github.com/aws/aws-sdk-go-v2 v1.18.0 diff --git a/pkg/bootstrap/validation/migration.go b/pkg/bootstrap/validation/migration.go new file mode 100644 index 00000000..e53431ae --- /dev/null +++ b/pkg/bootstrap/validation/migration.go @@ -0,0 +1,69 @@ +package validation + +import ( + "fmt" + + "github.com/Masterminds/semver" + "github.com/pluralsh/plural/pkg/api" +) + +var ( + tfRequirements = map[string]string{ + "aws-bootstrap": ">= 0.1.53", + "gcp-bootstrap": ">= 0.2.24", + "azure-bootstrap": ">= 0.2.0", + } + helmRequirements = map[string]string{ + "bootstrap": ">= 0.8.72", + } +) + +func ValidateMigration(client api.Client) error { + repo, err := client.GetRepository("bootstrap") + if err != nil { + return err + } + + charts, tfs, err := client.GetPackageInstallations(repo.Id) + if err != nil { + return err + } + chartsByName, tfsByName := map[string]*api.ChartInstallation{}, map[string]*api.TerraformInstallation{} + for _, chart := range charts { + chartsByName[chart.Chart.Name] = chart + } + for _, tf := range tfs { + tfsByName[tf.Terraform.Name] = tf + } + + for name, req := range tfRequirements { + if tf, ok := tfsByName[name]; ok { + if !testSemver(req, tf.Version.Version) { + return fmt.Errorf("You must have installed the %s terraform module at least at version %s to run cluster migration, your version is %s", name, req, tf.Version.Version) + } + } + } + + for name, req := range helmRequirements { + if chart, ok := chartsByName[name]; ok { + if !testSemver(req, chart.Version.Version) { + return fmt.Errorf("You must have installed the %s helm chart at least at version %s to run cluster migration, your version is %s", name, req, chart.Version.Version) + } + } + } + + return nil +} + +func testSemver(constraint, vsn string) bool { + c, err := semver.NewConstraint(constraint) + if err != nil { + return false + } + v, err := semver.NewVersion(vsn) + if err != nil { + return false + } + + return c.Check(v) +}