From d3db858852869748a6e511ef30a39b8a5e404136 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 19 Aug 2022 09:55:39 +1000 Subject: [PATCH] feat: add initial compatability check --- cmd/root.go | 8 +- cmd/validate_lagoonversion.go | 73 ++++++++++++ cmd/validate_lagoonversion_test.go | 143 ++++++++++++++++++++++++ go.mod | 3 +- go.sum | 1 + internal/compat/compat.go | 27 +++++ internal/compat/compat_test.go | 83 ++++++++++++++ internal/generator/buildvalues.go | 3 +- internal/generator/generator.go | 6 + test-resources/basic/docker-compose.yml | 20 ++++ test-resources/basic/lagoon.yml | 10 ++ 11 files changed, 371 insertions(+), 6 deletions(-) create mode 100644 cmd/validate_lagoonversion.go create mode 100644 cmd/validate_lagoonversion_test.go create mode 100644 internal/compat/compat.go create mode 100644 internal/compat/compat_test.go create mode 100644 test-resources/basic/docker-compose.yml create mode 100644 test-resources/basic/lagoon.yml diff --git a/cmd/root.go b/cmd/root.go index ab20e176..0960600a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -71,10 +71,10 @@ func Execute() { // version/build information (populated at build time by make file) var ( - bdtName = "build-deploy-tool" - bdtVersion = "0.x.x" - bdtBuild = "" - goVersion = "" + bdtName = "build-deploy-tool" + bdtVersion = "0.x.x" + bdtBuild = "" + goVersion = "" ) // version/build information command diff --git a/cmd/validate_lagoonversion.go b/cmd/validate_lagoonversion.go new file mode 100644 index 00000000..65cbe7ae --- /dev/null +++ b/cmd/validate_lagoonversion.go @@ -0,0 +1,73 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/uselagoon/build-deploy-tool/internal/compat" + generator "github.com/uselagoon/build-deploy-tool/internal/generator" +) + +var validateLagoonVersion = &cobra.Command{ + Use: "lagoon-version", + Aliases: []string{"lagoon-ver", "lag-ver", "lver", "lv"}, + Short: "Check if the Lagoon version provided is supported by this tool", + Run: func(cmd *cobra.Command, args []string) { + // check for the LAGOON_SYSTEM_CORE_VERSION + version, err := ValidateLagoonVersion(false) + if err != nil { + fmt.Println(fmt.Sprintf("Unable to validate lagoon version; %v", err)) + os.Exit(1) + } + supported := compat.CheckVersion(version) + if !supported { + fmt.Println(fmt.Sprintf("Lagoon version %s is not supported by this build-deploy-tool, you will need to upgrade your lagoon-core to at least version %s", version, compat.SupportedMinVersion())) + os.Exit(1) + } + }, +} + +// ValidateLagoonVersion . +func ValidateLagoonVersion(debug bool) (string, error) { + lagoonBuild, err := generator.NewGenerator( + lagoonYml, + lagoonYmlOverride, + projectVariables, + environmentVariables, + projectName, + environmentName, + environmentType, + activeEnvironment, + standbyEnvironment, + buildType, + branch, + prNumber, + prTitle, + prHeadBranch, + prBaseBranch, + lagoonVersion, + defaultBackupSchedule, + hourlyDefaultBackupRetention, + dailyDefaultBackupRetention, + weeklyDefaultBackupRetention, + monthlyDefaultBackupRetention, + monitoringContact, + monitoringStatusPageID, + fastlyCacheNoCahce, + fastlyAPISecretPrefix, + fastlyServiceID, + ignoreNonStringKeyErrors, + ignoreMissingEnvFiles, + debug, + ) + if err != nil { + return "", err + } + + return lagoonBuild.BuildValues.LagoonCoreVersion, nil +} + +func init() { + validateCmd.AddCommand(validateLagoonVersion) +} diff --git a/cmd/validate_lagoonversion_test.go b/cmd/validate_lagoonversion_test.go new file mode 100644 index 00000000..3847af38 --- /dev/null +++ b/cmd/validate_lagoonversion_test.go @@ -0,0 +1,143 @@ +package cmd + +import ( + "os" + "testing" + + "github.com/uselagoon/build-deploy-tool/internal/helpers" +) + +func TestValidateLagoonVersion(t *testing.T) { + type args struct { + debug bool + lagoonSystemCoreVersion string + alertContact string + statusPageID string + projectName string + environmentName string + branch string + prNumber string + prHeadBranch string + prBaseBranch string + environmentType string + buildType string + activeEnvironment string + standbyEnvironment string + cacheNoCache string + serviceID string + secretPrefix string + projectVars string + envVars string + lagoonVersion string + lagoonYAML string + valuesFilePath string + templatePath string + } + tests := []struct { + name string + args args + want string + wantErr bool + vars []helpers.EnvironmentVariable + }{ + { + name: "test1", + args: args{ + alertContact: "alertcontact", + statusPageID: "statuspageid", + projectName: "example-project", + environmentName: "main", + environmentType: "production", + buildType: "branch", + lagoonVersion: "v2.7.x", + branch: "main", + projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}, + {"name":"LAGOON_SYSTEM_CORE_VERSION","value":"v2.10.0","scope":"internal_system"}]`, + envVars: `[]`, + lagoonYAML: "../test-resources/basic/lagoon.yml", + }, + want: "v2.10.0", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // set the environment variables from args + err := os.Setenv("MONITORING_ALERTCONTACT", tt.args.alertContact) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("MONITORING_STATUSPAGEID", tt.args.statusPageID) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("PROJECT", tt.args.projectName) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("ENVIRONMENT", tt.args.environmentName) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("BRANCH", tt.args.branch) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("PR_NUMBER", tt.args.prNumber) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("PR_HEAD_BRANCH", tt.args.prHeadBranch) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("PR_BASE_BRANCH", tt.args.prBaseBranch) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("ENVIRONMENT_TYPE", tt.args.environmentType) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("BUILD_TYPE", tt.args.buildType) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("ACTIVE_ENVIRONMENT", tt.args.activeEnvironment) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("STANDBY_ENVIRONMENT", tt.args.standbyEnvironment) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("LAGOON_FASTLY_NOCACHE_SERVICE_ID", tt.args.cacheNoCache) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("LAGOON_PROJECT_VARIABLES", tt.args.projectVars) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("LAGOON_ENVIRONMENT_VARIABLES", tt.args.envVars) + if err != nil { + t.Errorf("%v", err) + } + err = os.Setenv("LAGOON_VERSION", tt.args.lagoonVersion) + if err != nil { + t.Errorf("%v", err) + } + lagoonYml = tt.args.lagoonYAML + got, err := ValidateLagoonVersion(tt.args.debug) + if (err != nil) != tt.wantErr { + t.Errorf("ValidateLagoonVersion() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ValidateLagoonVersion() = %v, want %v", got, tt.want) + } + t.Cleanup(func() { + helpers.UnsetEnvVars(tt.vars) + }) + }) + } +} diff --git a/go.mod b/go.mod index aa2d95ec..691d957e 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,10 @@ require ( github.com/compose-spec/compose-go v1.2.7 github.com/cxmcc/unixsums v0.0.0-20131125091133-89564297d82f github.com/google/go-cmp v0.5.7 + github.com/imdario/mergo v0.3.13 github.com/spf13/cobra v1.4.0 github.com/vshn/k8up v1.99.99 + golang.org/x/mod v0.4.2 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.23.6 k8s.io/apimachinery v0.23.6 @@ -27,7 +29,6 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/googleapis/gnostic v0.5.5 // indirect - github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect diff --git a/go.sum b/go.sum index b41fc041..fc782608 100644 --- a/go.sum +++ b/go.sum @@ -901,6 +901,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/internal/compat/compat.go b/internal/compat/compat.go new file mode 100644 index 00000000..e8d91bd6 --- /dev/null +++ b/internal/compat/compat.go @@ -0,0 +1,27 @@ +package compat + +import ( + "golang.org/x/mod/semver" +) + +// this is the minimum supported version of Lagoon that the build tool can be used with +// if there is a change in lagoon-core that the build tool has to support, then this value +// should be adjusted to the version of lagoon-core to support +// this could also be modified with a compiler flag for developing +var supportedMinVersion = "v2.9.0" + +func checkVersion(version, minVersion string) bool { + comp := semver.Compare(version, minVersion) + if comp == -1 { + return false + } + return true +} + +func CheckVersion(version string) bool { + return checkVersion(version, supportedMinVersion) +} + +func SupportedMinVersion() string { + return supportedMinVersion +} diff --git a/internal/compat/compat_test.go b/internal/compat/compat_test.go new file mode 100644 index 00000000..07c8f9de --- /dev/null +++ b/internal/compat/compat_test.go @@ -0,0 +1,83 @@ +package compat + +import ( + "testing" +) + +func Test_checkVersion(t *testing.T) { + type args struct { + version string + } + tests := []struct { + name string + args args + supportedMinVersion string + want bool + }{ + { + name: "test1", + args: args{ + version: "v2.8.4", + }, + supportedMinVersion: "v2.9.0", + want: false, + }, + { + name: "test2", + args: args{ + version: "v2.9.0", + }, + supportedMinVersion: "v2.9.0", + want: true, + }, + { + name: "test3", + args: args{ + version: "v2.9.3", + }, + supportedMinVersion: "v2.9.0", + want: true, + }, + { + name: "test4", + args: args{ + version: "", + }, + supportedMinVersion: "v2.9.0", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := checkVersion(tt.args.version, tt.supportedMinVersion); got != tt.want { + t.Errorf("checkVersion() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCheckVersion(t *testing.T) { + type args struct { + version string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "test1", + args: args{ + version: "v1.0.0", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CheckVersion(tt.args.version); got != tt.want { + t.Errorf("CheckVersion() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index 44c58aef..c2e13570 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -11,7 +11,8 @@ type BuildValues struct { GitSha string `json:"gitSha"` BuildType string `json:"buildType"` Kubernetes string `json:"kubernetes"` - LagoonVersion string `json:"lagoonVersion"` + LagoonVersion string `json:"lagoonVersion"` // this is the version that is bundled in images, probably stop using this? + LagoonCoreVersion string `json:"lagoonCoreVersion"` // this is the version that will come from lagoon-core ActiveEnvironment string `json:"activeEnvironment"` StandbyEnvironment string `json:"standbyEnvironment"` IsActiveEnvironment bool `json:"isActiveEnvironment"` diff --git a/internal/generator/generator.go b/internal/generator/generator.go index ddd5cb35..d74bb142 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -174,6 +174,12 @@ func NewGenerator( ingressClass := CheckFeatureFlag("INGRESS_CLASS", lagoonEnvVars, debug) buildValues.IngressClass = ingressClass + // get the lagoon core version from the project variables internal_system scope + lagoonCoreVersion, _ := lagoon.GetLagoonVariable("LAGOON_SYSTEM_CORE_VERSION", []string{"internal_system"}, lagoonEnvVars) + if lagoonCoreVersion != nil { + buildValues.LagoonCoreVersion = lagoonCoreVersion.Value + } + // get any variables from the API here lagoonServiceTypes, _ := lagoon.GetLagoonVariable("LAGOON_SERVICE_TYPES", nil, lagoonEnvVars) buildValues.ServiceTypeOverrides = lagoonServiceTypes diff --git a/test-resources/basic/docker-compose.yml b/test-resources/basic/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/basic/docker-compose.yml @@ -0,0 +1,20 @@ +version: '2' +services: + node: + networks: + - amazeeio-network + - default + build: + context: . + dockerfile: node.dockerfile + labels: + lagoon.type: node + volumes: + - .:/app:delegated + environment: + - LAGOON_LOCALDEV_HTTP_PORT=3000 + - LAGOON_ROUTE=http://node.docker.amazee.io + +networks: + amazeeio-network: + external: true \ No newline at end of file diff --git a/test-resources/basic/lagoon.yml b/test-resources/basic/lagoon.yml new file mode 100644 index 00000000..fa52f2e8 --- /dev/null +++ b/test-resources/basic/lagoon.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: ../test-resources/basic/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com