diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0478126b..72b8ba187 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,12 +30,15 @@ jobs: output: traefik/values.schema.json fail-on-diff: true - - name: Lint + - name: Lint Chart run: make lint - - name: Test + - name: Test Chart run: make test + - name: Test overrideNamespace + run: make test-ns + - name: Test if it's a release PR id: check run: | diff --git a/Makefile b/Makefile index 43ffaf01f..22dbf0a74 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ traefik/tests/__snapshot__: test: traefik/tests/__snapshot__ docker run ${DOCKER_ARGS} --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_HELM_UNITTEST) /charts/hack/test.sh +test-ns: + ./hack/check-ns.sh + lint: docker run ${DOCKER_ARGS} --env GIT_SAFE_DIR="true" --entrypoint /bin/sh --rm -v $(CURDIR):/charts -w /charts $(IMAGE_CHART_TESTING) /charts/hack/ct.sh lint diff --git a/hack/check-ns.sh b/hack/check-ns.sh new file mode 100755 index 000000000..3df1a63dd --- /dev/null +++ b/hack/check-ns.sh @@ -0,0 +1,14 @@ +#!/bin/bash + + +ns=$(grep -rn .Release.Namespace traefik/templates/ | wc -l) + +if [[ ${ns} -ne 1 ]] ; then + echo "Namespace check KO. Please check an overrideNamespace case has not been missed." + echo "See https://github.com/traefik/traefik-helm-chart/issues/1289" + exit 1 +fi + +echo "Namespace check OK" + +exit 0 diff --git a/traefik/VALUES.md b/traefik/VALUES.md index 5a6b595f3..86fb6d5cc 100644 --- a/traefik/VALUES.md +++ b/traefik/VALUES.md @@ -262,7 +262,7 @@ Kubernetes: `>=1.22.0-0` | providers.kubernetesGateway.nativeLBByDefault | bool | `false` | Defines whether to use Native Kubernetes load-balancing mode by default. | | providers.kubernetesGateway.statusAddress.hostname | string | `""` | This Hostname will get copied to the Gateway status.addresses. | | providers.kubernetesGateway.statusAddress.ip | string | `""` | This IP will get copied to the Gateway status.addresses, and currently only supports one IP value (IPv4 or IPv6). | -| providers.kubernetesGateway.statusAddress.service | object | `{"name":"{{ (include \"traefik.fullname\" .) }}","namespace":"{{ .Release.Namespace }}"}` | The Kubernetes service to copy status addresses from. When using third parties tools like External-DNS, this option can be used to copy the service loadbalancer.status (containing the service's endpoints IPs) to the gateways. Default to Service of this Chart. | +| providers.kubernetesGateway.statusAddress.service | object | `{"name":"{{ (include \"traefik.fullname\" .) }}","namespace":"{{ include \"traefik.namespace\" . }}"}` | The Kubernetes service to copy status addresses from. When using third parties tools like External-DNS, this option can be used to copy the service loadbalancer.status (containing the service's endpoints IPs) to the gateways. Default to Service of this Chart. | | providers.kubernetesIngress.allowEmptyServices | bool | `true` | Allows to return 503 when there is no endpoints available | | providers.kubernetesIngress.allowExternalNameServices | bool | `false` | Allows to reference ExternalName services in Ingress | | providers.kubernetesIngress.enabled | bool | `true` | Load Kubernetes Ingress provider | diff --git a/traefik/templates/_helpers.tpl b/traefik/templates/_helpers.tpl index 7ab9ee594..718f54d8d 100644 --- a/traefik/templates/_helpers.tpl +++ b/traefik/templates/_helpers.tpl @@ -43,7 +43,7 @@ If release name contains chart name it will be used as a full name. Allow customization of the instance label value. */}} {{- define "traefik.instance-name" -}} -{{- default (printf "%s-%s" .Release.Name .Release.Namespace) .Values.instanceLabelOverride | trunc 63 | trimSuffix "-" -}} +{{- default (printf "%s-%s" .Release.Name (include "traefik.namespace" .)) .Values.instanceLabelOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* Shared labels used for selector*/}} @@ -89,7 +89,7 @@ Adds the namespace to name to prevent duplicate resource names when there are multiple namespaced releases with the same release name. */}} {{- define "traefik.clusterRoleName" -}} -{{- (printf "%s-%s" (include "traefik.fullname" .) .Release.Namespace) | trunc 63 | trimSuffix "-" }} +{{- (printf "%s-%s" (include "traefik.fullname" .) (include "traefik.namespace" .)) | trunc 63 | trimSuffix "-" }} {{- end -}} {{/* @@ -99,7 +99,7 @@ service generated. Users can provide an override for an explicit service they want bound via `.Values.providers.kubernetesIngress.publishedService.pathOverride` */}} {{- define "providers.kubernetesIngress.publishedServicePath" -}} -{{- $defServiceName := printf "%s/%s" .Release.Namespace (include "traefik.fullname" .) -}} +{{- $defServiceName := printf "%s/%s" (include "traefik.namespace" .) (include "traefik.fullname" .) -}} {{- $servicePath := default $defServiceName .Values.providers.kubernetesIngress.publishedService.pathOverride }} {{- print $servicePath | trimSuffix "-" -}} {{- end -}} @@ -150,15 +150,15 @@ based on semverCompare {{/* Generate/load self-signed certificate for admission webhooks */}} {{- define "traefik-hub.webhook_cert" -}} -{{- $cert := lookup "v1" "Secret" .Release.Namespace "hub-agent-cert" -}} +{{- $cert := lookup "v1" "Secret" (include "traefik.namespace" .) "hub-agent-cert" -}} {{- if $cert -}} {{/* reusing value of existing cert */}} Cert: {{ index $cert.data "tls.crt" }} Key: {{ index $cert.data "tls.key" }} {{- else -}} {{/* generate a new one */}} -{{- $altNames := list ( printf "admission.%s.svc" .Release.Namespace ) -}} -{{- $cert := genSelfSignedCert ( printf "admission.%s.svc" .Release.Namespace ) (list) $altNames 3650 -}} +{{- $altNames := list ( printf "admission.%s.svc" (include "traefik.namespace" .) ) -}} +{{- $cert := genSelfSignedCert ( printf "admission.%s.svc" (include "traefik.namespace" .) ) (list) $altNames 3650 -}} Cert: {{ $cert.Cert | b64enc }} Key: {{ $cert.Key | b64enc }} {{- end -}} diff --git a/traefik/tests/container-config_test.yaml b/traefik/tests/container-config_test.yaml index a781a0bf7..1d1b8536b 100644 --- a/traefik/tests/container-config_test.yaml +++ b/traefik/tests/container-config_test.yaml @@ -206,3 +206,13 @@ tests: matchLabels: app.kubernetes.io/name: traefik app.kubernetes.io/instance: traefik + - it: should set instance label to release.name-namespaceOverride when it is set + set: + namespaceOverride: foo + asserts: + - isSubset: + path: spec.selector + content: + matchLabels: + app.kubernetes.io/name: traefik + app.kubernetes.io/instance: RELEASE-NAME-foo diff --git a/traefik/tests/pod-config_test.yaml b/traefik/tests/pod-config_test.yaml index c077ea4cf..7c3e05f03 100644 --- a/traefik/tests/pod-config_test.yaml +++ b/traefik/tests/pod-config_test.yaml @@ -314,6 +314,18 @@ tests: - contains: path: spec.template.spec.containers[0].args content: "--providers.kubernetesgateway.statusaddress.service.namespace=NAMESPACE" + - it: When gateway provider is enabled with ns override, k8s providers & default statusAddress should be set + set: + namespaceOverride: foo + providers: + kubernetesGateway: + enabled: true + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--providers.kubernetesgateway.statusaddress.service.namespace=foo" + + - it: should have experimental flag when set set: experimental: @@ -744,4 +756,4 @@ tests: asserts: - contains: path: spec.template.spec.containers[0].args - content: "--providers.kubernetesingress.allowEmptyServices=false" \ No newline at end of file + content: "--providers.kubernetesingress.allowEmptyServices=false" diff --git a/traefik/tests/rbac-config_test.yaml b/traefik/tests/rbac-config_test.yaml index a57134e20..c4525f24b 100644 --- a/traefik/tests/rbac-config_test.yaml +++ b/traefik/tests/rbac-config_test.yaml @@ -40,6 +40,26 @@ tests: path: subjects[0].name value: RELEASE-NAME-traefik template: rbac/clusterrolebinding.yaml + - equal: + path: metadata.name + value: RELEASE-NAME-traefik-NAMESPACE + template: rbac/clusterrole.yaml + - equal: + path: metadata.name + value: RELEASE-NAME-traefik-NAMESPACE + template: rbac/clusterrolebinding.yaml + - it: should set expected name when ns is overriden + set: + namespaceOverride: foo + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-traefik-foo + template: rbac/clusterrole.yaml + - equal: + path: metadata.name + value: RELEASE-NAME-traefik-foo + template: rbac/clusterrolebinding.yaml - it: should not create RBAC related objects when disabled set: rbac: diff --git a/traefik/tests/traefik-config_test.yaml b/traefik/tests/traefik-config_test.yaml index ec8e89be5..5b78a816b 100644 --- a/traefik/tests/traefik-config_test.yaml +++ b/traefik/tests/traefik-config_test.yaml @@ -74,12 +74,18 @@ tests: - notContains: path: spec.template.spec.containers[0].args content: "--providers.kubernetescrd" - - it: should have enabled published Kubernetes service when default configuration asserts: - contains: path: spec.template.spec.containers[0].args content: "--providers.kubernetesingress.ingressendpoint.publishedservice=NAMESPACE/RELEASE-NAME-traefik" + - it: should use overrided namespace when specified + set: + namespaceOverride: foo + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: "--providers.kubernetesingress.ingressendpoint.publishedservice=foo/RELEASE-NAME-traefik" - it: should be possible to disable published Kubernetes service when specified in configuration set: providers: diff --git a/traefik/tests/values/antiaffinity.yaml b/traefik/tests/values/antiaffinity.yaml index f0472fe12..a31dc3010 100644 --- a/traefik/tests/values/antiaffinity.yaml +++ b/traefik/tests/values/antiaffinity.yaml @@ -4,5 +4,5 @@ affinity: - labelSelector: matchLabels: app.kubernetes.io/name: '{{ template "traefik.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}-{{ .Release.Namespace }}' + app.kubernetes.io/instance: '{{ .Release.Name }}-{{ include "traefik.namespace" . }}' topologyKey: kubernetes.io/hostname diff --git a/traefik/values.yaml b/traefik/values.yaml index 78c8ea4f4..64cbbec50 100644 --- a/traefik/values.yaml +++ b/traefik/values.yaml @@ -315,7 +315,7 @@ providers: # @schema additionalProperties: false # -- The Kubernetes service to copy status addresses from. When using third parties tools like External-DNS, this option can be used to copy the service loadbalancer.status (containing the service's endpoints IPs) to the gateways. Default to Service of this Chart. service: name: "{{ (include \"traefik.fullname\" .) }}" - namespace: "{{ .Release.Namespace }}" + namespace: "{{ include \"traefik.namespace\" . }}" file: # -- Create a file provider @@ -869,7 +869,7 @@ affinity: {} # - labelSelector: # matchLabels: # app.kubernetes.io/name: '{{ template "traefik.name" . }}' -# app.kubernetes.io/instance: '{{ .Release.Name }}-{{ .Release.Namespace }}' +# app.kubernetes.io/instance: '{{ .Release.Name }}-{{ include "traefik.namespace" . }}' # topologyKey: kubernetes.io/hostname # -- nodeSelector is the simplest recommended form of node selection constraint.