From 7ce41d075f35b98031aa344049e1fc019f4bf0f3 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 17 May 2022 11:41:08 +1000 Subject: [PATCH 1/9] feat: add alternative names to lagoonyml --- cmd/template_ingress_test.go | 20 ++++++ .../template-ingress/altnames-lagoon.yml | 13 ++++ .../test11-results/example.com.yaml | 71 +++++++++++++++++++ internal/lagoon/routes.go | 31 ++++++-- internal/lagoon/routes_test.go | 19 +++-- 5 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 cmd/test-resources/template-ingress/altnames-lagoon.yml create mode 100644 cmd/test-resources/template-ingress/test11-results/example.com.yaml diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index 1a4ead8c..dd510327 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -229,6 +229,26 @@ func TestTemplateRoutes(t *testing.T) { }, want: "test-resources/template-ingress/test10-results", }, + { + name: "test11 alternative names", + args: args{ + alertContact: "alertcontact", + statusPageID: "statuspageid", + projectName: "example-project", + environmentName: "main", + environmentType: "production", + buildType: "branch", + standbyEnvironment: "main2", + lagoonVersion: "v2.7.x", + branch: "main", + projectVars: `[]`, + envVars: `[]`, + secretPrefix: "fastly-api-", + lagoonYAML: "test-resources/template-ingress/altnames-lagoon.yml", + templatePath: "test-resources/template-ingress/output", + }, + want: "test-resources/template-ingress/test11-results", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cmd/test-resources/template-ingress/altnames-lagoon.yml b/cmd/test-resources/template-ingress/altnames-lagoon.yml new file mode 100644 index 00000000..c45368ef --- /dev/null +++ b/cmd/test-resources/template-ingress/altnames-lagoon.yml @@ -0,0 +1,13 @@ +docker-compose-yaml: test-resources/template-ingress/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com: + alternativenames: + - www.example.com + - en.example.com diff --git a/cmd/test-resources/template-ingress/test11-results/example.com.yaml b/cmd/test-resources/template-ingress/test11-results/example.com.yaml new file mode 100644 index 00000000..0e18d98c --- /dev/null +++ b/cmd/test-resources/template-ingress/test11-results/example.com.yaml @@ -0,0 +1,71 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + 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: + rules: + - host: example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + - host: www.example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + - host: en.example.com + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - example.com + - www.example.com + - en.example.com + secretName: example.com-tls +status: + loadBalancer: {} diff --git a/internal/lagoon/routes.go b/internal/lagoon/routes.go index c00b55e6..9613b863 100644 --- a/internal/lagoon/routes.go +++ b/internal/lagoon/routes.go @@ -32,12 +32,13 @@ type RouteV2 struct { // Ingress represents a Lagoon route. type Ingress struct { - TLSAcme *bool `json:"tls-acme,omitempty"` - Migrate *bool `json:"migrate,omitempty"` - Insecure *string `json:"insecure,omitempty"` - MonitoringPath string `json:"monitoring-path,omitempty"` - Fastly Fastly `json:"fastly,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` + TLSAcme *bool `json:"tls-acme,omitempty"` + Migrate *bool `json:"migrate,omitempty"` + Insecure *string `json:"insecure,omitempty"` + MonitoringPath string `json:"monitoring-path,omitempty"` + Fastly Fastly `json:"fastly,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` + AlternativeNames []string `json:"alternativenames,omitempty"` } // Route can be either a string or a map[string]Ingress, so we must @@ -94,6 +95,7 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable newRoute.Annotations = map[string]string{} newRoute.Fastly.ServiceID = "" newRoute.Fastly.Watch = false + newRoute.AlternativeNames = []string{} if activeStandby { newRoute.Migrate = helpers.BoolPtr(true) } @@ -113,6 +115,9 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable if ingress.Insecure != nil { newRoute.Insecure = ingress.Insecure } + if ingress.AlternativeNames != nil { + newRoute.AlternativeNames = ingress.AlternativeNames + } } } else { // this route is just a domain @@ -159,12 +164,21 @@ func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []Environme } else { add.Annotations = map[string]string{} } + if aRoute.AlternativeNames != nil { + add.AlternativeNames = aRoute.AlternativeNames + } else { + add.AlternativeNames = []string{} + } } } if existsInAPI { finalRoutes.Routes = append(finalRoutes.Routes, add) existsInAPI = false } else { + + if route.AlternativeNames == nil { + route.AlternativeNames = []string{} + } finalRoutes.Routes = append(finalRoutes.Routes, route) } } @@ -189,6 +203,11 @@ func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []Environme } else { add.Annotations = map[string]string{} } + if aRoute.AlternativeNames != nil { + add.AlternativeNames = aRoute.AlternativeNames + } else { + add.AlternativeNames = []string{} + } if aRoute.Domain == route.Domain { existsInAPI = true } diff --git a/internal/lagoon/routes_test.go b/internal/lagoon/routes_test.go index 91a21fdc..987de9b3 100644 --- a/internal/lagoon/routes_test.go +++ b/internal/lagoon/routes_test.go @@ -51,6 +51,7 @@ func TestGenerateRouteStructure(t *testing.T) { Fastly: Fastly{ Watch: false, }, + AlternativeNames: []string{}, }, { Domain: "www.example.com", @@ -62,6 +63,7 @@ func TestGenerateRouteStructure(t *testing.T) { Fastly: Fastly{ Watch: false, }, + AlternativeNames: []string{}, }, }, }, @@ -103,6 +105,7 @@ func TestGenerateRouteStructure(t *testing.T) { Fastly: Fastly{ Watch: false, }, + AlternativeNames: []string{}, }, { Domain: "www.example.com", @@ -116,6 +119,7 @@ func TestGenerateRouteStructure(t *testing.T) { Watch: true, ServiceID: "12345", }, + AlternativeNames: []string{}, }, }, }, @@ -211,6 +215,7 @@ func TestMergeRouteStructures(t *testing.T) { ServiceID: "12345", APISecretName: "fastly-api-annotationscom", }, + AlternativeNames: []string{}, }, { Domain: "www.example.com", @@ -221,14 +226,16 @@ func TestMergeRouteStructures(t *testing.T) { Annotations: map[string]string{ "nginx": "nginx", }, + AlternativeNames: []string{}, }, { - Domain: "another.example.com", - Service: "nginx", - MonitoringPath: "/", - Insecure: helpers.StrPtr("Redirect"), - TLSAcme: helpers.BoolPtr(true), - Annotations: map[string]string{}, + Domain: "another.example.com", + Service: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + AlternativeNames: []string{}, }, }, }, From 521e309efb00def3e4c38650593f380f41a52e60 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 17 May 2022 14:07:26 +1000 Subject: [PATCH 2/9] test: add altname test case --- internal/lagoon/routes_test.go | 56 +++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/internal/lagoon/routes_test.go b/internal/lagoon/routes_test.go index 987de9b3..d645d660 100644 --- a/internal/lagoon/routes_test.go +++ b/internal/lagoon/routes_test.go @@ -12,7 +12,7 @@ import ( func TestGenerateRouteStructure(t *testing.T) { type args struct { genRoutes *RoutesV2 - routeMap map[string][]Route + yamlRouteMap map[string][]Route variables []EnvironmentVariable secretPrefix string activeStandby bool @@ -26,7 +26,7 @@ func TestGenerateRouteStructure(t *testing.T) { name: "test1", args: args{ genRoutes: &RoutesV2{}, - routeMap: map[string][]Route{ + yamlRouteMap: map[string][]Route{ "nginx": { { Name: "example.com", @@ -72,7 +72,7 @@ func TestGenerateRouteStructure(t *testing.T) { name: "test2", args: args{ genRoutes: &RoutesV2{}, - routeMap: map[string][]Route{ + yamlRouteMap: map[string][]Route{ "nginx": { { Name: "example.com", @@ -124,10 +124,58 @@ func TestGenerateRouteStructure(t *testing.T) { }, }, }, + { + name: "test3", + args: args{ + genRoutes: &RoutesV2{}, + yamlRouteMap: map[string][]Route{ + "nginx": { + { + Ingresses: map[string]Ingress{ + "example.com": { + Fastly: Fastly{ + APISecretName: "annotationscom", + Watch: true, + ServiceID: "12345", + }, + AlternativeNames: []string{ + "www.example.com", + "en.example.com", + }, + }, + }, + }, + }, + }, + secretPrefix: "fastly-api-", + activeStandby: false, + }, + want: &RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + Service: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Fastly: Fastly{ + APISecretName: "fastly-api-annotationscom", + Watch: true, + ServiceID: "12345", + }, + AlternativeNames: []string{ + "www.example.com", + "en.example.com", + }, + }, + }, + }, + }, } 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.yamlRouteMap, tt.args.variables, 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) From fc6e43be5239d43f45dfe1fb5aa57be1a64c2b35 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 23 May 2022 15:39:31 +1000 Subject: [PATCH 3/9] test: fix test to have required variables --- cmd/template_ingress_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index b480c283..1b0a8afa 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -241,7 +241,7 @@ func TestTemplateRoutes(t *testing.T) { standbyEnvironment: "main2", lagoonVersion: "v2.7.x", branch: "main", - projectVars: `[]`, + projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, envVars: `[]`, secretPrefix: "fastly-api-", lagoonYAML: "test-resources/template-ingress/altnames-lagoon.yml", From 1355cd0a8145a215fc65f5f75aea702e5ac0a22d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 17 Jun 2022 09:07:38 +1000 Subject: [PATCH 4/9] test: fix up test cases --- cmd/template_ingress_test.go | 10 +++++----- .../template-ingress/test11/lagoon.yml | 2 +- .../test12-results}/example.com.yaml | 0 .../test12/docker-compose.yml | 20 +++++++++++++++++++ .../template-ingress/test12/lagoon.yml | 2 +- 5 files changed, 27 insertions(+), 7 deletions(-) rename {cmd/test-resources/template-ingress/test11-results => test-resources/template-ingress/test12-results}/example.com.yaml (100%) create mode 100644 test-resources/template-ingress/test12/docker-compose.yml rename cmd/test-resources/template-ingress/altnames-lagoon.yml => test-resources/template-ingress/test12/lagoon.yml (72%) diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index 73ce7745..2fde7493 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -230,7 +230,7 @@ func TestTemplateRoutes(t *testing.T) { want: "../test-resources/template-ingress/test10-results", }, { - name: "test10 standby no values", + name: "test11 standby no values", args: args{ alertContact: "alertcontact", statusPageID: "statuspageid", @@ -249,7 +249,7 @@ func TestTemplateRoutes(t *testing.T) { want: "../test-resources/template-ingress/test11-results", }, { - name: "test11 alternative names", + name: "test12 alternative names", args: args{ alertContact: "alertcontact", statusPageID: "statuspageid", @@ -263,10 +263,10 @@ func TestTemplateRoutes(t *testing.T) { projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"}]`, envVars: `[]`, secretPrefix: "fastly-api-", - lagoonYAML: "test-resources/template-ingress/altnames-lagoon.yml", - templatePath: "test-resources/template-ingress/output", + lagoonYAML: "../test-resources/template-ingress/test12/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", }, - want: "test-resources/template-ingress/test11-results", + want: "../test-resources/template-ingress/test12-results", }, } for _, tt := range tests { diff --git a/test-resources/template-ingress/test11/lagoon.yml b/test-resources/template-ingress/test11/lagoon.yml index 31b68477..15cb9340 100644 --- a/test-resources/template-ingress/test11/lagoon.yml +++ b/test-resources/template-ingress/test11/lagoon.yml @@ -1,5 +1,5 @@ --- -docker-compose-yaml: ../test-resources/template-autogenerated/test20/docker-compose.yml +docker-compose-yaml: ../test-resources/template-ingress/test11/docker-compose.yml project: content-example-com diff --git a/cmd/test-resources/template-ingress/test11-results/example.com.yaml b/test-resources/template-ingress/test12-results/example.com.yaml similarity index 100% rename from cmd/test-resources/template-ingress/test11-results/example.com.yaml rename to test-resources/template-ingress/test12-results/example.com.yaml diff --git a/test-resources/template-ingress/test12/docker-compose.yml b/test-resources/template-ingress/test12/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/template-ingress/test12/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/cmd/test-resources/template-ingress/altnames-lagoon.yml b/test-resources/template-ingress/test12/lagoon.yml similarity index 72% rename from cmd/test-resources/template-ingress/altnames-lagoon.yml rename to test-resources/template-ingress/test12/lagoon.yml index c45368ef..dcbd3f71 100644 --- a/cmd/test-resources/template-ingress/altnames-lagoon.yml +++ b/test-resources/template-ingress/test12/lagoon.yml @@ -1,4 +1,4 @@ -docker-compose-yaml: test-resources/template-ingress/docker-compose.yml +docker-compose-yaml: ../test-resources/template-ingress/test12/docker-compose.yml environment_variables: git_sha: "true" From 479d5f5908b0e239c191c70e476df52af3b7482f Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Thu, 5 Jan 2023 14:28:23 +1100 Subject: [PATCH 5/9] fix: add primaryIngress label to test result --- test-resources/template-ingress/test21-results/example.com.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/test-resources/template-ingress/test21-results/example.com.yaml b/test-resources/template-ingress/test21-results/example.com.yaml index 0e18d98c..e143e7f9 100644 --- a/test-resources/template-ingress/test21-results/example.com.yaml +++ b/test-resources/template-ingress/test21-results/example.com.yaml @@ -25,6 +25,7 @@ metadata: lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production + lagoon.sh/primaryIngress: "true" lagoon.sh/project: example-project lagoon.sh/service: example.com lagoon.sh/service-type: custom-ingress From 4e3af15d400fe0d0811b9221fb59617c415f085a Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 May 2023 20:01:34 +1000 Subject: [PATCH 6/9] chore: revert openssh --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0ddbd887..cd33c08b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,7 +71,7 @@ ENV KUBECTL_VERSION=v1.20.4 \ RUN apk add -U --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing aufs-util \ && apk add --update openssl curl jq parallel \ - && apk add --no-cache bash git openssh-client-common=9.1_p1-r2 openssh=9.1_p1-r2 py-pip skopeo \ + && apk add --no-cache bash git openssh py-pip skopeo \ && git config --global user.email "lagoon@lagoon.io" && git config --global user.name lagoon \ && pip install shyaml yq \ && curl -Lo /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ From dbc191c021bfc4e0d94e72f61077db6f8e8d4cce Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 May 2023 21:20:42 +1000 Subject: [PATCH 7/9] chore: revert openssh --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cd33c08b..9fee2f8a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,7 +71,7 @@ ENV KUBECTL_VERSION=v1.20.4 \ RUN apk add -U --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing aufs-util \ && apk add --update openssl curl jq parallel \ - && apk add --no-cache bash git openssh py-pip skopeo \ + && apk add --no-cache bash git openssh-client-common=9.1_p1-r3 openssh=9.1_p1-r3 py-pip skopeo \ && git config --global user.email "lagoon@lagoon.io" && git config --global user.name lagoon \ && pip install shyaml yq \ && curl -Lo /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ From a38b8ed9714aa31a74fc165ed26f05d4b3f226ef Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Tue, 30 May 2023 13:00:45 +1000 Subject: [PATCH 8/9] feat: support wildcard ingress, handle route errors earlier --- cmd/template_ingress_test.go | 18 ++ internal/generator/ingress.go | 29 +- internal/generator/ingress_test.go | 178 ++++++++++- internal/lagoon/routes.go | 255 +++++++++------- internal/lagoon/routes_test.go | 289 ++++++++++++++++-- .../templating/ingress/templates_ingress.go | 45 ++- .../ingress/templates_ingress_test.go | 50 +-- .../result-wildcard-ingress1.yaml | 48 +++ .../result-wildcard-ingress2.yaml | 48 +++ .../test22-results/example.com.yaml | 46 +++ .../test22/docker-compose.yml | 20 ++ .../template-ingress/test22/lagoon.yml | 12 + 12 files changed, 851 insertions(+), 187 deletions(-) create mode 100644 internal/templating/ingress/test-resources/result-wildcard-ingress1.yaml create mode 100644 internal/templating/ingress/test-resources/result-wildcard-ingress2.yaml create mode 100644 test-resources/template-ingress/test22-results/example.com.yaml create mode 100644 test-resources/template-ingress/test22/docker-compose.yml create mode 100644 test-resources/template-ingress/test22/lagoon.yml diff --git a/cmd/template_ingress_test.go b/cmd/template_ingress_test.go index 505add1e..20a44562 100644 --- a/cmd/template_ingress_test.go +++ b/cmd/template_ingress_test.go @@ -452,6 +452,24 @@ func TestTemplateRoutes(t *testing.T) { }, want: "../test-resources/template-ingress/test21-results", }, + { + name: "test22 check wildcard", + 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: `[]`, + lagoonYAML: "../test-resources/template-ingress/test22/lagoon.yml", + templatePath: "../test-resources/template-ingress/output", + }, + want: "../test-resources/template-ingress/test22-results", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/generator/ingress.go b/internal/generator/ingress.go index 2f8715f8..c942349a 100644 --- a/internal/generator/ingress.go +++ b/internal/generator/ingress.go @@ -76,7 +76,10 @@ func generateRoutes( // generate the templates for these independently of any previously generated routes, // this WILL overwrite previously created templates ensuring that anything defined in the `production_routes` // section are created correctly ensuring active/standby will work - *activeStanbyRoutes = generateActiveStandbyRoutes(lagoonEnvVars, lYAML, buildValues) + *activeStanbyRoutes, err = generateActiveStandbyRoutes(lagoonEnvVars, lYAML, buildValues) + if err != nil { + return "", []string{}, []string{}, fmt.Errorf("couldn't generate and merge routes: %v", err) + } // get the first route from the list of routes, replace the previous one if necessary if len(activeStanbyRoutes.Routes) > 0 { // if primary != "" { @@ -244,14 +247,17 @@ func generateActiveStandbyRoutes( envVars []lagoon.EnvironmentVariable, lagoonYAML lagoon.YAML, buildValues BuildValues, -) lagoon.RoutesV2 { +) (lagoon.RoutesV2, error) { activeStanbyRoutes := &lagoon.RoutesV2{} if lagoonYAML.ProductionRoutes != nil { if buildValues.IsActiveEnvironment == true { if lagoonYAML.ProductionRoutes.Active != nil { if lagoonYAML.ProductionRoutes.Active.Routes != nil { for _, routeMap := range lagoonYAML.ProductionRoutes.Active.Routes { - lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, true) + err := lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, true) + if err != nil { + return *activeStanbyRoutes, err + } } } } @@ -260,13 +266,16 @@ 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.IngressClass, buildValues.FastlyAPISecretPrefix, true) + err := lagoon.GenerateRoutesV2(activeStanbyRoutes, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, true) + if err != nil { + return *activeStanbyRoutes, err + } } } } } } - return *activeStanbyRoutes + return *activeStanbyRoutes, nil } // getRoutesFromEnvVar will collect the value of the LAGOON_ROUTES_JSON @@ -305,9 +314,15 @@ func generateAndMerge( // otherwise it just uses the default environment name for _, routeMap := range lagoonYAML.Environments[buildValues.Branch].Routes { - lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, false) + err := lagoon.GenerateRoutesV2(n, routeMap, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix, false) + if err != nil { + return *n, err + } } // merge routes from the API on top of the routes from the `.lagoon.yml` - mainRoutes := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix) + mainRoutes, err := lagoon.MergeRoutesV2(*n, api, envVars, buildValues.IngressClass, buildValues.FastlyAPISecretPrefix) + if err != nil { + return *n, err + } return mainRoutes, nil } diff --git a/internal/generator/ingress_test.go b/internal/generator/ingress_test.go index 69569230..225f085c 100644 --- a/internal/generator/ingress_test.go +++ b/internal/generator/ingress_test.go @@ -342,7 +342,7 @@ func Test_generateAndMerge(t *testing.T) { }, }, { - name: "test3 - generate routes from lagoon yaml and merge ones from api with hsts", + name: "test4 - generate routes from lagoon yaml and merge ones from api with hsts", args: args{ buildValues: BuildValues{ Branch: "main", @@ -397,6 +397,83 @@ func Test_generateAndMerge(t *testing.T) { }, }, }, + { + name: "test5 - wildcard with tls-acme false", + args: args{ + buildValues: BuildValues{ + Branch: "main", + IngressClass: "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(false), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "a.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + IngressClass: "nginx", + AlternativeNames: []string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + { + name: "test6 - wildcard with tls-acme true (should error)", + args: args{ + buildValues: BuildValues{ + Branch: "main", + IngressClass: "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), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantErr: true, + want: lagoon.RoutesV2{ + Routes: nil, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -407,7 +484,7 @@ func Test_generateAndMerge(t *testing.T) { } lValues, _ := json.Marshal(got) wValues, _ := json.Marshal(tt.want) - if !reflect.DeepEqual(string(lValues), string(wValues)) { + if !reflect.DeepEqual(string(lValues), string(wValues)) && !tt.wantErr { t.Errorf("generateAndMerge() = %v, want %v", string(lValues), string(wValues)) } }) @@ -421,9 +498,10 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { buildValues BuildValues } tests := []struct { - name string - args args - want lagoon.RoutesV2 + name string + args args + want lagoon.RoutesV2 + wantErr bool }{ { name: "test1", @@ -508,7 +586,7 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { }, }, { - name: "test2 - with custom ingress class defined", + name: "test3 - with custom ingress class defined", args: args{ buildValues: BuildValues{ IsActiveEnvironment: true, @@ -552,13 +630,97 @@ func Test_generateActiveStandbyRoutes(t *testing.T) { }, }, }, + { + name: "test4 - with wildcard and tls-acme true (should error)", + args: args{ + buildValues: BuildValues{ + IngressClass: "nginx", + IsActiveEnvironment: true, + }, + 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), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + }, + envVars: []lagoon.EnvironmentVariable{}, + }, + wantErr: true, + want: lagoon.RoutesV2{ + Routes: nil, + }, + }, + { + name: "test5 - with wildcard and tls-acme false", + args: args{ + buildValues: BuildValues{ + IngressClass: "nginx", + IsActiveEnvironment: true, + }, + 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(false), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + }, + }, + }, + }, + envVars: []lagoon.EnvironmentVariable{}, + }, + want: lagoon.RoutesV2{ + Routes: []lagoon.RouteV2{ + { + Domain: "active.example.com", + LagoonService: "nginx", + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + Migrate: helpers.BoolPtr(true), + Insecure: helpers.StrPtr("Redirect"), + MonitoringPath: "/", + IngressClass: "nginx", + AlternativeNames: []string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := generateActiveStandbyRoutes(tt.args.envVars, tt.args.lagoonYAML, tt.args.buildValues) + got, err := generateActiveStandbyRoutes(tt.args.envVars, tt.args.lagoonYAML, tt.args.buildValues) + if (err != nil) != tt.wantErr { + t.Errorf("generateAndMerge() error = %v, wantErr %v", err, tt.wantErr) + return + } lValues, _ := json.Marshal(got) wValues, _ := json.Marshal(tt.want) - if !reflect.DeepEqual(string(lValues), string(wValues)) { + if !reflect.DeepEqual(string(lValues), string(wValues)) && !tt.wantErr { t.Errorf("generateAndMerge() = %v, want %v", string(lValues), string(wValues)) } }) diff --git a/internal/lagoon/routes.go b/internal/lagoon/routes.go index f21ab138..c4302672 100644 --- a/internal/lagoon/routes.go +++ b/internal/lagoon/routes.go @@ -2,10 +2,13 @@ package lagoon import ( "encoding/json" + "fmt" "reflect" "strconv" + "strings" "github.com/uselagoon/build-deploy-tool/internal/helpers" + "k8s.io/apimachinery/pkg/util/validation" ) // RoutesV2 is the new routes definition @@ -35,6 +38,7 @@ type RouteV2 struct { HSTSIncludeSubdomains *bool `json:"hstsIncludeSubdomains,omitempty"` HSTSPreload *bool `json:"hstsPreload,omitempty"` Autogenerated bool `json:"-"` + Wildcard *bool `json:"wildcard,omitempty"` } // Ingress represents a Lagoon route. @@ -51,6 +55,7 @@ type Ingress struct { HSTSIncludeSubdomains *bool `json:"hstsIncludeSubdomains,omitempty"` HSTSPreload *bool `json:"hstsPreload,omitempty"` AlternativeNames []string `json:"alternativenames,omitempty"` + Wildcard *bool `json:"wildcard,omitempty"` } // Route can be either a string or a map[string]Ingress, so we must @@ -60,7 +65,17 @@ type Route struct { Ingresses map[string]Ingress } -var defaultHSTSMaxAge = 31536000 +// defaults +var ( + defaultHSTSMaxAge = 31536000 + defaultMonitoringPath string = "/" + defaultFastlyService string = "" + defaultFastlyWatch bool = false + defaultInsecure *string = helpers.StrPtr("Redirect") + defaultTLSAcme *bool = helpers.BoolPtr(true) + defaultActiveStandby *bool = helpers.BoolPtr(true) + defaultAnnotations map[string]string = map[string]string{} +) // UnmarshalJSON implements json.Unmarshaler. func (r *Route) UnmarshalJSON(data []byte) error { @@ -99,21 +114,21 @@ 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, defaultIngressClass, secretPrefix string, activeStandby bool) { +func GenerateRoutesV2(yamlRoutes *RoutesV2, routeMap map[string][]Route, variables []EnvironmentVariable, defaultIngressClass, secretPrefix string, activeStandby bool) error { for rName, lagoonRoutes := range routeMap { for _, lagoonRoute := range lagoonRoutes { newRoute := RouteV2{} // set the defaults for routes - newRoute.TLSAcme = helpers.BoolPtr(true) - newRoute.Insecure = helpers.StrPtr("Redirect") - newRoute.MonitoringPath = "/" - newRoute.Annotations = map[string]string{} - newRoute.Fastly.ServiceID = "" - newRoute.Fastly.Watch = false + newRoute.TLSAcme = defaultTLSAcme + newRoute.Insecure = defaultInsecure + newRoute.MonitoringPath = defaultMonitoringPath + newRoute.Annotations = defaultAnnotations + newRoute.Fastly.ServiceID = defaultFastlyService + newRoute.Fastly.Watch = defaultFastlyWatch newRoute.AlternativeNames = []string{} newRoute.IngressClass = defaultIngressClass if activeStandby { - newRoute.Migrate = helpers.BoolPtr(true) + newRoute.Migrate = defaultActiveStandby } if lagoonRoute.Name == "" { // this route from the lagoon route map contains field overrides @@ -160,6 +175,17 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable } } // hsts end + + // handle wildcards + if ingress.Wildcard != nil { + newRoute.Wildcard = ingress.Wildcard + if *newRoute.TLSAcme == true && *newRoute.Wildcard == true { + return fmt.Errorf("Route %s has wildcard: true and tls-acme: true, this is not supported", newRoute.Domain) + } + if ingress.AlternativeNames != nil && *newRoute.Wildcard == true { + return fmt.Errorf("Route %s has wildcard: true and alternativenames defined, this is not supported", newRoute.Domain) + } + } } } else { // this route is just a domain @@ -173,149 +199,150 @@ func GenerateRoutesV2(genRoutes *RoutesV2, routeMap map[string][]Route, variable //@TODO: error handling } - genRoutes.Routes = append(genRoutes.Routes, newRoute) + // validate the domain earlier and fail if it is invalid + if err := validation.IsDNS1123Subdomain(strings.ToLower(newRoute.Domain)); err != nil { + return fmt.Errorf("Route %s in .lagoon.yml is not valid: %v", newRoute.Domain, err) + } + yamlRoutes.Routes = append(yamlRoutes.Routes, newRoute) } } + return nil } // MergeRoutesV2 merge routes from the API onto the previously generated routes. -func MergeRoutesV2(genRoutes RoutesV2, apiRoutes RoutesV2, variables []EnvironmentVariable, defaultIngressClass, secretPrefix string) RoutesV2 { - finalRoutes := RoutesV2{} +func MergeRoutesV2(yamlRoutes RoutesV2, apiRoutes RoutesV2, variables []EnvironmentVariable, defaultIngressClass, secretPrefix string) (RoutesV2, error) { + firstRoundRoutes := RoutesV2{} existsInAPI := false // replace any routes from the lagoon yaml with ones from the api // this only modifies ones that exist in lagoon yaml - for _, route := range genRoutes.Routes { - add := RouteV2{} - for _, aRoute := range apiRoutes.Routes { - if aRoute.Domain == route.Domain { - existsInAPI = true - add = aRoute - add.Fastly = aRoute.Fastly - if aRoute.TLSAcme != nil { - add.TLSAcme = aRoute.TLSAcme - } else { - add.TLSAcme = helpers.BoolPtr(true) - } - if aRoute.Insecure != nil { - add.Insecure = aRoute.Insecure - } else { - add.Insecure = helpers.StrPtr("Redirect") - } - if aRoute.Annotations != nil { - add.Annotations = aRoute.Annotations - } else { - add.Annotations = map[string]string{} - } - if aRoute.AlternativeNames != nil { - add.AlternativeNames = aRoute.AlternativeNames - } else { - add.AlternativeNames = []string{} - } - if aRoute.IngressClass != "" { - add.IngressClass = aRoute.IngressClass - } else { - add.IngressClass = defaultIngressClass - } - - // handle hsts here - if aRoute.HSTSEnabled != nil { - add.HSTSEnabled = aRoute.HSTSEnabled - } - if aRoute.HSTSIncludeSubdomains != nil { - add.HSTSIncludeSubdomains = aRoute.HSTSIncludeSubdomains - } - if aRoute.HSTSPreload != nil { - add.HSTSPreload = aRoute.HSTSPreload + for _, route := range yamlRoutes.Routes { + routeAdd := RouteV2{} + // validate the domain earlier and fail if it is invalid + if err := validation.IsDNS1123Subdomain(strings.ToLower(route.Domain)); err != nil { + return firstRoundRoutes, fmt.Errorf("Route %s in .lagoon.yml is not valid: %v", route.Domain, err) + } + for _, apiRoute := range apiRoutes.Routes { + if apiRoute.Domain == route.Domain { + // validate the domain earlier and fail if it is invalid + if err := validation.IsDNS1123Subdomain(strings.ToLower(apiRoute.Domain)); err != nil { + return firstRoundRoutes, fmt.Errorf("Route %s in API defined routes is not valid: %v", apiRoute.Domain, err) } - if aRoute.HSTSMaxAge > 0 { - add.HSTSMaxAge = aRoute.HSTSMaxAge - } else { - if add.HSTSEnabled != nil && *add.HSTSEnabled { - add.HSTSMaxAge = defaultHSTSMaxAge // set default hsts value if one not provided - } + existsInAPI = true + var err error + routeAdd, err = handleAPIRoute(defaultIngressClass, apiRoute) + if err != nil { + return firstRoundRoutes, err } - // hsts end } } if existsInAPI { - finalRoutes.Routes = append(finalRoutes.Routes, add) + firstRoundRoutes.Routes = append(firstRoundRoutes.Routes, routeAdd) existsInAPI = false } else { if route.AlternativeNames == nil { route.AlternativeNames = []string{} } - finalRoutes.Routes = append(finalRoutes.Routes, route) + firstRoundRoutes.Routes = append(firstRoundRoutes.Routes, route) } } // add any that exist in the api only to the final routes list - for _, aRoute := range apiRoutes.Routes { - add := aRoute - add.Fastly = aRoute.Fastly - if aRoute.TLSAcme != nil { - add.TLSAcme = aRoute.TLSAcme - } else { - add.TLSAcme = helpers.BoolPtr(true) - } - if aRoute.Insecure != nil { - add.Insecure = aRoute.Insecure - } else { - add.Insecure = helpers.StrPtr("Redirect") - } - if aRoute.Annotations != nil { - add.Annotations = aRoute.Annotations - } else { - add.Annotations = map[string]string{} - } - if aRoute.IngressClass != "" { - add.IngressClass = aRoute.IngressClass - } else { - add.IngressClass = defaultIngressClass + for _, apiRoute := range apiRoutes.Routes { + if err := validation.IsDNS1123Subdomain(strings.ToLower(apiRoute.Domain)); err != nil { + return firstRoundRoutes, fmt.Errorf("Route %s in API defined routes is not valid: %v", apiRoute.Domain, err) } - // handle hsts here - if aRoute.HSTSEnabled != nil { - add.HSTSEnabled = aRoute.HSTSEnabled - } - if aRoute.HSTSIncludeSubdomains != nil { - add.HSTSIncludeSubdomains = aRoute.HSTSIncludeSubdomains - } - if aRoute.HSTSPreload != nil { - add.HSTSPreload = aRoute.HSTSPreload - } - if aRoute.HSTSMaxAge > 0 { - add.HSTSMaxAge = aRoute.HSTSMaxAge - } else { - if add.HSTSEnabled != nil && *add.HSTSEnabled { - add.HSTSMaxAge = defaultHSTSMaxAge // set default hsts value if one not provided - } - if aRoute.AlternativeNames != nil { - add.AlternativeNames = aRoute.AlternativeNames - } else { - add.AlternativeNames = []string{} - } + routeAdd, err := handleAPIRoute(defaultIngressClass, apiRoute) + if err != nil { + return firstRoundRoutes, err } - // hsts end - for _, route := range finalRoutes.Routes { - if aRoute.Domain == route.Domain { + for _, route := range firstRoundRoutes.Routes { + if apiRoute.Domain == route.Domain { existsInAPI = true } } if existsInAPI { existsInAPI = false } else { - finalRoutes.Routes = append(finalRoutes.Routes, add) + firstRoundRoutes.Routes = append(firstRoundRoutes.Routes, routeAdd) } } - finalRoutes2 := RoutesV2{} - for _, fRoute := range finalRoutes.Routes { + + // generate the final routes to provide back as "the" route list for this environment + finalRoutes := RoutesV2{} + for _, fRoute := range firstRoundRoutes.Routes { // generate the fastly configuration for this route if required err := GenerateFastlyConfiguration(&fRoute.Fastly, "", fRoute.Fastly.ServiceID, fRoute.Domain, secretPrefix, variables) if err != nil { //@TODO: error handling } - finalRoutes2.Routes = append(finalRoutes2.Routes, fRoute) + fRoute.Domain = strings.ToLower(fRoute.Domain) + finalRoutes.Routes = append(finalRoutes.Routes, fRoute) + } + return finalRoutes, nil +} + +// handleAPIRoute handles setting the defaults for API defined routes +// main lagoon.yml defaults are handled in `GenerateRoutesV2` function +func handleAPIRoute(defaultIngressClass string, apiRoute RouteV2) (RouteV2, error) { + routeAdd := apiRoute + // copy in the apiroute fastly configuration + routeAdd.Fastly = apiRoute.Fastly + if apiRoute.TLSAcme != nil { + routeAdd.TLSAcme = apiRoute.TLSAcme + } else { + routeAdd.TLSAcme = defaultTLSAcme + } + if apiRoute.Insecure != nil { + routeAdd.Insecure = apiRoute.Insecure + } else { + routeAdd.Insecure = defaultInsecure + } + if apiRoute.Annotations != nil { + routeAdd.Annotations = apiRoute.Annotations + } else { + routeAdd.Annotations = defaultAnnotations + } + if apiRoute.AlternativeNames != nil { + routeAdd.AlternativeNames = apiRoute.AlternativeNames + } else { + routeAdd.AlternativeNames = []string{} + } + if apiRoute.IngressClass != "" { + routeAdd.IngressClass = apiRoute.IngressClass + } else { + routeAdd.IngressClass = defaultIngressClass + } + + // handle hsts here + if apiRoute.HSTSEnabled != nil { + routeAdd.HSTSEnabled = apiRoute.HSTSEnabled + } + if apiRoute.HSTSIncludeSubdomains != nil { + routeAdd.HSTSIncludeSubdomains = apiRoute.HSTSIncludeSubdomains + } + if apiRoute.HSTSPreload != nil { + routeAdd.HSTSPreload = apiRoute.HSTSPreload + } + if apiRoute.HSTSMaxAge > 0 { + routeAdd.HSTSMaxAge = apiRoute.HSTSMaxAge + } else { + if routeAdd.HSTSEnabled != nil && *routeAdd.HSTSEnabled { + routeAdd.HSTSMaxAge = defaultHSTSMaxAge // set default hsts value if one not provided + } + } + // hsts end + + // handle wildcards + if apiRoute.Wildcard != nil { + routeAdd.Wildcard = apiRoute.Wildcard + if *routeAdd.TLSAcme == true && *routeAdd.Wildcard == true { + return routeAdd, fmt.Errorf("Route %s has wildcard=true and tls-acme=true, this is not supported", routeAdd.Domain) + } + if apiRoute.AlternativeNames != nil && *routeAdd.Wildcard == true { + return routeAdd, fmt.Errorf("Route %s has wildcard=true and alternativenames defined, this is not supported", routeAdd.Domain) + } } - return finalRoutes2 + return routeAdd, nil } diff --git a/internal/lagoon/routes_test.go b/internal/lagoon/routes_test.go index d690c6b8..d2ff9be5 100644 --- a/internal/lagoon/routes_test.go +++ b/internal/lagoon/routes_test.go @@ -11,7 +11,7 @@ import ( func TestGenerateRouteStructure(t *testing.T) { type args struct { - genRoutes *RoutesV2 + yamlRoutes *RoutesV2 yamlRouteMap map[string][]Route variables []EnvironmentVariable defaultIngressClass string @@ -19,14 +19,15 @@ func TestGenerateRouteStructure(t *testing.T) { activeStandby bool } tests := []struct { - name string - args args - want *RoutesV2 + name string + args args + want *RoutesV2 + wantErr bool }{ { name: "test1", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -72,7 +73,7 @@ func TestGenerateRouteStructure(t *testing.T) { { name: "test2", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -128,7 +129,7 @@ func TestGenerateRouteStructure(t *testing.T) { { name: "test3", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -176,7 +177,7 @@ func TestGenerateRouteStructure(t *testing.T) { { name: "test4 - ingress class", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -225,7 +226,7 @@ func TestGenerateRouteStructure(t *testing.T) { { name: "test5 - custom ingress class on one route", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -285,7 +286,7 @@ func TestGenerateRouteStructure(t *testing.T) { { name: "test6 - hsts", args: args{ - genRoutes: &RoutesV2{}, + yamlRoutes: &RoutesV2{}, yamlRouteMap: map[string][]Route{ "nginx": { { @@ -342,12 +343,74 @@ func TestGenerateRouteStructure(t *testing.T) { }, }, }, + { + name: "test7 - wildcard with tls-acme true (should error)", + args: args{ + yamlRoutes: &RoutesV2{}, + yamlRouteMap: map[string][]Route{ + "nginx": { + { + Ingresses: map[string]Ingress{ + "www.example.com": { + TLSAcme: helpers.BoolPtr(true), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + secretPrefix: "fastly-api-", + activeStandby: false, + }, + wantErr: true, + want: &RoutesV2{ + Routes: nil, + }, + }, + { + name: "test7 - wildcard with tls-acme false", + args: args{ + yamlRoutes: &RoutesV2{}, + yamlRouteMap: map[string][]Route{ + "nginx": { + { + Ingresses: map[string]Ingress{ + "www.example.com": { + TLSAcme: helpers.BoolPtr(false), + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + }, + secretPrefix: "fastly-api-", + activeStandby: false, + }, + want: &RoutesV2{ + Routes: []RouteV2{ + { + Domain: "www.example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + AlternativeNames: []string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - GenerateRoutesV2(tt.args.genRoutes, tt.args.yamlRouteMap, 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) + err := GenerateRoutesV2(tt.args.yamlRoutes, tt.args.yamlRouteMap, tt.args.variables, tt.args.defaultIngressClass, tt.args.secretPrefix, tt.args.activeStandby) + if (err != nil) != tt.wantErr { + t.Errorf("GenerateRouteStructure() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !cmp.Equal(tt.args.yamlRoutes, tt.want) && !tt.wantErr { + stra, _ := json.Marshal(tt.args.yamlRoutes) strb, _ := json.Marshal(tt.want) t.Errorf("GenerateRouteStructure() = %v, want %v", string(stra), string(strb)) } @@ -357,21 +420,22 @@ func TestGenerateRouteStructure(t *testing.T) { func TestMergeRouteStructures(t *testing.T) { type args struct { - genRoutes RoutesV2 + yamlRoutes RoutesV2 apiRoutes RoutesV2 variables []EnvironmentVariable defaultIngressClass string secretPrefix string } tests := []struct { - name string - args args - want RoutesV2 + name string + args args + want RoutesV2 + wantErr bool }{ { name: "test1", args: args{ - genRoutes: RoutesV2{ + yamlRoutes: RoutesV2{ Routes: []RouteV2{ { Domain: "example.com", @@ -490,10 +554,197 @@ func TestMergeRouteStructures(t *testing.T) { }, }, }, + { + name: "test2 - wildcard with tls-acme changed to false", + args: args{ + yamlRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + { + Domain: "a.example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + apiRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + { + Domain: "a.example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + secretPrefix: "fastly-api-", + }, + want: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + AlternativeNames: []string{}, + Wildcard: helpers.BoolPtr(true), + }, + { + Domain: "a.example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(false), + Annotations: map[string]string{}, + AlternativeNames: []string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + }, + { + name: "test3 - wildcard with tls-acme true (should error)", + args: args{ + yamlRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + apiRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + secretPrefix: "fastly-api-", + }, + wantErr: true, + want: RoutesV2{ + Routes: nil, + }, + }, + { + name: "test4 - invalid yaml route", + args: args{ + yamlRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "*._re/f#3safasF*.was_-..asfexample.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + apiRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "fail@example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + secretPrefix: "fastly-api-", + }, + wantErr: true, + want: RoutesV2{ + Routes: nil, + }, + }, + { + name: "test5 - invalid api route", + args: args{ + yamlRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + apiRoutes: RoutesV2{ + Routes: []RouteV2{ + { + Domain: "fail@example.com", + LagoonService: "nginx", + MonitoringPath: "/", + Insecure: helpers.StrPtr("Redirect"), + TLSAcme: helpers.BoolPtr(true), + Annotations: map[string]string{}, + Wildcard: helpers.BoolPtr(true), + }, + }, + }, + secretPrefix: "fastly-api-", + }, + wantErr: true, + want: RoutesV2{ + Routes: nil, + }, + }, } 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.defaultIngressClass, tt.args.secretPrefix); !reflect.DeepEqual(got, tt.want) { + got, err := MergeRoutesV2(tt.args.yamlRoutes, tt.args.apiRoutes, tt.args.variables, tt.args.defaultIngressClass, tt.args.secretPrefix) + if (err != nil) != tt.wantErr { + t.Errorf("MergeRouteStructures() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) && !tt.wantErr { stra, _ := json.Marshal(got) strb, _ := json.Marshal(tt.want) t.Errorf("MergeRouteStructures() = %v, want %v", string(stra), string(strb)) diff --git a/internal/templating/ingress/templates_ingress.go b/internal/templating/ingress/templates_ingress.go index 2fee60c9..88bb863b 100644 --- a/internal/templating/ingress/templates_ingress.go +++ b/internal/templating/ingress/templates_ingress.go @@ -25,20 +25,14 @@ func GenerateIngressTemplate( lValues generator.BuildValues, ) ([]byte, error) { - // lowercase any domains then validate them - routeDomain := strings.ToLower(route.Domain) - if err := validation.IsDNS1123Subdomain(strings.ToLower(routeDomain)); err != nil { - return nil, fmt.Errorf("the provided domain name %s is not valid: %v", route.Domain, err) - } - // truncate the route for use in labels and secretname - truncatedRouteDomain := routeDomain + truncatedRouteDomain := route.Domain if len(truncatedRouteDomain) >= 53 { subdomain := strings.Split(truncatedRouteDomain, ".")[0] if errs := utilvalidation.IsValidLabelValue(subdomain); errs != nil { subdomain = subdomain[:53] } - truncatedRouteDomain = fmt.Sprintf("%s-%s", strings.Split(subdomain, ".")[0], helpers.GetMD5HashWithNewLine(routeDomain)[:5]) + truncatedRouteDomain = fmt.Sprintf("%s-%s", strings.Split(subdomain, ".")[0], helpers.GetMD5HashWithNewLine(route.Domain)[:5]) } // create the ingress object for templating @@ -47,11 +41,32 @@ func GenerateIngressTemplate( Kind: "Ingress", APIVersion: "networking.k8s.io/v1", } - ingress.ObjectMeta.Name = routeDomain + ingress.ObjectMeta.Name = route.Domain if route.Autogenerated { // autogenerated routes just have the service name ingress.ObjectMeta.Name = route.LagoonService } + + // if this is a wildcard ingress, handle templating that here + if route.Wildcard != nil && *route.Wildcard == true { + // prefix the object name with wildcard + ingress.ObjectMeta.Name = fmt.Sprintf("wildcard-%s", ingress.ObjectMeta.Name) + // if the new name exceeds the validation spec, truncate it + if err := validation.IsDNS1123Subdomain(strings.ToLower(ingress.ObjectMeta.Name)); err != nil { + ingress.ObjectMeta.Name = fmt.Sprintf("%s-%s", ingress.ObjectMeta.Name[:len(ingress.ObjectMeta.Name)-10], helpers.GetMD5HashWithNewLine(route.Domain)[:5]) + } + truncatedRouteDomain = fmt.Sprintf("wildcard-%s", truncatedRouteDomain) + if len(truncatedRouteDomain) >= 53 { + subdomain := strings.Split(truncatedRouteDomain, "-")[0] + if errs := utilvalidation.IsValidLabelValue(subdomain); errs != nil { + subdomain = subdomain[:53] + } + truncatedRouteDomain = fmt.Sprintf("%s-%s", strings.Split(subdomain, "-")[0], helpers.GetMD5HashWithNewLine(route.Domain)[:5]) + } + // set the domain to include the wildcard prefix + route.Domain = fmt.Sprintf("*.%s", route.Domain) + } + // add the default labels ingress.ObjectMeta.Labels = map[string]string{ "lagoon.sh/autogenerated": "false", @@ -89,7 +104,7 @@ func GenerateIngressTemplate( primaryIngress, _ := url.Parse(lValues.Route) // check if monitoring enabled, route isn't autogenerated, and the primary ingress from the .lagoon.yml is this processed routedomain // and enable monitoring on the primary ingress only. - if lValues.Monitoring.Enabled && !route.Autogenerated && primaryIngress.Host == routeDomain { + if lValues.Monitoring.Enabled && !route.Autogenerated && primaryIngress.Host == route.Domain { additionalLabels["lagoon.sh/primaryIngress"] = "true" // only add the monitring annotations if monitoring is enabled @@ -185,13 +200,13 @@ func GenerateIngressTemplate( // validate any annotations if err := apivalidation.ValidateAnnotations(ingress.ObjectMeta.Annotations, nil); err != nil { if len(err) != 0 { - return nil, fmt.Errorf("the annotations for %s are not valid: %v", routeDomain, err) + return nil, fmt.Errorf("the annotations for %s are not valid: %v", route.Domain, err) } } // validate any labels if err := metavalidation.ValidateLabels(ingress.ObjectMeta.Labels, nil); err != nil { if len(err) != 0 { - return nil, fmt.Errorf("the labels for %s are not valid: %v", routeDomain, err) + return nil, fmt.Errorf("the labels for %s are not valid: %v", route.Domain, err) } } @@ -220,13 +235,13 @@ func GenerateIngressTemplate( // use the compose service name to check this, as this is how Services are populated from the compose generation for _, service := range lValues.Services { if service.Name == route.ComposeService { - if service.ShortAutogeneratedRouteDomain != "" && len(routeDomain) > 63 { + if service.ShortAutogeneratedRouteDomain != "" && len(route.Domain) > 63 { ingress.Spec.TLS[0].Hosts = append(ingress.Spec.TLS[0].Hosts, service.ShortAutogeneratedRouteDomain) } } } // add the main domain to the tls spec now - ingress.Spec.TLS[0].Hosts = append(ingress.Spec.TLS[0].Hosts, routeDomain) + ingress.Spec.TLS[0].Hosts = append(ingress.Spec.TLS[0].Hosts, route.Domain) // default service port is http in all lagoon deployments servicePort := networkv1.ServiceBackendPort{ @@ -251,7 +266,7 @@ func GenerateIngressTemplate( // add the main domain as the first rule in the spec ingress.Spec.Rules = []networkv1.IngressRule{ { - Host: routeDomain, + Host: route.Domain, IngressRuleValue: networkv1.IngressRuleValue{ HTTP: &networkv1.HTTPIngressRuleValue{ Paths: []networkv1.HTTPIngressPath{ diff --git a/internal/templating/ingress/templates_ingress_test.go b/internal/templating/ingress/templates_ingress_test.go index 5c290ace..8f2c4cd7 100644 --- a/internal/templating/ingress/templates_ingress_test.go +++ b/internal/templating/ingress/templates_ingress_test.go @@ -257,10 +257,10 @@ func TestGenerateKubeTemplate(t *testing.T) { want: "test-resources/result-custom-ingress5.yaml", }, { - name: "test6 - invalid domain", + name: "test6 - invalid annotation", args: args{ route: lagoon.RouteV2{ - Domain: "fail@.extra-long-name.a-really-long-name-that-should-truncate.www.example.com", + Domain: "extra-long-name.a-really-long-name-that-should-truncate.www.example.com", LagoonService: "nginx", MonitoringPath: "/", Insecure: helpers.StrPtr("Redirect"), @@ -268,6 +268,7 @@ func TestGenerateKubeTemplate(t *testing.T) { Migrate: helpers.BoolPtr(false), Annotations: map[string]string{ "custom-annotation": "custom annotation value", + "@invalid": "this is an invalid annotation", }, Fastly: lagoon.Fastly{ Watch: false, @@ -294,7 +295,7 @@ func TestGenerateKubeTemplate(t *testing.T) { wantErr: true, }, { - name: "test7 - invalid annotation", + name: "test7 - invalid label", args: args{ route: lagoon.RouteV2{ Domain: "extra-long-name.a-really-long-name-that-should-truncate.www.example.com", @@ -305,7 +306,9 @@ func TestGenerateKubeTemplate(t *testing.T) { Migrate: helpers.BoolPtr(false), Annotations: map[string]string{ "custom-annotation": "custom annotation value", - "@invalid": "this is an invalid annotation", + }, + Labels: map[string]string{ + "@invalid": "this is an invalid annotation", }, Fastly: lagoon.Fastly{ Watch: false, @@ -332,10 +335,10 @@ func TestGenerateKubeTemplate(t *testing.T) { wantErr: true, }, { - name: "test8 - invalid label", + name: "test8 - custom ingress with exceptionally long subdomain", args: args{ route: lagoon.RouteV2{ - Domain: "extra-long-name.a-really-long-name-that-should-truncate.www.example.com", + Domain: "hmm-this-is-a-really-long-branch-name-designed-to-test-a-specific-feature.www.example.com", LagoonService: "nginx", MonitoringPath: "/", Insecure: helpers.StrPtr("Redirect"), @@ -344,9 +347,6 @@ func TestGenerateKubeTemplate(t *testing.T) { Annotations: map[string]string{ "custom-annotation": "custom annotation value", }, - Labels: map[string]string{ - "@invalid": "this is an invalid annotation", - }, Fastly: lagoon.Fastly{ Watch: false, }, @@ -369,17 +369,17 @@ func TestGenerateKubeTemplate(t *testing.T) { }, activeStandby: false, }, - wantErr: true, + want: "test-resources/result-custom-ingress6.yaml", }, { - name: "test9 - too long domain", + name: "test9 - wildcard ingress", args: args{ route: lagoon.RouteV2{ - Domain: "extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.www.example.com", + Domain: "www.example.com", LagoonService: "nginx", MonitoringPath: "/", Insecure: helpers.StrPtr("Redirect"), - TLSAcme: helpers.BoolPtr(true), + TLSAcme: helpers.BoolPtr(false), Migrate: helpers.BoolPtr(false), Annotations: map[string]string{ "custom-annotation": "custom annotation value", @@ -388,16 +388,17 @@ func TestGenerateKubeTemplate(t *testing.T) { Watch: false, }, IngressClass: "nginx", + Wildcard: helpers.BoolPtr(true), }, values: generator.BuildValues{ Project: "example-project", - Environment: "environment-with-really-really-reall-3fdb", + Environment: "environment", EnvironmentType: "development", - Namespace: "myexample-project-environment-with-really-really-reall-3fdb", + Namespace: "myexample-project-environment", BuildType: "branch", LagoonVersion: "v2.x.x", Kubernetes: "lagoon.local", - Branch: "environment-with-really-really-reall-3fdb", + Branch: "environment", Monitoring: generator.MonitoringConfig{ AlertContact: "abcdefg", StatusPageID: "12345", @@ -406,17 +407,17 @@ func TestGenerateKubeTemplate(t *testing.T) { }, activeStandby: false, }, - wantErr: true, + want: "test-resources/result-wildcard-ingress1.yaml", }, { - name: "test10 - custom ingress with exceptionally long subdomain", + name: "test10 - wildcard ingress", args: args{ route: lagoon.RouteV2{ - Domain: "hmm-this-is-a-really-long-branch-name-designed-to-test-a-specific-feature.www.example.com", + Domain: "this-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.www.example.com", LagoonService: "nginx", MonitoringPath: "/", Insecure: helpers.StrPtr("Redirect"), - TLSAcme: helpers.BoolPtr(true), + TLSAcme: helpers.BoolPtr(false), Migrate: helpers.BoolPtr(false), Annotations: map[string]string{ "custom-annotation": "custom annotation value", @@ -425,16 +426,17 @@ func TestGenerateKubeTemplate(t *testing.T) { Watch: false, }, IngressClass: "nginx", + Wildcard: helpers.BoolPtr(true), }, values: generator.BuildValues{ Project: "example-project", - Environment: "environment-with-really-really-reall-3fdb", + Environment: "environment", EnvironmentType: "development", - Namespace: "myexample-project-environment-with-really-really-reall-3fdb", + Namespace: "myexample-project-environment", BuildType: "branch", LagoonVersion: "v2.x.x", Kubernetes: "lagoon.local", - Branch: "environment-with-really-really-reall-3fdb", + Branch: "environment", Monitoring: generator.MonitoringConfig{ AlertContact: "abcdefg", StatusPageID: "12345", @@ -443,7 +445,7 @@ func TestGenerateKubeTemplate(t *testing.T) { }, activeStandby: false, }, - want: "test-resources/result-custom-ingress6.yaml", + want: "test-resources/result-wildcard-ingress2.yaml", }, } for _, tt := range tests { diff --git a/internal/templating/ingress/test-resources/result-wildcard-ingress1.yaml b/internal/templating/ingress/test-resources/result-wildcard-ingress1.yaml new file mode 100644 index 00000000..10d657ac --- /dev/null +++ b/internal/templating/ingress/test-resources/result-wildcard-ingress1.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: "false" + lagoon.sh/branch: environment + 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: wildcard-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 + lagoon.sh/environmentType: development + lagoon.sh/project: example-project + lagoon.sh/service: wildcard-www.example.com + lagoon.sh/service-type: custom-ingress + name: wildcard-www.example.com +spec: + ingressClassName: nginx + rules: + - host: '*.www.example.com' + http: + paths: + - backend: + service: + name: nginx + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - '*.www.example.com' + secretName: wildcard-www.example.com-tls +status: + loadBalancer: {} diff --git a/internal/templating/ingress/test-resources/result-wildcard-ingress2.yaml b/internal/templating/ingress/test-resources/result-wildcard-ingress2.yaml new file mode 100644 index 00000000..8dc4e2b3 --- /dev/null +++ b/internal/templating/ingress/test-resources/result-wildcard-ingress2.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: "false" + lagoon.sh/branch: environment + 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: wildcard-this-truncate-f1945 + 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 + lagoon.sh/environmentType: development + lagoon.sh/project: example-project + lagoon.sh/service: wildcard-this-truncate-f1945 + lagoon.sh/service-type: custom-ingress + name: wildcard-this-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.www.e-f1945 +spec: + ingressClassName: nginx + rules: + - host: '*.this-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.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: + - '*.this-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.extra-long-name.a-really-long-name-that-should-truncate.www.example.com' + secretName: wildcard-this-truncate-f1945-tls +status: + loadBalancer: {} diff --git a/test-resources/template-ingress/test22-results/example.com.yaml b/test-resources/template-ingress/test22-results/example.com.yaml new file mode 100644 index 00000000..ce022329 --- /dev/null +++ b/test-resources/template-ingress/test22-results/example.com.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + fastly.amazee.io/watch: "false" + ingress.kubernetes.io/ssl-redirect: "true" + kubernetes.io/tls-acme: "false" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + monitor.stakater.com/enabled: "false" + monitor.stakater.com/overridePath: / + nginx.ingress.kubernetes.io/ssl-redirect: "true" + creationTimestamp: null + labels: + app.kubernetes.io/instance: wildcard-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: wildcard-example.com + lagoon.sh/service-type: custom-ingress + name: wildcard-example.com +spec: + rules: + - host: '*.example.com' + http: + paths: + - backend: + service: + name: node + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - '*.example.com' + secretName: wildcard-example.com-tls +status: + loadBalancer: {} diff --git a/test-resources/template-ingress/test22/docker-compose.yml b/test-resources/template-ingress/test22/docker-compose.yml new file mode 100644 index 00000000..85386270 --- /dev/null +++ b/test-resources/template-ingress/test22/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/test22/lagoon.yml b/test-resources/template-ingress/test22/lagoon.yml new file mode 100644 index 00000000..9f44e4c6 --- /dev/null +++ b/test-resources/template-ingress/test22/lagoon.yml @@ -0,0 +1,12 @@ +docker-compose-yaml: ../test-resources/template-ingress/test22/docker-compose.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com: + tls-acme: false + wildcard: true From cab37c856b22386231ed799e3bf4359df929c0c1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 24 Jul 2023 08:01:09 +1000 Subject: [PATCH 9/9] chore: revert Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9fee2f8a..ce17d0c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,8 +70,8 @@ ENV KUBECTL_VERSION=v1.20.4 \ HELM_SHA256=01b317c506f8b6ad60b11b1dc3f093276bb703281cb1ae01132752253ec706a2 RUN apk add -U --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing aufs-util \ - && apk add --update openssl curl jq parallel \ - && apk add --no-cache bash git openssh-client-common=9.1_p1-r3 openssh=9.1_p1-r3 py-pip skopeo \ + && apk upgrade --no-cache openssh openssh-keygen openssh-client-common openssh-client-default \ + && apk add --no-cache openssl curl jq parallel bash git py-pip skopeo \ && git config --global user.email "lagoon@lagoon.io" && git config --global user.name lagoon \ && pip install shyaml yq \ && curl -Lo /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl \