From bc9a81c021c35f96138d15e5b9358562156c4830 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 25 Jul 2022 10:06:36 +1000 Subject: [PATCH 1/4] feat: support ingress class if defined, also fix for monitoring path --- internal/generator/buildvalues.go | 1 + internal/generator/ingress.go | 13 +- internal/generator/ingress_test.go | 309 +++++++++++++++++- internal/lagoon/lagoon.go | 1 + internal/lagoon/routes.go | 24 +- internal/lagoon/routes_test.go | 129 +++++++- .../test11-results/content.example.com.yaml | 2 +- 7 files changed, 460 insertions(+), 19 deletions(-) diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index d0c5334b..25e611c3 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -48,6 +48,7 @@ type BuildValues struct { ServiceTypeOverrides *lagoon.EnvironmentVariable `json:"serviceTypeOverrides"` DBaaSEnvironmentTypeOverrides *lagoon.EnvironmentVariable `json:"dbaasEnvironmentTypeOverrides"` DBaaSFallbackSingle bool `json:"dbaasFallbackSingle"` + DefaultIngressClass string `json:"defaultIngressClass"` } type MonitoringConfig struct { diff --git a/internal/generator/ingress.go b/internal/generator/ingress.go index 2370df08..c17673b9 100644 --- a/internal/generator/ingress.go +++ b/internal/generator/ingress.go @@ -165,6 +165,10 @@ func generateAutogenRoutes( if lagoonYAML.Routes.Autogenerate.Insecure != "" { insecure = lagoonYAML.Routes.Autogenerate.Insecure } + ingressClass := buildValues.DefaultIngressClass + if lagoonYAML.Routes.Autogenerate.IngressClass != "" { + ingressClass = lagoonYAML.Routes.Autogenerate.IngressClass + } autogenRoute := lagoon.RouteV2{ Domain: domain, Fastly: *fastlyConfig, @@ -178,6 +182,7 @@ func generateAutogenRoutes( "lagoon.sh/service": serviceOverrideName, "lagoon.sh/service-type": service.Type, }, + IngressClass: ingressClass, Autogenerated: true, LagoonService: serviceOverrideName, ComposeService: serviceName, @@ -248,7 +253,7 @@ func generateActiveStandbyRoutes( if lagoonYAML.ProductionRoutes.Active != nil { if lagoonYAML.ProductionRoutes.Active.Routes != nil { for _, routeMap := range lagoonYAML.ProductionRoutes.Active.Routes { - lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.FastlyAPISecretPrefix, true) + lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, true) } } } @@ -257,7 +262,7 @@ func generateActiveStandbyRoutes( if lagoonYAML.ProductionRoutes.Standby != nil { if lagoonYAML.ProductionRoutes.Standby.Routes != nil { for _, routeMap := range lagoonYAML.ProductionRoutes.Standby.Routes { - lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.FastlyAPISecretPrefix, true) + lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, true) } } } @@ -302,9 +307,9 @@ func generateAndMerge( // otherwise it just uses the default environment name for _, routeMap := range lagoonYAML.Environments[buildValues.Branch].Routes { - lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.FastlyAPISecretPrefix, false) + lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, false) } // merge routes from the API on top of the routes from the `.lagoon.yml` - mainRoutes := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.FastlyAPISecretPrefix) + mainRoutes := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix) return mainRoutes, nil } diff --git a/internal/generator/ingress_test.go b/internal/generator/ingress_test.go index 6d535524..641ec4de 100644 --- a/internal/generator/ingress_test.go +++ b/internal/generator/ingress_test.go @@ -38,6 +38,25 @@ func Test_getRoutesFromAPIEnvVar(t *testing.T) { }, }, }, + { + name: "test2 - check that route in API is converted to RoutesV2 with ingress class name", + args: args{ + envVars: []lagoon.EnvironmentVariable{ + {Name: "LAGOON_ROUTES_JSON", Value: "eyJyb3V0ZXMiOlt7ImRvbWFpbiI6InRlc3QxLmV4YW1wbGUuY29tIiwic2VydmljZSI6Im5naW54IiwiaW5ncmVzc0NsYXNzIjoiY3VzdG9tLW5naW54IiwidGxzLWFjbWUiOmZhbHNlLCJtb25pdG9yaW5nLXBhdGgiOiIvYnlwYXNzLWNhY2hlIn1dfQ==", Scope: "build"}, + }, + }, + want: &lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "test1.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + MonitoringPath: "/bypass-cache", + IngressClass: "custom-nginx", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -71,7 +90,6 @@ func Test_generateAndMerge(t *testing.T) { want lagoon.RoutesV2 wantErr bool }{ - // TODO: test just API { name: "test1 - generate routes from lagoon yaml and merge ones from api onto them", args: args{ @@ -202,6 +220,96 @@ func Test_generateAndMerge(t *testing.T) { }, }, }, + { + name: "test3 - generate routes from lagoon yaml and merge ones from api onto them with ingress class", + args: args{ + buildValues: BuildValues{ + Branch: "main", + DefaultIngressClass: "nginx", + }, + lagoonYAML: lagoon.YAML{ + Environments: lagoon.Environments{ + "main": lagoon.Environment{ + Routes: []map[string][]lagoon.Route{ + { + "nginx": { + { + Ingresses: map[string]lagoon.Ingress{ + "a.example.com": { + TLSAcme: helpers.BoolPtr(true), + }, + }, + }, + { + Name: "b.example.com", + }, + { + Name: "c.example.com", + }, + }, + }, + }, + }, + }, + }, + api: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "test1.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + MonitoringPath: "/bypass-cache", + }, + { + Domain: "a.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + MonitoringPath: "/bypass-cache", + }, + }, + }, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "a.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/bypass-cache", + IngressClass: "nginx", + }, + { + Domain: "b.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/", + IngressClass: "nginx", + }, + { + Domain: "c.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/", + IngressClass: "nginx", + }, + { + Domain: "test1.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + MonitoringPath: "/bypass-cache", + Insecure: helpers.StrPtr("Redirect"), + Annotations: map[string]string{}, + IngressClass: "nginx", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -267,6 +375,93 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { }, }, }, + { + name: "test2 - with ingress class defined", + args: args{ + buildValues: BuildValues{ + IsActiveEnvironment: true, + DefaultIngressClass: "nginx", + }, + lagoonYAML: lagoon.YAML{ + ProductionRoutes: &lagoon.ProductionRoutes{ + Active: &lagoon.Environment{ + Routes: []map[string][]lagoon.Route{ + { + "nginx": { + { + Ingresses: map[string]lagoon.Ingress{ + "active.example.com": { + TLSAcme: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + }, + envVars: []lagoon.EnvironmentVariable{}, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "active.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Migrate: helpers.BoolPtr(true), + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/", + IngressClass: "nginx", + }, + }, + }, + }, + { + name: "test2 - with custom ingress class defined", + args: args{ + buildValues: BuildValues{ + IsActiveEnvironment: true, + DefaultIngressClass: "nginx", + }, + lagoonYAML: lagoon.YAML{ + ProductionRoutes: &lagoon.ProductionRoutes{ + Active: &lagoon.Environment{ + Routes: []map[string][]lagoon.Route{ + { + "nginx": { + { + Ingresses: map[string]lagoon.Ingress{ + "active.example.com": { + TLSAcme: helpers.BoolPtr(true), + IngressClass: "custom-nginx", + }, + }, + }, + }, + }, + }, + }, + }, + }, + envVars: []lagoon.EnvironmentVariable{}, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "active.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Migrate: helpers.BoolPtr(true), + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/", + IngressClass: "custom-nginx", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -393,6 +588,118 @@ func Test_generateAutogenRoutes(t *testing.T) { }, }, }, + { + name: "test2 - default ingress class", + args: args{ + envVars: []lagoon.EnvironmentVariable{ + { + Name: "LAGOON_SYSTEM_ROUTER_PATTERN", + Value: "${service}-${project}-${environment}.example.com", + Scope: "internal_system", + }, + }, + lagoonYAML: &lagoon.YAML{}, + buildValues: &BuildValues{ + Project: "example-com", + BuildType: "branch", + Environment: "main", + EnvironmentType: "development", + Namespace: "example-com-main", + Services: map[string]ServiceValues{ + "nginx": { + Name: "nginx", + Type: "nginx", + AutogeneratedRoutesEnabled: true, + AutogeneratedRoutesTLSAcme: true, + }, + }, + DefaultIngressClass: "nginx", + }, + autogenRoutes: &lagoon.RoutesV2{}, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "nginx-example-com-main.example.com", + LagoonService: "nginx", + ComposeService: "nginx", + Autogenerated: true, + TLSAcme: helpers.BoolPtr(true), + IngressName: "nginx", + IngressClass: "nginx", + Insecure: helpers.StrPtr("Allow"), + AlternativeNames: []string{}, + Labels: map[string]string{ + "app.kubernetes.io/instance": "nginx", + "app.kubernetes.io/name": "autogenerated-ingress", + "helm.sh/chart": "autogenerated-ingress-0.1.0", + "lagoon.sh/autogenerated": "true", + "lagoon.sh/service": "nginx", + "lagoon.sh/service-type": "nginx", + }, + }, + }, + }, + }, + { + name: "test2 - autogenerated routes ingress class", + args: args{ + envVars: []lagoon.EnvironmentVariable{ + { + Name: "LAGOON_SYSTEM_ROUTER_PATTERN", + Value: "${service}-${project}-${environment}.example.com", + Scope: "internal_system", + }, + }, + lagoonYAML: &lagoon.YAML{ + Routes: lagoon.Routes{ + Autogenerate: lagoon.Autogenerate{ + IngressClass: "custom-nginx", + }, + }, + }, + buildValues: &BuildValues{ + Project: "example-com", + BuildType: "branch", + Environment: "main", + EnvironmentType: "development", + Namespace: "example-com-main", + Services: map[string]ServiceValues{ + "nginx": { + Name: "nginx", + Type: "nginx", + AutogeneratedRoutesEnabled: true, + AutogeneratedRoutesTLSAcme: true, + }, + }, + DefaultIngressClass: "nginx", + }, + autogenRoutes: &lagoon.RoutesV2{}, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "nginx-example-com-main.example.com", + LagoonService: "nginx", + ComposeService: "nginx", + Autogenerated: true, + TLSAcme: helpers.BoolPtr(true), + IngressName: "nginx", + IngressClass: "custom-nginx", + Insecure: helpers.StrPtr("Allow"), + AlternativeNames: []string{}, + Labels: map[string]string{ + "app.kubernetes.io/instance": "nginx", + "app.kubernetes.io/name": "autogenerated-ingress", + "helm.sh/chart": "autogenerated-ingress-0.1.0", + "lagoon.sh/autogenerated": "true", + "lagoon.sh/service": "nginx", + "lagoon.sh/service-type": "nginx", + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/lagoon/lagoon.go b/internal/lagoon/lagoon.go index f603a53b..7814a94f 100644 --- a/internal/lagoon/lagoon.go +++ b/internal/lagoon/lagoon.go @@ -72,6 +72,7 @@ type Autogenerate struct { Insecure string `json:"insecure"` Prefixes []string `json:"prefixes"` TLSAcme *bool `json:"tls-acme,omitempty"` + IngressClass string `json:"ingressClass"` } // UnmarshalLagoonYAML unmarshal the lagoon.yml file into a YAML and map for consumption. diff --git a/internal/lagoon/routes.go b/internal/lagoon/routes.go index 8f6bfb10..db981244 100644 --- a/internal/lagoon/routes.go +++ b/internal/lagoon/routes.go @@ -29,6 +29,7 @@ type RouteV2 struct { ServicePortNumber *int32 `json:"servicePortNumber"` ServicePortName *string `json:"servicePortName"` IngressName string `json:"ingressName"` + IngressClass string `json:"ingressClass"` Autogenerated bool `json:"-"` } @@ -40,6 +41,7 @@ type Ingress struct { MonitoringPath string `json:"monitoring-path,omitempty"` Fastly Fastly `json:"fastly,omitempty"` Annotations map[string]string `json:"annotations,omitempty"` + IngressClass string `json:"ingressClass"` } // Route can be either a string or a map[string]Ingress, so we must @@ -85,7 +87,7 @@ func (r *Route) UnmarshalJSON(data []byte) error { } // GenerateRoutesV2 generate routesv2 definitions from lagoon route mappings -func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variables []EnvironmentVariable, secretPrefix string, activeStandby bool) { +func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variables []EnvironmentVariable, defaultIngressClass, secretPrefix string, activeStandby bool) { for rName, lagoonRoutes := range routeMap { for _, lagoonRoute := range lagoonRoutes { newRoute := RouteV2{} @@ -96,6 +98,7 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable newRoute.Annotations = map[string]string{} newRoute.Fastly.ServiceID = "" newRoute.Fastly.Watch = false + newRoute.IngressClass = defaultIngressClass if activeStandby { newRoute.Migrate = helpers.BoolPtr(true) } @@ -105,6 +108,7 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable for iName, ingress := range lagoonRoute.Ingresses { newRoute.Domain = iName newRoute.LagoonService = rName + newRoute.IngressClass = defaultIngressClass newRoute.Fastly = ingress.Fastly if ingress.Annotations != nil { newRoute.Annotations = ingress.Annotations @@ -115,6 +119,12 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable if ingress.Insecure != nil { newRoute.Insecure = ingress.Insecure } + if ingress.IngressClass != "" { + newRoute.IngressClass = ingress.IngressClass + } + if ingress.MonitoringPath != "" { + newRoute.MonitoringPath = ingress.MonitoringPath + } } } else { // this route is just a domain @@ -134,7 +144,7 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable } // MergeRoutesV2 merge routes from the API onto the previously generated routes. -func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []EnvironmentVariable, secretPrefix string) RoutesV2 { +func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []EnvironmentVariable, defaultIngressClass, secretPrefix string) RoutesV2 { finalRoutes := RoutesV2{} existsInAPI := false // replace any routes from the lagoon yaml with ones from the api @@ -161,6 +171,11 @@ func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []Environme } else { add.Annotations = map[string]string{} } + if aRoute.IngressClass != "" { + add.IngressClass = aRoute.IngressClass + } else { + add.IngressClass = defaultIngressClass + } } } if existsInAPI { @@ -189,6 +204,11 @@ func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []Environme } else { add.Annotations = map[string]string{} } + if aRoute.IngressClass != "" { + add.IngressClass = aRoute.IngressClass + } else { + add.IngressClass = defaultIngressClass + } for _, route := range finalRoutes.Routes { if aRoute.Domain == route.Domain { existsInAPI = true diff --git a/internal/lagoon/routes_test.go b/internal/lagoon/routes_test.go index 5b6e555b..fdc7480e 100644 --- a/internal/lagoon/routes_test.go +++ b/internal/lagoon/routes_test.go @@ -11,11 +11,12 @@ import ( func TestGenerateRouteStructure(t *testing.T) { type args struct { - genRoutes *RoutesV2 - routeMap map[string][]Route - variables []EnvironmentVariable - secretPrefix string - activeStandby bool + genRoutes *RoutesV2 + routeMap map[string][]Route + variables []EnvironmentVariable + defaultIngressClass string + secretPrefix string + activeStandby bool } tests := []struct { name string @@ -120,10 +121,115 @@ func TestGenerateRouteStructure(t *testing.T) { }, }, }, + { + name: "test3 - ingress class", + args: args{ + genRoutes: &RoutesV2{}, + routeMap: map[string][]Route{ + "nginx": { + { + Name: "example.com", + }, + { + Name: "www.example.com", + }, + }, + }, + secretPrefix: "", + defaultIngressClass: "nginx", + activeStandby: false, + }, + want: &RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + IngressClass: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Fastly: Fastly{ + Watch: false, + }, + }, + { + Domain: "www.example.com", + LagoonService: "nginx", + IngressClass: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Fastly: Fastly{ + Watch: false, + }, + }, + }, + }, + }, + { + name: "test4 - custom ingress class on one route", + args: args{ + genRoutes: &RoutesV2{}, + routeMap: map[string][]Route{ + "nginx": { + { + Name: "example.com", + }, + { + Ingresses: map[string]Ingress{ + "www.example.com": { + Fastly: Fastly{ + APISecretName: "annotationscom", + Watch: true, + ServiceID: "12345", + }, + IngressClass: "custom-ingress", + }, + }, + }, + }, + }, + secretPrefix: "fastly-api-", + defaultIngressClass: "nginx", + activeStandby: false, + }, + want: &RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + IngressClass: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Fastly: Fastly{ + Watch: false, + }, + }, + { + Domain: "www.example.com", + LagoonService: "nginx", + IngressClass: "custom-ingress", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Fastly: Fastly{ + APISecretName: "fastly-api-annotationscom", + Watch: true, + ServiceID: "12345", + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - GenerateRoutesV2(tt.args.genRoutes, tt.args.routeMap, tt.args.variables, tt.args.secretPrefix, tt.args.activeStandby) + GenerateRoutesV2(tt.args.genRoutes, tt.args.routeMap, tt.args.variables, tt.args.defaultIngressClass, tt.args.secretPrefix, tt.args.activeStandby) if !cmp.Equal(tt.args.genRoutes, tt.want) { stra, _ := json.Marshal(tt.args.genRoutes) strb, _ := json.Marshal(tt.want) @@ -135,10 +241,11 @@ func TestGenerateRouteStructure(t *testing.T) { func TestMergeRouteStructures(t *testing.T) { type args struct { - genRoutes RoutesV2 - apiRoutes RoutesV2 - variables []EnvironmentVariable - secretPrefix string + genRoutes RoutesV2 + apiRoutes RoutesV2 + variables []EnvironmentVariable + defaultIngressClass string + secretPrefix string } tests := []struct { name string @@ -236,7 +343,7 @@ func TestMergeRouteStructures(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := MergeRoutesV2(tt.args.genRoutes, tt.args.apiRoutes, tt.args.variables, tt.args.secretPrefix); !reflect.DeepEqual(got, tt.want) { + if got := MergeRoutesV2(tt.args.genRoutes, tt.args.apiRoutes, tt.args.variables, tt.args.defaultIngressClass, tt.args.secretPrefix); !reflect.DeepEqual(got, tt.want) { stra, _ := json.Marshal(got) strb, _ := json.Marshal(tt.want) t.Errorf("MergeRouteStructures() = %v, want %v", string(stra), string(strb)) diff --git a/test-resources/template-ingress/test11-results/content.example.com.yaml b/test-resources/template-ingress/test11-results/content.example.com.yaml index fe313731..6f60537a 100644 --- a/test-resources/template-ingress/test11-results/content.example.com.yaml +++ b/test-resources/template-ingress/test11-results/content.example.com.yaml @@ -9,7 +9,7 @@ metadata: lagoon.sh/branch: production lagoon.sh/version: v2.7.x monitor.stakater.com/enabled: "true" - monitor.stakater.com/overridePath: / + monitor.stakater.com/overridePath: /api/v1 nginx.ingress.kubernetes.io/ssl-redirect: "false" uptimerobot.monitor.stakater.com/alert-contacts: alertcontact uptimerobot.monitor.stakater.com/interval: "60" From feda45aaaa8c75c4b415c7c4045b2870efa85809 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 25 Jul 2022 10:06:51 +1000 Subject: [PATCH 2/4] test: add template tests --- .../templating/ingress/templates_ingress.go | 7 +++ .../ingress/templates_ingress_test.go | 37 ++++++++++++++ .../result-custom-ingress3.yaml | 48 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 internal/templating/ingress/test-resources/result-custom-ingress3.yaml diff --git a/internal/templating/ingress/templates_ingress.go b/internal/templating/ingress/templates_ingress.go index 1903e323..124d0c42 100644 --- a/internal/templating/ingress/templates_ingress.go +++ b/internal/templating/ingress/templates_ingress.go @@ -114,6 +114,13 @@ func GenerateIngressTemplate( additionalAnnotations["nginx.ingress.kubernetes.io/server-snippet"] = "add_header X-Robots-Tag \"noindex, nofollow\";\n" } + // add ingressclass support to ingress template generation + if route.IngressClass != "" { + ingress.Spec.IngressClassName = &route.IngressClass + // add the certmanager ingressclass annotation + additionalAnnotations["acme.cert-manager.io/http01-ingress-class"] = route.IngressClass + } + // add any additional labels for key, value := range additionalLabels { ingress.ObjectMeta.Labels[key] = value diff --git a/internal/templating/ingress/templates_ingress_test.go b/internal/templating/ingress/templates_ingress_test.go index 09d0b66e..21a83e9c 100644 --- a/internal/templating/ingress/templates_ingress_test.go +++ b/internal/templating/ingress/templates_ingress_test.go @@ -129,6 +129,43 @@ func TestGenerateKubeTemplate(t *testing.T) { }, want: "test-resources/result-custom-ingress2.yaml", }, + { + name: "test3 - custom ingress with ingress class", + args: args{ + route: lagoon.RouteV2{ + Domain: "extra-long-name.a-really-long-name-that-should-truncate.www.example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Migrate: helpers.BoolPtr(false), + Annotations: map[string]string{ + "custom-annotation": "custom annotation value", + }, + Fastly: lagoon.Fastly{ + Watch: false, + }, + IngressClass: "nginx", + }, + values: generator.BuildValues{ + Project: "example-project", + Environment: "environment-with-really-really-reall-3fdb", + EnvironmentType: "development", + Namespace: "myexample-project-environment-with-really-really-reall-3fdb", + BuildType: "branch", + LagoonVersion: "v2.x.x", + Kubernetes: "lagoon.local", + Branch: "environment-with-really-really-reall-3fdb", + Monitoring: generator.MonitoringConfig{ + AlertContact: "abcdefg", + StatusPageID: "12345", + Enabled: true, + }, + }, + activeStandby: false, + }, + want: "test-resources/result-custom-ingress3.yaml", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/templating/ingress/test-resources/result-custom-ingress3.yaml b/internal/templating/ingress/test-resources/result-custom-ingress3.yaml new file mode 100644 index 00000000..62eb4a5d --- /dev/null +++ b/internal/templating/ingress/test-resources/result-custom-ingress3.yaml @@ -0,0 +1,48 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + acme.cert-manager.io/http01-ingress-class: nginx + custom-annotation: custom annotation value + fastly.amazee.io/watch: "false" + ingress.kubernetes.io/ssl-redirect: "true" + kubernetes.io/tls-acme: "true" + lagoon.sh/branch: environment-with-really-really-reall-3fdb + lagoon.sh/version: v2.x.x + nginx.ingress.kubernetes.io/server-snippet: | + add_header X-Robots-Tag "noindex, nofollow"; + nginx.ingress.kubernetes.io/ssl-redirect: "true" + creationTimestamp: null + labels: + app.kubernetes.io/instance: extra-long-name.a-really-long-name-that-should-truncate.www.example.com + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: custom-ingress + helm.sh/chart: custom-ingress-0.1.0 + lagoon.sh/autogenerated: "false" + lagoon.sh/buildType: branch + lagoon.sh/environment: environment-with-really-really-reall-3fdb + lagoon.sh/environmentType: development + lagoon.sh/project: example-project + lagoon.sh/service: extra-long-name.a-really-long-name-that-should-truncate.www.example.com + lagoon.sh/service-type: custom-ingress + name: extra-long-name-f6c8a +spec: + ingressClassName: nginx + rules: + - host: extra-long-name.a-really-long-name-that-should-truncate.www.example.com + http: + paths: + - backend: + service: + name: nginx + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - extra-long-name.a-really-long-name-that-should-truncate.www.example.com + secretName: extra-long-name-f6c8a-tls +status: + loadBalancer: {} From 88e651a7ede3f9070b23fb60b51b6bd3315efb96 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 25 Jul 2022 11:24:38 +1000 Subject: [PATCH 3/4] feat: add feature flag variable collector function and support for checking the ingress class flag +tests --- cmd/template_ingress_test.go | 46 ++++++++- internal/generator/buildvalues.go | 2 +- internal/generator/generator.go | 28 ++++++ internal/generator/generator_test.go | 97 +++++++++++++++++++ internal/generator/ingress.go | 10 +- internal/generator/ingress_test.go | 12 +-- .../test13-results/example.com.yaml | 51 ++++++++++ .../test13/docker-compose.yml | 20 ++++ .../template-ingress/test13/lagoon.yml | 10 ++ .../test14-results/example.com.yaml | 51 ++++++++++ .../test14/docker-compose.yml | 20 ++++ .../template-ingress/test14/lagoon.yml | 11 +++ 12 files changed, 345 insertions(+), 13 deletions(-) create mode 100644 internal/generator/generator_test.go create mode 100644 test-resources/template-ingress/test13-results/example.com.yaml create mode 100644 test-resources/template-ingress/test13/docker-compose.yml create mode 100644 test-resources/template-ingress/test13/lagoon.yml create mode 100644 test-resources/template-ingress/test14-results/example.com.yaml create mode 100644 test-resources/template-ingress/test14/docker-compose.yml create mode 100644 test-resources/template-ingress/test14/lagoon.yml diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index 0b8dd957..71cc6280 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -27,6 +27,7 @@ func TestTemplateRoutes(t *testing.T) { cacheNoCache string serviceID string secretPrefix string + ingressClass string projectVars string envVars string lagoonVersion string @@ -269,6 +270,45 @@ func TestTemplateRoutes(t *testing.T) { }, want: "../test-resources/template-ingress/test12-results", }, + { + name: "test13 ingress class from default flag", + 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"}]`, + envVars: `[]`, + secretPrefix: "fastly-api-", + ingressClass: "nginx", + lagoonYAML: "../test-resources/template-ingress/test13/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", + }, + want: "../test-resources/template-ingress/test13-results", + }, + { + name: "test14 ingress class from lagoon.yml", + 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"}]`, + envVars: `[]`, + secretPrefix: "fastly-api-", + lagoonYAML: "../test-resources/template-ingress/test14/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", + }, + want: "../test-resources/template-ingress/test14-results", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -337,6 +377,10 @@ func TestTemplateRoutes(t *testing.T) { if err != nil { t.Errorf("%v", err) } + err = os.Setenv("LAGOON_FEATURE_FLAG_DEFAULT_INGRESS_CLASS", tt.args.ingressClass) + if err != nil { + t.Errorf("%v", err) + } lagoonYml = tt.args.lagoonYAML templateValues = tt.args.valuesFilePath @@ -404,7 +448,7 @@ func TestTemplateRoutes(t *testing.T) { t.Errorf("resulting templates do not match") } t.Cleanup(func() { - helpers.UnsetEnvVars(nil) + helpers.UnsetEnvVars([]helpers.EnvironmentVariable{{Name: "LAGOON_FEATURE_FLAG_DEFAULT_INGRESS_CLASS"}}) }) }) } diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index 25e611c3..6350de47 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -48,7 +48,7 @@ type BuildValues struct { ServiceTypeOverrides *lagoon.EnvironmentVariable `json:"serviceTypeOverrides"` DBaaSEnvironmentTypeOverrides *lagoon.EnvironmentVariable `json:"dbaasEnvironmentTypeOverrides"` DBaaSFallbackSingle bool `json:"dbaasFallbackSingle"` - DefaultIngressClass string `json:"defaultIngressClass"` + IngressClass string `json:"ingressClass"` } type MonitoringConfig struct { diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 0ea11b97..cc333620 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -3,6 +3,7 @@ package generator import ( "encoding/json" "fmt" + "os" "strings" "github.com/uselagoon/build-deploy-tool/internal/helpers" @@ -169,6 +170,10 @@ func NewGenerator( // this will later be used to add `runtime|global` scope into the `lagoon-env` configmap lagoonEnvVars = lagoon.MergeVariables(mergedVariables, configVars) + // check the environment for INGRESS_CLASS flag, will be "" if there are none found + ingressClass := CheckFeatureFlag("INGRESS_CLASS", lagoonEnvVars, debug) + buildValues.IngressClass = ingressClass + // get any variables from the API here lagoonServiceTypes, _ := lagoon.GetLagoonVariable("LAGOON_SERVICE_TYPES", nil, lagoonEnvVars) buildValues.ServiceTypeOverrides = lagoonServiceTypes @@ -253,3 +258,26 @@ func collectBuildVariables(buildValues BuildValues) []lagoon.EnvironmentVariable vars = append(vars, lagoon.EnvironmentVariable{Name: "LAGOON_AUTOGENERATED_ROUTES", Value: strings.Join(buildValues.AutogeneratedRoutes, ","), Scope: "runtime"}) return vars } + +// GetEnv gets an environment variable +func CheckFeatureFlag(key string, envVariables []lagoon.EnvironmentVariable, debug bool) string { + // check for force value + if value, ok := os.LookupEnv(fmt.Sprintf("LAGOON_FEATURE_FLAG_FORCE_%s", key)); ok { + fmt.Println(fmt.Sprintf("Using forced flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_FORCE_%s", key))) + return value + } + // check lagoon environment variables + for _, lVar := range envVariables { + if strings.Contains(lVar.Name, fmt.Sprintf("LAGOON_FEATURE_FLAG_%s", key)) { + fmt.Println(fmt.Sprintf("Using flag value from Lagoon environment variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_%s", key))) + return lVar.Value + } + } + // return default + if value, ok := os.LookupEnv(fmt.Sprintf("LAGOON_FEATURE_FLAG_DEFAULT_%s", key)); ok { + fmt.Println(fmt.Sprintf("Using default flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_DEFAULT_%s", key))) + return value + } + // otherwise nothing + return "" +} diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go new file mode 100644 index 00000000..c0227a05 --- /dev/null +++ b/internal/generator/generator_test.go @@ -0,0 +1,97 @@ +package generator + +import ( + "os" + "testing" + + "github.com/uselagoon/build-deploy-tool/internal/helpers" + "github.com/uselagoon/build-deploy-tool/internal/lagoon" +) + +func TestCheckFeatureFlag(t *testing.T) { + type args struct { + key string + envVariables []lagoon.EnvironmentVariable + debug bool + } + tests := []struct { + name string + vars []helpers.EnvironmentVariable + args args + want string + }{ + { + name: "test1 - rootless from default", + vars: []helpers.EnvironmentVariable{ + { + Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", + Value: "enabled", + }, + }, + args: args{ + key: "ROOTLESS_WORKLOAD", + }, + want: "enabled", + }, + { + name: "test2 - rootless from variable", + vars: []helpers.EnvironmentVariable{ + { + Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", + Value: "enabled", + }, + }, + args: args{ + key: "ROOTLESS_WORKLOAD", + envVariables: []lagoon.EnvironmentVariable{ + { + Name: "LAGOON_FEATURE_FLAG_ROOTLESS_WORKLOAD", + Value: "disabled", + Scope: "build", + }, + }, + }, + want: "disabled", + }, + { + name: "test2 - rootless from forced", + vars: []helpers.EnvironmentVariable{ + { + Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", + Value: "disabled", + }, + { + Name: "LAGOON_FEATURE_FLAG_FORCE_ROOTLESS_WORKLOAD", + Value: "enabled", + }, + }, + args: args{ + key: "ROOTLESS_WORKLOAD", + envVariables: []lagoon.EnvironmentVariable{ + { + Name: "LAGOON_FEATURE_FLAG_ROOTLESS_WORKLOAD", + Value: "disabled", + Scope: "build", + }, + }, + }, + want: "enabled", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, envVar := range tt.vars { + err := os.Setenv(envVar.Name, envVar.Value) + if err != nil { + t.Errorf("%v", err) + } + } + if got := CheckFeatureFlag(tt.args.key, tt.args.envVariables, tt.args.debug); got != tt.want { + t.Errorf("CheckFeatureFlag() = %v, want %v", got, tt.want) + } + t.Cleanup(func() { + helpers.UnsetEnvVars(tt.vars) + }) + }) + } +} diff --git a/internal/generator/ingress.go b/internal/generator/ingress.go index c17673b9..220b3d06 100644 --- a/internal/generator/ingress.go +++ b/internal/generator/ingress.go @@ -165,7 +165,7 @@ func generateAutogenRoutes( if lagoonYAML.Routes.Autogenerate.Insecure != "" { insecure = lagoonYAML.Routes.Autogenerate.Insecure } - ingressClass := buildValues.DefaultIngressClass + ingressClass := buildValues.IngressClass if lagoonYAML.Routes.Autogenerate.IngressClass != "" { ingressClass = lagoonYAML.Routes.Autogenerate.IngressClass } @@ -253,7 +253,7 @@ func generateActiveStandbyRoutes( if lagoonYAML.ProductionRoutes.Active != nil { if lagoonYAML.ProductionRoutes.Active.Routes != nil { for _, routeMap := range lagoonYAML.ProductionRoutes.Active.Routes { - lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, true) + lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, true) } } } @@ -262,7 +262,7 @@ func generateActiveStandbyRoutes( if lagoonYAML.ProductionRoutes.Standby != nil { if lagoonYAML.ProductionRoutes.Standby.Routes != nil { for _, routeMap := range lagoonYAML.ProductionRoutes.Standby.Routes { - lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, true) + lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, true) } } } @@ -307,9 +307,9 @@ func generateAndMerge( // otherwise it just uses the default environment name for _, routeMap := range lagoonYAML.Environments[buildValues.Branch].Routes { - lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix, false) + lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, false) } // merge routes from the API on top of the routes from the `.lagoon.yml` - mainRoutes := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.DefaultIngressClass, buildValues.FastlyAPISecretPrefix) + mainRoutes := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix) return mainRoutes, nil } diff --git a/internal/generator/ingress_test.go b/internal/generator/ingress_test.go index 641ec4de..73619acb 100644 --- a/internal/generator/ingress_test.go +++ b/internal/generator/ingress_test.go @@ -224,8 +224,8 @@ func Test_generateAndMerge(t *testing.T) { name: "test3 - generate routes from lagoon yaml and merge ones from api onto them with ingress class", args: args{ buildValues: BuildValues{ - Branch: "main", - DefaultIngressClass: "nginx", + Branch: "main", + IngressClass: "nginx", }, lagoonYAML: lagoon.YAML{ Environments: lagoon.Environments{ @@ -380,7 +380,7 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { args: args{ buildValues: BuildValues{ IsActiveEnvironment: true, - DefaultIngressClass: "nginx", + IngressClass: "nginx", }, lagoonYAML: lagoon.YAML{ ProductionRoutes: &lagoon.ProductionRoutes{ @@ -423,7 +423,7 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { args: args{ buildValues: BuildValues{ IsActiveEnvironment: true, - DefaultIngressClass: "nginx", + IngressClass: "nginx", }, lagoonYAML: lagoon.YAML{ ProductionRoutes: &lagoon.ProductionRoutes{ @@ -613,7 +613,7 @@ func Test_generateAutogenRoutes(t *testing.T) { AutogeneratedRoutesTLSAcme: true, }, }, - DefaultIngressClass: "nginx", + IngressClass: "nginx", }, autogenRoutes: &lagoon.RoutesV2{}, }, @@ -672,7 +672,7 @@ func Test_generateAutogenRoutes(t *testing.T) { AutogeneratedRoutesTLSAcme: true, }, }, - DefaultIngressClass: "nginx", + IngressClass: "nginx", }, autogenRoutes: &lagoon.RoutesV2{}, }, diff --git a/test-resources/template-ingress/test13-results/example.com.yaml b/test-resources/template-ingress/test13-results/example.com.yaml new file mode 100644 index 00000000..d9e0eb15 --- /dev/null +++ b/test-resources/template-ingress/test13-results/example.com.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + acme.cert-manager.io/http01-ingress-class: nginx + fastly.amazee.io/watch: "false" + ingress.kubernetes.io/ssl-redirect: "true" + kubernetes.io/tls-acme: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + monitor.stakater.com/enabled: "true" + monitor.stakater.com/overridePath: / + nginx.ingress.kubernetes.io/ssl-redirect: "true" + uptimerobot.monitor.stakater.com/alert-contacts: alertcontact + uptimerobot.monitor.stakater.com/interval: "60" + uptimerobot.monitor.stakater.com/status-pages: statuspageid + creationTimestamp: null + labels: + app.kubernetes.io/instance: example.com + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: custom-ingress + dioscuri.amazee.io/migrate: "false" + helm.sh/chart: custom-ingress-0.1.0 + lagoon.sh/autogenerated: "false" + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: example.com + lagoon.sh/service-type: custom-ingress + name: example.com +spec: + ingressClassName: nginx + rules: + - host: example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - example.com + secretName: example.com-tls +status: + loadBalancer: {} diff --git a/test-resources/template-ingress/test13/docker-compose.yml b/test-resources/template-ingress/test13/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/template-ingress/test13/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/template-ingress/test13/lagoon.yml b/test-resources/template-ingress/test13/lagoon.yml new file mode 100644 index 00000000..739440a7 --- /dev/null +++ b/test-resources/template-ingress/test13/lagoon.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: ../test-resources/template-ingress/test13/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com diff --git a/test-resources/template-ingress/test14-results/example.com.yaml b/test-resources/template-ingress/test14-results/example.com.yaml new file mode 100644 index 00000000..3a2a7a42 --- /dev/null +++ b/test-resources/template-ingress/test14-results/example.com.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + acme.cert-manager.io/http01-ingress-class: custom-ingress + fastly.amazee.io/watch: "false" + ingress.kubernetes.io/ssl-redirect: "true" + kubernetes.io/tls-acme: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + monitor.stakater.com/enabled: "true" + monitor.stakater.com/overridePath: / + nginx.ingress.kubernetes.io/ssl-redirect: "true" + uptimerobot.monitor.stakater.com/alert-contacts: alertcontact + uptimerobot.monitor.stakater.com/interval: "60" + uptimerobot.monitor.stakater.com/status-pages: statuspageid + creationTimestamp: null + labels: + app.kubernetes.io/instance: example.com + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: custom-ingress + dioscuri.amazee.io/migrate: "false" + helm.sh/chart: custom-ingress-0.1.0 + lagoon.sh/autogenerated: "false" + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: example.com + lagoon.sh/service-type: custom-ingress + name: example.com +spec: + ingressClassName: custom-ingress + rules: + - host: example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - example.com + secretName: example.com-tls +status: + loadBalancer: {} diff --git a/test-resources/template-ingress/test14/docker-compose.yml b/test-resources/template-ingress/test14/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/template-ingress/test14/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/template-ingress/test14/lagoon.yml b/test-resources/template-ingress/test14/lagoon.yml new file mode 100644 index 00000000..cd57b8ab --- /dev/null +++ b/test-resources/template-ingress/test14/lagoon.yml @@ -0,0 +1,11 @@ +docker-compose-yaml: ../test-resources/template-ingress/test14/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com: + ingressClass: "custom-ingress" From f175a1a2e0b368da713385140361c40e3a9a2a04 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 25 Jul 2022 15:55:34 +1000 Subject: [PATCH 4/4] chore: add test for environment variable flag override of ingress class --- cmd/template_ingress_test.go | 45 +++++++++++++++- internal/generator/generator.go | 12 +++-- .../test15-results/example.com.yaml | 51 +++++++++++++++++++ .../test15/docker-compose.yml | 20 ++++++++ .../template-ingress/test15/lagoon.yml | 10 ++++ 5 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 test-resources/template-ingress/test15-results/example.com.yaml create mode 100644 test-resources/template-ingress/test15/docker-compose.yml create mode 100644 test-resources/template-ingress/test15/lagoon.yml diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index 71cc6280..fa88bb63 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -291,7 +291,7 @@ func TestTemplateRoutes(t *testing.T) { want: "../test-resources/template-ingress/test13-results", }, { - name: "test14 ingress class from lagoon.yml", + name: "test14 ingress class from lagoon.yml should overwrite default and featureflag variable", args: args{ alertContact: "alertcontact", statusPageID: "statuspageid", @@ -301,7 +301,8 @@ func TestTemplateRoutes(t *testing.T) { buildType: "branch", lagoonVersion: "v2.7.x", branch: "main", - projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, + ingressClass: "nginx", + projectVars: `[{"name":"LAGOON_FEATURE_FLAG_INGRESS_CLASS","value":"nginx","scope":"build"},{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, envVars: `[]`, secretPrefix: "fastly-api-", lagoonYAML: "../test-resources/template-ingress/test14/lagoon.yml", @@ -309,6 +310,46 @@ func TestTemplateRoutes(t *testing.T) { }, want: "../test-resources/template-ingress/test14-results", }, + { + name: "test15a ingress class from lagoon api project scope", + args: args{ + alertContact: "alertcontact", + statusPageID: "statuspageid", + projectName: "example-project", + environmentName: "main", + environmentType: "production", + buildType: "branch", + lagoonVersion: "v2.7.x", + branch: "main", + ingressClass: "nginx", + projectVars: `[{"name":"LAGOON_FEATURE_FLAG_INGRESS_CLASS","value":"custom-ingress","scope":"build"},{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, + envVars: `[]`, + secretPrefix: "fastly-api-", + lagoonYAML: "../test-resources/template-ingress/test15/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", + }, + want: "../test-resources/template-ingress/test15-results", + }, + { + name: "test15b ingress class from lagoon api environment scope", + args: args{ + alertContact: "alertcontact", + statusPageID: "statuspageid", + projectName: "example-project", + environmentName: "main", + environmentType: "production", + buildType: "branch", + lagoonVersion: "v2.7.x", + branch: "main", + ingressClass: "nginx", + projectVars: `[{"name":"LAGOON_FEATURE_FLAG_INGRESS_CLASS","value":"project-custom-ingress","scope":"build"},{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, + envVars: `[{"name":"LAGOON_FEATURE_FLAG_INGRESS_CLASS","value":"custom-ingress","scope":"build"}]`, + secretPrefix: "fastly-api-", + lagoonYAML: "../test-resources/template-ingress/test15/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", + }, + want: "../test-resources/template-ingress/test15-results", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/generator/generator.go b/internal/generator/generator.go index cc333620..6348b562 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -263,19 +263,25 @@ func collectBuildVariables(buildValues BuildValues) []lagoon.EnvironmentVariable func CheckFeatureFlag(key string, envVariables []lagoon.EnvironmentVariable, debug bool) string { // check for force value if value, ok := os.LookupEnv(fmt.Sprintf("LAGOON_FEATURE_FLAG_FORCE_%s", key)); ok { - fmt.Println(fmt.Sprintf("Using forced flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_FORCE_%s", key))) + if debug { + fmt.Println(fmt.Sprintf("Using forced flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_FORCE_%s", key))) + } return value } // check lagoon environment variables for _, lVar := range envVariables { if strings.Contains(lVar.Name, fmt.Sprintf("LAGOON_FEATURE_FLAG_%s", key)) { - fmt.Println(fmt.Sprintf("Using flag value from Lagoon environment variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_%s", key))) + if debug { + fmt.Println(fmt.Sprintf("Using flag value from Lagoon environment variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_%s", key))) + } return lVar.Value } } // return default if value, ok := os.LookupEnv(fmt.Sprintf("LAGOON_FEATURE_FLAG_DEFAULT_%s", key)); ok { - fmt.Println(fmt.Sprintf("Using default flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_DEFAULT_%s", key))) + if debug { + fmt.Println(fmt.Sprintf("Using default flag value from build variable %s", fmt.Sprintf("LAGOON_FEATURE_FLAG_DEFAULT_%s", key))) + } return value } // otherwise nothing diff --git a/test-resources/template-ingress/test15-results/example.com.yaml b/test-resources/template-ingress/test15-results/example.com.yaml new file mode 100644 index 00000000..3a2a7a42 --- /dev/null +++ b/test-resources/template-ingress/test15-results/example.com.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + acme.cert-manager.io/http01-ingress-class: custom-ingress + fastly.amazee.io/watch: "false" + ingress.kubernetes.io/ssl-redirect: "true" + kubernetes.io/tls-acme: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + monitor.stakater.com/enabled: "true" + monitor.stakater.com/overridePath: / + nginx.ingress.kubernetes.io/ssl-redirect: "true" + uptimerobot.monitor.stakater.com/alert-contacts: alertcontact + uptimerobot.monitor.stakater.com/interval: "60" + uptimerobot.monitor.stakater.com/status-pages: statuspageid + creationTimestamp: null + labels: + app.kubernetes.io/instance: example.com + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: custom-ingress + dioscuri.amazee.io/migrate: "false" + helm.sh/chart: custom-ingress-0.1.0 + lagoon.sh/autogenerated: "false" + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: example.com + lagoon.sh/service-type: custom-ingress + name: example.com +spec: + ingressClassName: custom-ingress + rules: + - host: example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - example.com + secretName: example.com-tls +status: + loadBalancer: {} diff --git a/test-resources/template-ingress/test15/docker-compose.yml b/test-resources/template-ingress/test15/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/template-ingress/test15/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/template-ingress/test15/lagoon.yml b/test-resources/template-ingress/test15/lagoon.yml new file mode 100644 index 00000000..96757f31 --- /dev/null +++ b/test-resources/template-ingress/test15/lagoon.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: ../test-resources/template-ingress/test15/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com