From 7bd59deed1ff93f58f1e43301363b09c9e7a1943 Mon Sep 17 00:00:00 2001 From: Ricardo Pchevuzinske Katz Date: Sun, 18 Jul 2021 16:44:43 -0300 Subject: [PATCH] Fix chart and admission tests Signed-off-by: Ricardo Pchevuzinske Katz --- .github/workflows/ci.yaml | 18 + .../ci/daemonset-customconfig-values.yaml | 4 + .../ci/daemonset-customnodeport-values.yaml | 4 + .../ci/daemonset-headers-values.yaml | 4 + .../ci/daemonset-internal-lb-values.yaml | 4 + .../ci/daemonset-nodeport-values.yaml | 4 + .../ci/daemonset-podannotations-values.yaml | 4 + ...set-tcp-udp-configMapNamespace-values.yaml | 4 + .../ci/daemonset-tcp-udp-values.yaml | 4 + .../ci/daemonset-tcp-values.yaml | 4 + .../ci/deamonset-default-values.yaml | 4 + .../ci/deamonset-metrics-values.yaml | 4 + .../ci/deamonset-psp-values.yaml | 4 + .../ci/deamonset-webhook-and-psp-values.yaml | 4 + .../ci/deamonset-webhook-values.yaml | 4 + .../ci/deployment-autoscaling-values.yaml | 4 + .../ci/deployment-customconfig-values.yaml | 4 + .../ci/deployment-customnodeport-values.yaml | 4 + .../ci/deployment-default-values.yaml | 4 + .../ci/deployment-headers-values.yaml | 4 + .../ci/deployment-internal-lb-values.yaml | 4 + .../ci/deployment-metrics-values.yaml | 4 + .../ci/deployment-nodeport-values.yaml | 4 + .../ci/deployment-podannotations-values.yaml | 4 + .../ci/deployment-psp-values.yaml | 4 + ...ent-tcp-udp-configMapNamespace-values.yaml | 4 + .../ci/deployment-tcp-udp-values.yaml | 4 + .../ci/deployment-tcp-values.yaml | 4 + .../ci/deployment-webhook-and-psp-values.yaml | 4 + .../ci/deployment-webhook-values.yaml | 4 + .../ingress-nginx/templates/clusterrole.yaml | 6 +- .../templates/controller-ingressclass.yaml | 33 +- .../templates/controller-role.yaml | 6 +- charts/ingress-nginx/values.yaml | 7 +- internal/ingress/controller/store/store.go | 6 +- .../forwarded-port-headers/values.yaml | 4 +- test/e2e/admission/admission.go | 55 +- test/e2e/annotations/affinity.go | 2 +- test/e2e/annotations/canary.go | 56 +- test/e2e/defaultbackend/with_hosts.go | 2 +- test/e2e/framework/framework.go | 22 +- test/e2e/framework/util.go | 91 ++++ test/e2e/ingress/without_host.go | 2 +- test/e2e/run-chart-test.sh | 20 +- test/e2e/servicebackend/service_backend.go | 4 +- .../servicebackend/service_externalname.go | 15 +- test/e2e/settings/ingress_class.disabled | 334 ------------ test/e2e/settings/ingress_class.go | 513 ++++++++++++++++++ test/e2e/settings/no_auth_locations.go | 2 +- test/e2e/settings/server_tokens.go | 2 +- test/e2e/status/update.go | 2 +- test/e2e/wait-for-nginx.sh | 4 +- 52 files changed, 886 insertions(+), 436 deletions(-) delete mode 100644 test/e2e/settings/ingress_class.disabled create mode 100644 test/e2e/settings/ingress_class.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8904fe20231..1e76fa5ad87 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -116,6 +116,7 @@ jobs: runs-on: ubuntu-latest needs: - changes + - build if: | (needs.changes.outputs.charts == 'true') @@ -123,6 +124,12 @@ jobs: - name: Checkout uses: actions/checkout@v2 + + - name: cache + uses: actions/download-artifact@v2 + with: + name: docker.tar.gz + - name: Lint run: | @@ -139,11 +146,22 @@ jobs: with: version: v0.11.1 image: kindest/node:v1.21.1 + + - uses: geekyeggo/delete-artifact@v1 + with: + name: docker.tar.gz + failOnError: false + + - name: Load images from cache + run: | + echo "loading docker images..." + pigz -dc docker.tar.gz | docker load - name: Test env: KIND_CLUSTER_NAME: kind SKIP_CLUSTER_CREATION: true + SKIP_IMAGE_CREATION: true run: | kind get kubeconfig > $HOME/.kube/kind-config-kind make kind-e2e-chart-tests diff --git a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml b/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml index e12b53421bb..43dd2b2ac90 100644 --- a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null kind: DaemonSet admissionWebhooks: enabled: false diff --git a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml index cfc545f69fc..1d94be219bd 100644 --- a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false diff --git a/charts/ingress-nginx/ci/daemonset-headers-values.yaml b/charts/ingress-nginx/ci/daemonset-headers-values.yaml index ff82cd9c703..ab7d47bd4d0 100644 --- a/charts/ingress-nginx/ci/daemonset-headers-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-headers-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false addHeaders: diff --git a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml b/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml index 443e39d8ba8..abae84f6d76 100644 --- a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml index 6d6605f0e1e..3b7aa2fcd2c 100644 --- a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml b/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml index 04ac58dbd82..0b55306a108 100644 --- a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false metrics: diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml index afb5487c571..acd86a77ab2 100644 --- a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml index 7b4d7cbe7d6..25ee64d856c 100644 --- a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-values.yaml index a359a6a401d..380c8b4b133 100644 --- a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml +++ b/charts/ingress-nginx/ci/daemonset-tcp-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deamonset-default-values.yaml b/charts/ingress-nginx/ci/deamonset-default-values.yaml index e63a7f5db36..82fa23e8546 100644 --- a/charts/ingress-nginx/ci/deamonset-default-values.yaml +++ b/charts/ingress-nginx/ci/deamonset-default-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml b/charts/ingress-nginx/ci/deamonset-metrics-values.yaml index 1e5190afc05..cb3cb54be20 100644 --- a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml +++ b/charts/ingress-nginx/ci/deamonset-metrics-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false metrics: diff --git a/charts/ingress-nginx/ci/deamonset-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-psp-values.yaml index 017b60a9c6f..8026a6356f5 100644 --- a/charts/ingress-nginx/ci/deamonset-psp-values.yaml +++ b/charts/ingress-nginx/ci/deamonset-psp-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml index 88aafc66fd9..fccdb134cf4 100644 --- a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml +++ b/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: true service: diff --git a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml b/charts/ingress-nginx/ci/deamonset-webhook-values.yaml index 6e3b371da62..54d364df11f 100644 --- a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml +++ b/charts/ingress-nginx/ci/deamonset-webhook-values.yaml @@ -1,5 +1,9 @@ controller: kind: DaemonSet + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: true service: diff --git a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml b/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml index 5314cecb38e..b8b3ac6862e 100644 --- a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml +++ b/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null autoscaling: enabled: true admissionWebhooks: diff --git a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml b/charts/ingress-nginx/ci/deployment-customconfig-values.yaml index f232531acb1..85715ddb762 100644 --- a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml +++ b/charts/ingress-nginx/ci/deployment-customconfig-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null config: use-proxy-protocol: "true" admissionWebhooks: diff --git a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml b/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml index 9eda282b138..a564eaf9315 100644 --- a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml +++ b/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deployment-default-values.yaml b/charts/ingress-nginx/ci/deployment-default-values.yaml index 93a393c9752..9f46b4e7e9c 100644 --- a/charts/ingress-nginx/ci/deployment-default-values.yaml +++ b/charts/ingress-nginx/ci/deployment-default-values.yaml @@ -1,4 +1,8 @@ # Left blank to test default values controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null service: type: ClusterIP diff --git a/charts/ingress-nginx/ci/deployment-headers-values.yaml b/charts/ingress-nginx/ci/deployment-headers-values.yaml index 665fd48d356..17a11ac370c 100644 --- a/charts/ingress-nginx/ci/deployment-headers-values.yaml +++ b/charts/ingress-nginx/ci/deployment-headers-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false addHeaders: diff --git a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml b/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml index 892f6de3f05..8b2eb78bf15 100644 --- a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml +++ b/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deployment-metrics-values.yaml b/charts/ingress-nginx/ci/deployment-metrics-values.yaml index 887ed0f620c..9209ad5a6f6 100644 --- a/charts/ingress-nginx/ci/deployment-metrics-values.yaml +++ b/charts/ingress-nginx/ci/deployment-metrics-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false metrics: diff --git a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml b/charts/ingress-nginx/ci/deployment-nodeport-values.yaml index 84f1f7582e7..cd9b323528e 100644 --- a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml +++ b/charts/ingress-nginx/ci/deployment-nodeport-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml b/charts/ingress-nginx/ci/deployment-podannotations-values.yaml index b65a0910b35..b48d93c46ad 100644 --- a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml +++ b/charts/ingress-nginx/ci/deployment-podannotations-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false metrics: diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/deployment-psp-values.yaml index e339c69c329..2f332a7b201 100644 --- a/charts/ingress-nginx/ci/deployment-psp-values.yaml +++ b/charts/ingress-nginx/ci/deployment-psp-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null service: type: ClusterIP diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml index 141e06b6875..c51a4e91fa7 100644 --- a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml +++ b/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml index bc29abeba72..5b45b69dcc4 100644 --- a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml +++ b/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: false service: diff --git a/charts/ingress-nginx/ci/deployment-tcp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-values.yaml index b7f54c09fac..ac0b6e60eb7 100644 --- a/charts/ingress-nginx/ci/deployment-tcp-values.yaml +++ b/charts/ingress-nginx/ci/deployment-tcp-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null service: type: ClusterIP diff --git a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml index a829c36144f..6195bb33915 100644 --- a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml +++ b/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: true service: diff --git a/charts/ingress-nginx/ci/deployment-webhook-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-values.yaml index 4f18a70b9ff..76669a53006 100644 --- a/charts/ingress-nginx/ci/deployment-webhook-values.yaml +++ b/charts/ingress-nginx/ci/deployment-webhook-values.yaml @@ -1,4 +1,8 @@ controller: + image: + repository: ingress-controller/controller + tag: 1.0.0-dev + digest: null admissionWebhooks: enabled: true service: diff --git a/charts/ingress-nginx/templates/clusterrole.yaml b/charts/ingress-nginx/templates/clusterrole.yaml index a2dec16836e..95b7fec0852 100644 --- a/charts/ingress-nginx/templates/clusterrole.yaml +++ b/charts/ingress-nginx/templates/clusterrole.yaml @@ -42,7 +42,7 @@ rules: - list - watch - apiGroups: - - "networking.k8s.io" # k8s 1.14+ + - networking.k8s.io resources: - ingresses verbs: @@ -57,13 +57,13 @@ rules: - create - patch - apiGroups: - - "networking.k8s.io" # k8s 1.14+ + - networking.k8s.io resources: - ingresses/status verbs: - update - apiGroups: - - networking.k8s.io # k8s 1.14+ + - networking.k8s.io resources: - ingressclasses verbs: diff --git a/charts/ingress-nginx/templates/controller-ingressclass.yaml b/charts/ingress-nginx/templates/controller-ingressclass.yaml index cb625d7fd8d..9492784a280 100644 --- a/charts/ingress-nginx/templates/controller-ingressclass.yaml +++ b/charts/ingress-nginx/templates/controller-ingressclass.yaml @@ -10,7 +10,7 @@ metadata: {{- with .Values.controller.labels }} {{- toYaml . | nindent 4 }} {{- end }} - name: {{ .Values.controller.ingressClass }} + name: {{ .Values.controller.ingressClassResource.name }} {{- if .Values.controller.ingressClassResource.default }} annotations: ingressclass.kubernetes.io/is-default-class: "true" @@ -18,35 +18,4 @@ metadata: spec: controller: {{ .Values.controller.ingressClassResource.controllerValue }} {{ template "ingressClass.parameters" . }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - {{- include "ingress-nginx.labels" . | nindent 4 }} - name: {{ include "ingress-nginx.ingressclassclrole.fullname" . }} -rules: - - apiGroups: - - networking.k8s.io - resources: - - ingressclasses - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - {{- include "ingress-nginx.labels" . | nindent 4 }} - name: {{ include "ingress-nginx.ingressclassclrole.fullname" . }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "ingress-nginx.ingressclassclrole.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ template "ingress-nginx.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} {{- end }} diff --git a/charts/ingress-nginx/templates/controller-role.yaml b/charts/ingress-nginx/templates/controller-role.yaml index dd58b213b16..97c627dacb1 100644 --- a/charts/ingress-nginx/templates/controller-role.yaml +++ b/charts/ingress-nginx/templates/controller-role.yaml @@ -34,7 +34,7 @@ rules: - list - watch - apiGroups: - - "networking.k8s.io" + - networking.k8s.io resources: - ingresses verbs: @@ -42,13 +42,13 @@ rules: - list - watch - apiGroups: - - "networking.k8s.io" + - networking.k8s.io resources: - ingresses/status verbs: - update - apiGroups: - - "networking.k8s.io" + - networking.k8s.io resources: - ingressclasses verbs: diff --git a/charts/ingress-nginx/values.yaml b/charts/ingress-nginx/values.yaml index 043320daaa7..4c048422705 100644 --- a/charts/ingress-nginx/values.yaml +++ b/charts/ingress-nginx/values.yaml @@ -76,13 +76,10 @@ controller: ## electionID: ingress-controller-leader - ## Name of the ingress class to route through this controller - ## - ingressClass: nginx - # This section refers to the creation of the IngressClass resource - # IngressClass resources are supported since k8s >= 1.18 + # IngressClass resources are supported since k8s >= 1.18 and required since k8s >= 1.19 ingressClassResource: + name: nginx enabled: true default: false controllerValue: "k8s.io/ingress-nginx" diff --git a/internal/ingress/controller/store/store.go b/internal/ingress/controller/store/store.go index a290b31bec3..39ba29abd9c 100644 --- a/internal/ingress/controller/store/store.go +++ b/internal/ingress/controller/store/store.go @@ -331,14 +331,12 @@ func New( } } - ic, err := store.GetIngressClass(ing, icConfig) + _, err := store.GetIngressClass(ing, icConfig) if err != nil { klog.InfoS("Ignoring ingress because of error while validating ingress class", "ingress", klog.KObj(ing), "error", err) return } - klog.InfoS("Found valid IngressClass", "ingress", klog.KObj(ing), "ingressclass", ic) - if hasCatchAllIngressRule(ing.Spec) && disableCatchAll { klog.InfoS("Ignoring delete for catch-all because of --disable-catch-all", "ingress", klog.KObj(ing)) return @@ -388,7 +386,7 @@ func New( curIng, _ := toIngress(cur) _, errOld := store.GetIngressClass(oldIng, icConfig) - classCur, errCur := store.GetIngressClass(oldIng, icConfig) + classCur, errCur := store.GetIngressClass(curIng, icConfig) if errOld != nil && errCur == nil { if hasCatchAllIngressRule(curIng.Spec) && disableCatchAll { klog.InfoS("ignoring update for catch-all ingress because of --disable-catch-all", "ingress", klog.KObj(curIng)) diff --git a/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml b/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml index c79154d289e..4fef671a764 100644 --- a/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml +++ b/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml @@ -14,7 +14,9 @@ controller: https-port: "1443" # e2e tests do not require information about ingress status update-status: "false" - + ingressClassResource: + # We will create and remove each IC/ClusterRole/ClusterRoleBinding per test so there's no conflict + enabled: false scope: enabled: true diff --git a/test/e2e/admission/admission.go b/test/e2e/admission/admission.go index 71b86200d6b..121d0d37aa0 100644 --- a/test/e2e/admission/admission.go +++ b/test/e2e/admission/admission.go @@ -121,11 +121,7 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() { assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid configuration should return an error") }) - ginkgo.It("should not return an error if the Ingress V1 definition is valid", func() { - if !f.IsIngressV1Ready { - ginkgo.Skip("Test requires Kubernetes v1.19 or higher") - } - + ginkgo.It("should not return an error if the Ingress V1 definition is valid with Ingress Class", func() { err := createIngress(f.Namespace, validV1Ingress) assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl") @@ -140,15 +136,26 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() { Status(http.StatusOK) }) - ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() { - if !f.IsIngressV1Ready { - ginkgo.Skip("Test requires Kubernetes v1.19 or higher") - } + ginkgo.It("should not return an error if the Ingress V1 definition is valid with IngressClass annotation", func() { + err := createIngress(f.Namespace, validV1IngressAnnotation) + assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl") + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "extensions-class") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", "extensions-class"). + Expect(). + Status(http.StatusOK) + }) + ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() { err := createIngress(f.Namespace, invalidV1Ingress) assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl") - _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), "extensions", metav1.GetOptions{}) + _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), "extensions-invalid", metav1.GetOptions{}) if !apierrors.IsNotFound(err) { assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid configuration should return an error") } @@ -172,6 +179,7 @@ kind: Ingress metadata: name: extensions spec: + ingressClassName: nginx rules: - host: extensions http: @@ -184,6 +192,28 @@ spec: port: number: 80 +--- +` + validV1IngressAnnotation = ` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: extensions-class + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: extensions-class + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: echo + port: + number: 80 + --- ` @@ -191,13 +221,14 @@ spec: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: extensions + name: extensions-invalid annotations: nginx.ingress.kubernetes.io/configuration-snippet: | invalid directive spec: + ingressClassName: nginx rules: - - host: extensions + - host: extensions-invalid http: paths: - path: / diff --git a/test/e2e/annotations/affinity.go b/test/e2e/annotations/affinity.go index 04177f03141..998eca82f72 100644 --- a/test/e2e/annotations/affinity.go +++ b/test/e2e/annotations/affinity.go @@ -131,7 +131,7 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() { Annotations: annotations, }, Spec: networking.IngressSpec{ - IngressClassName: &f.Namespace, + IngressClassName: &f.IngressClass, Rules: []networking.IngressRule{ { Host: host, diff --git a/test/e2e/annotations/canary.go b/test/e2e/annotations/canary.go index b452ef3b0e8..fe3e1544f6b 100644 --- a/test/e2e/annotations/canary.go +++ b/test/e2e/annotations/canary.go @@ -22,9 +22,7 @@ import ( "strings" "github.com/onsi/ginkgo" - "github.com/stretchr/testify/assert" - networking "k8s.io/api/networking/v1" "k8s.io/ingress-nginx/test/e2e/framework" ) @@ -32,7 +30,7 @@ const ( canaryService = "echo-canary" ) -var _ = framework.DescribeAnnotation("canary-*", func() { +var _ = framework.DescribeAnnotation("canary", func() { f := framework.NewDefaultFramework("canary") ginkgo.BeforeEach(func() { @@ -327,15 +325,25 @@ var _ = framework.DescribeAnnotation("canary-*", func() { f.Namespace, canaryService, 80, canaryAnnotations) f.EnsureIngress(canaryIng) - err := framework.UpdateIngress(f.KubeClientSet, f.Namespace, canaryIngName, - func(ingress *networking.Ingress) error { - ingress.ObjectMeta.Annotations = map[string]string{ - "nginx.ingress.kubernetes.io/canary": "true", - "nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader2", - } - return nil + f.WaitForNginxServer(host, + func(server string) bool { + return strings.Contains(server, "server_name foo") + }) + + newAnnotations := map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader2", + } + + modIng := framework.NewSingleIngress(canaryIngName, "/", host, + f.Namespace, canaryService, 80, newAnnotations) + + f.UpdateIngress(modIng) + + f.WaitForNginxServer(host, + func(server string) bool { + return strings.Contains(server, "server_name foo") }) - assert.Nil(ginkgo.GinkgoT(), err) ginkgo.By("routing requests destined for the mainline ingress to the mainline upstream") f.HTTPTestClient(). @@ -707,6 +715,11 @@ var _ = framework.DescribeAnnotation("canary-*", func() { f.Namespace, canaryService, 80, canaryAnnotations) f.EnsureIngress(canaryIng) + f.WaitForNginxServer(host, + func(server string) bool { + return strings.Contains(server, "server_name foo") + }) + ginkgo.By("returning requests from the mainline only when weight is equal to 0") f.HTTPTestClient(). GET("/"). @@ -719,15 +732,20 @@ var _ = framework.DescribeAnnotation("canary-*", func() { ginkgo.By("returning requests from the canary only when weight is equal to 100") - err := framework.UpdateIngress(f.KubeClientSet, f.Namespace, canaryIngName, - func(ingress *networking.Ingress) error { - ingress.ObjectMeta.Annotations = map[string]string{ - "nginx.ingress.kubernetes.io/canary": "true", - "nginx.ingress.kubernetes.io/canary-weight": "100", - } - return nil + newAnnotations := map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "100", + } + + modIng := framework.NewSingleIngress(canaryIngName, "/", host, + f.Namespace, canaryService, 80, newAnnotations) + + f.UpdateIngress(modIng) + + f.WaitForNginxServer(host, + func(server string) bool { + return strings.Contains(server, "server_name foo") }) - assert.Nil(ginkgo.GinkgoT(), err) f.HTTPTestClient(). GET("/"). diff --git a/test/e2e/defaultbackend/with_hosts.go b/test/e2e/defaultbackend/with_hosts.go index 6962e7be5e6..c59b5807b9f 100644 --- a/test/e2e/defaultbackend/with_hosts.go +++ b/test/e2e/defaultbackend/with_hosts.go @@ -47,7 +47,7 @@ var _ = framework.IngressNginxDescribe("[Default Backend] change default setting Annotations: annotations, }, Spec: networking.IngressSpec{ - IngressClassName: &f.Namespace, + IngressClassName: &f.IngressClass, DefaultBackend: &networking.IngressBackend{ Service: &networking.IngressServiceBackend{ Name: framework.EchoService, diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 76bc7c30226..e31fd1e4ee3 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -68,7 +68,8 @@ type Framework struct { KubeConfig *restclient.Config APIExtensionsClientSet apiextcs.Interface - Namespace string + Namespace string + IngressClass string pod *corev1.Pod } @@ -108,6 +109,9 @@ func (f *Framework) BeforeEach() { f.Namespace, err = CreateKubeNamespace(f.BaseName, f.KubeClientSet) assert.Nil(ginkgo.GinkgoT(), err, "creating namespace") + f.IngressClass, err = CreateIngressClass(f.Namespace, f.KubeClientSet) + assert.Nil(ginkgo.GinkgoT(), err, "creating IngressClass") + err = f.newIngressController(f.Namespace, f.BaseName) assert.Nil(ginkgo.GinkgoT(), err, "deploying the ingress controller") @@ -127,6 +131,14 @@ func (f *Framework) AfterEach() { }() }(f.KubeClientSet, f.Namespace) + defer func(kubeClient kubernetes.Interface, ingressclass string) { + go func() { + defer ginkgo.GinkgoRecover() + err := deleteIngressClass(kubeClient, ingressclass) + assert.Nil(ginkgo.GinkgoT(), err, "deleting IngressClass") + }() + }(f.KubeClientSet, f.IngressClass) + if !ginkgo.CurrentGinkgoTestDescription().Failed { return } @@ -580,7 +592,7 @@ func NewSingleIngress(name, path, host, ns, service string, port int, annotation func NewSingleIngressWithMultiplePaths(name string, paths []string, host, ns, service string, port int, annotations map[string]string) *networking.Ingress { pathtype := networking.PathTypePrefix spec := networking.IngressSpec{ - IngressClassName: &ns, + IngressClassName: GetIngressClassName(ns), Rules: []networking.IngressRule{ { Host: host, @@ -612,7 +624,7 @@ func NewSingleIngressWithMultiplePaths(name string, paths []string, host, ns, se func newSingleIngressWithRules(name, path, host, ns, service string, port int, annotations map[string]string, tlsHosts []string) *networking.Ingress { pathtype := networking.PathTypePrefix spec := networking.IngressSpec{ - IngressClassName: &ns, + IngressClassName: GetIngressClassName(ns), Rules: []networking.IngressRule{ { IngressRuleValue: networking.IngressRuleValue{ @@ -658,7 +670,7 @@ func newSingleIngressWithRules(name, path, host, ns, service string, port int, a func NewSingleIngressWithBackendAndRules(name, path, host, ns, defaultService string, defaultPort int, service string, port int, annotations map[string]string) *networking.Ingress { pathtype := networking.PathTypePrefix spec := networking.IngressSpec{ - IngressClassName: &ns, + IngressClassName: GetIngressClassName(ns), DefaultBackend: &networking.IngressBackend{ Service: &networking.IngressServiceBackend{ Name: defaultService, @@ -698,7 +710,7 @@ func NewSingleIngressWithBackendAndRules(name, path, host, ns, defaultService st // NewSingleCatchAllIngress creates a simple ingress with a catch-all backend func NewSingleCatchAllIngress(name, ns, service string, port int, annotations map[string]string) *networking.Ingress { spec := networking.IngressSpec{ - IngressClassName: &ns, + IngressClassName: GetIngressClassName(ns), DefaultBackend: &networking.IngressBackend{ Service: &networking.IngressServiceBackend{ Name: service, diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index b0fa92b153a..75fcb58ea4e 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -24,6 +24,8 @@ import ( "github.com/onsi/ginkgo" corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" @@ -31,6 +33,8 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" + + "k8s.io/ingress-nginx/internal/k8s" ) const ( @@ -117,6 +121,93 @@ func deleteKubeNamespace(c kubernetes.Interface, namespace string) error { }) } +// CreateIngressClass creates a new IngressClass related to a test/namespace and also +// the required ClusterRole/ClusterRoleBinding +func CreateIngressClass(namespace string, c kubernetes.Interface) (string, error) { + icname := fmt.Sprintf("ic-%s", namespace) + var err error + + ic, err := c.NetworkingV1().IngressClasses(). + Create(context.TODO(), &networkingv1.IngressClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: icname, + }, + Spec: networkingv1.IngressClassSpec{ + Controller: k8s.IngressNGINXController, + }, + }, metav1.CreateOptions{}) + if err != nil { + return "", fmt.Errorf("Unexpected error creating IngressClass %s: %v", icname, err) + } + + _, err = c.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{Name: icname}, + Rules: []rbacv1.PolicyRule{{ + APIGroups: []string{"networking.k8s.io"}, + Resources: []string{"ingressclasses"}, + Verbs: []string{"get", "list", "watch"}, + }}, + }, metav1.CreateOptions{}) + if err != nil { + return "", fmt.Errorf("Unexpected error creating IngressClass ClusterRole %s: %v", icname, err) + } + + _, err = c.RbacV1().ClusterRoleBindings().Create(context.TODO(), &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: icname, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: icname, + }, + Subjects: []rbacv1.Subject{ + { + APIGroup: "", + Kind: "ServiceAccount", + Namespace: namespace, + Name: "nginx-ingress", + }, + }, + }, metav1.CreateOptions{}) + if err != nil { + return "", fmt.Errorf("Unexpected error creating IngressClass ClusterRoleBinding %s: %v", icname, err) + } + return ic.Name, nil +} + +//deleteIngressClass deletes an IngressClass and its related ClusterRole* objects +func deleteIngressClass(c kubernetes.Interface, ingressclass string) error { + var err error + grace := int64(0) + pb := metav1.DeletePropagationBackground + deleteOptions := metav1.DeleteOptions{ + GracePeriodSeconds: &grace, + PropagationPolicy: &pb, + } + err = c.NetworkingV1().IngressClasses().Delete(context.TODO(), ingressclass, deleteOptions) + if err != nil { + return fmt.Errorf("Unexpected error deleting IngressClass %s: %v", ingressclass, err) + } + + err = c.RbacV1().ClusterRoleBindings().Delete(context.TODO(), ingressclass, deleteOptions) + if err != nil { + return fmt.Errorf("Unexpected error deleting IngressClass ClusterRoleBinding %s: %v", ingressclass, err) + } + err = c.RbacV1().ClusterRoles().Delete(context.TODO(), ingressclass, deleteOptions) + if err != nil { + return fmt.Errorf("Unexpected error deleting IngressClass ClusterRole %s: %v", ingressclass, err) + } + + return nil +} + +//GetIngressClassName returns the default IngressClassName given a namespace +func GetIngressClassName(namespace string) *string { + icname := fmt.Sprintf("ic-%s", namespace) + return &icname +} + // WaitForKubeNamespaceNotExist waits until a namespaces is not present in the cluster func WaitForKubeNamespaceNotExist(c kubernetes.Interface, namespace string) error { return wait.Poll(Poll, DefaultTimeout, namespaceNotExist(c, namespace)) diff --git a/test/e2e/ingress/without_host.go b/test/e2e/ingress/without_host.go index 6cfc41e502c..c0c2d3b12e7 100644 --- a/test/e2e/ingress/without_host.go +++ b/test/e2e/ingress/without_host.go @@ -61,7 +61,7 @@ var _ = framework.IngressNginxDescribe("[Ingress] definition without host", func Namespace: f.Namespace, }, Spec: networking.IngressSpec{ - IngressClassName: &f.Namespace, + IngressClassName: &f.IngressClass, DefaultBackend: &networking.IngressBackend{ Service: &networking.IngressServiceBackend{ Name: framework.EchoService, diff --git a/test/e2e/run-chart-test.sh b/test/e2e/run-chart-test.sh index 841c05e7df9..8ff224f957d 100755 --- a/test/e2e/run-chart-test.sh +++ b/test/e2e/run-chart-test.sh @@ -50,7 +50,7 @@ export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}" if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then echo "[dev-env] creating Kubernetes cluster with kind" - export K8S_VERSION=${K8S_VERSION:-v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab} + export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6} kind create cluster \ --verbosity=${KIND_LOG_LEVEL} \ @@ -61,7 +61,25 @@ if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then echo "Kubernetes cluster:" kubectl get nodes -o wide + +fi + +if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then + export TAG=1.0.0-dev + export ARCH=${ARCH:-amd64} + export REGISTRY=ingress-controller + if ! command -v ginkgo &> /dev/null; then + go get github.com/onsi/ginkgo/ginkgo + fi + echo "[dev-env] building image" + make -C ${DIR}/../../ clean-image build image fi + + +KIND_WORKERS=$(kind get nodes --name="${KIND_CLUSTER_NAME}" | grep worker | awk '{printf (NR>1?",":"") $1}') +echo "[dev-env] copying docker images to cluster..." + +kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} ${REGISTRY}/controller:${TAG} echo "[dev-env] running helm chart e2e tests..." # Uses a custom chart-testing image to avoid timeouts waiting for namespace deletion. diff --git a/test/e2e/servicebackend/service_backend.go b/test/e2e/servicebackend/service_backend.go index bff819dc590..0467e434e34 100644 --- a/test/e2e/servicebackend/service_backend.go +++ b/test/e2e/servicebackend/service_backend.go @@ -80,7 +80,7 @@ func buildIngressWithNonexistentService(host, namespace, path string) *networkin Namespace: namespace, }, Spec: networking.IngressSpec{ - IngressClassName: &namespace, + IngressClassName: framework.GetIngressClassName(namespace), Rules: []networking.IngressRule{ { Host: host, @@ -116,7 +116,7 @@ func buildIngressWithUnavailableServiceEndpoints(host, namespace, path string) ( Namespace: namespace, }, Spec: networking.IngressSpec{ - IngressClassName: &namespace, + IngressClassName: framework.GetIngressClassName(namespace), Rules: []networking.IngressRule{ { Host: host, diff --git a/test/e2e/servicebackend/service_externalname.go b/test/e2e/servicebackend/service_externalname.go index 437b35144bb..2c33c020f37 100644 --- a/test/e2e/servicebackend/service_externalname.go +++ b/test/e2e/servicebackend/service_externalname.go @@ -25,7 +25,6 @@ import ( "github.com/gavv/httpexpect/v2" "github.com/onsi/ginkgo" "github.com/stretchr/testify/assert" - core "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,7 +42,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -74,7 +73,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should return 200 for service type=ExternalName without a port defined", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -108,7 +107,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should return 200 for service type=ExternalName with a port defined", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -149,7 +148,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should return status 502 for service type=ExternalName with an invalid host", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -180,7 +179,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should return 200 for service type=ExternalName using a port name", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -230,7 +229,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should return 200 for service type=ExternalName using FQDN with trailing dot", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, @@ -261,7 +260,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() { ginkgo.It("should update the external name after a service update", func() { host := "echo" - svc := &core.Service{ + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: framework.HTTPBinService, Namespace: f.Namespace, diff --git a/test/e2e/settings/ingress_class.disabled b/test/e2e/settings/ingress_class.disabled deleted file mode 100644 index 2aa95a87f53..00000000000 --- a/test/e2e/settings/ingress_class.disabled +++ /dev/null @@ -1,334 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package settings - -import ( - "context" - "fmt" - "net/http" - "strings" - "sync" - - "github.com/onsi/ginkgo" - "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" - networking "k8s.io/api/networking/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "k8s.io/ingress-nginx/internal/ingress/controller/class" - "k8s.io/ingress-nginx/internal/k8s" - "k8s.io/ingress-nginx/test/e2e/framework" -) - -var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() { - f := framework.NewDefaultFramework("ingress-class") - - var doOnce sync.Once - - testIngressClassName := "test-new-ingress-class" - - ginkgo.BeforeEach(func() { - f.NewEchoDeploymentWithReplicas(1) - - doOnce.Do(func() { - f.KubeClientSet.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{Name: "ingress-nginx-class"}, - Rules: []rbacv1.PolicyRule{{ - APIGroups: []string{"networking.k8s.io"}, - Resources: []string{"ingressclasses"}, - Verbs: []string{"get", "list", "watch"}, - }}, - }, metav1.CreateOptions{}) - - f.KubeClientSet.RbacV1().ClusterRoleBindings().Create(context.TODO(), &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ingress-nginx-class", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: "ingress-nginx-class", - }, - }, metav1.CreateOptions{}) - - _, err := f.KubeClientSet.NetworkingV1().IngressClasses(). - Create(context.TODO(), &networking.IngressClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: testIngressClassName, - }, - Spec: networking.IngressClassSpec{ - Controller: k8s.IngressNGINXController, - }, - }, metav1.CreateOptions{}) - - if !apierrors.IsAlreadyExists(err) { - assert.Nil(ginkgo.GinkgoT(), err, "creating IngressClass") - } - }) - }) - - ginkgo.Context("Without a specific ingress-class", func() { - ginkgo.It("should ignore Ingress with class", func() { - invalidHost := "foo" - annotations := map[string]string{ - class.IngressKey: "testclass", - } - ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - validHost := "bar" - ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing) - - f.WaitForNginxConfiguration(func(cfg string) bool { - return !strings.Contains(cfg, "server_name foo") && - strings.Contains(cfg, "server_name bar") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", invalidHost). - Expect(). - Status(http.StatusNotFound) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", validHost). - Expect(). - Status(http.StatusOK) - }) - }) - - ginkgo.Context("With a specific ingress-class", func() { - ginkgo.BeforeEach(func() { - err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { - args := []string{} - for _, v := range deployment.Spec.Template.Spec.Containers[0].Args { - if strings.Contains(v, "--ingress-class") { - continue - } - - args = append(args, v) - } - - args = append(args, "--ingress-class=testclass") - deployment.Spec.Template.Spec.Containers[0].Args = args - _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) - - return err - }) - assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags") - }) - - ginkgo.It("should ignore Ingress with no class", func() { - invalidHost := "bar" - - ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing) - - validHost := "foo" - annotations := map[string]string{ - class.IngressKey: "testclass", - } - ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(validHost, func(cfg string) bool { - return strings.Contains(cfg, "server_name foo") - }) - - f.WaitForNginxConfiguration(func(cfg string) bool { - return !strings.Contains(cfg, "server_name bar") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", validHost). - Expect(). - Status(http.StatusOK) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", invalidHost). - Expect(). - Status(http.StatusNotFound) - }) - - ginkgo.It("should delete Ingress when class is removed", func() { - host := "foo" - annotations := map[string]string{ - class.IngressKey: "testclass", - } - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(host, func(cfg string) bool { - return strings.Contains(cfg, "server_name foo") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusOK) - - ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - delete(ing.Annotations, class.IngressKey) - _, err = f.KubeClientSet.NetworkingV1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - framework.Sleep() - - f.WaitForNginxConfiguration(func(cfg string) bool { - return !strings.Contains(cfg, "server_name foo") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusNotFound) - }) - }) - - ginkgo.It("check scenarios for IngressClass and ingress.class annotation", func() { - - pod := f.GetIngressNGINXPod() - - crb, err := f.KubeClientSet.RbacV1().ClusterRoleBindings().Get(context.Background(), "ingress-nginx-class", metav1.GetOptions{}) - assert.Nil(ginkgo.GinkgoT(), err, "searching cluster role binding") - - // add service of current namespace - crb.Subjects = append(crb.Subjects, rbacv1.Subject{ - APIGroup: "", - Kind: "ServiceAccount", - Name: pod.Spec.ServiceAccountName, - Namespace: f.Namespace, - }) - - _, err = f.KubeClientSet.RbacV1().ClusterRoleBindings().Update(context.Background(), crb, metav1.UpdateOptions{}) - assert.Nil(ginkgo.GinkgoT(), err, "searching cluster role binding") - - err = f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { - args := []string{} - for _, v := range deployment.Spec.Template.Spec.Containers[0].Args { - if strings.Contains(v, "--ingress-class") { - continue - } - - args = append(args, v) - } - - args = append(args, fmt.Sprintf("--ingress-class=%v", testIngressClassName)) - deployment.Spec.Template.Spec.Containers[0].Args = args - _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) - return err - }) - assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags") - - host := "ingress.class" - - ginkgo.By("only having IngressClassName") - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil) - ing.Spec.IngressClassName = &testIngressClassName - f.EnsureIngress(ing) - - f.WaitForNginxConfiguration(func(cfg string) bool { - return strings.Contains(cfg, fmt.Sprintf("server_name %v", host)) - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusOK) - - ginkgo.By("only having ingress.class annotation") - ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - ing.Annotations = map[string]string{ - class.IngressKey: testIngressClassName, - } - ing.Spec.IngressClassName = nil - - _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - f.WaitForNginxConfiguration(func(cfg string) bool { - return strings.Contains(cfg, fmt.Sprintf("server_name %v", host)) - }) - - framework.Sleep() - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusOK) - - ginkgo.By("having an invalid ingress.class annotation and no IngressClassName") - ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - ing.Annotations = map[string]string{ - class.IngressKey: "invalid", - } - ing.Spec.IngressClassName = nil - - _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - framework.Sleep() - - f.WaitForNginxConfiguration(func(cfg string) bool { - return !strings.Contains(cfg, fmt.Sprintf("server_name %v", host)) - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusNotFound) - - ginkgo.By("not having ingress.class annotation and invalid IngressClassName") - ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - ing.Annotations = map[string]string{} - invalidClassName := "invalidclass" - ing.Spec.IngressClassName = &invalidClassName - - _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) - assert.Nil(ginkgo.GinkgoT(), err) - - framework.Sleep() - - f.WaitForNginxConfiguration(func(cfg string) bool { - return !strings.Contains(cfg, fmt.Sprintf("server_name %v", host)) - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusNotFound) - }) -}) diff --git a/test/e2e/settings/ingress_class.go b/test/e2e/settings/ingress_class.go new file mode 100644 index 00000000000..3ba42f3113f --- /dev/null +++ b/test/e2e/settings/ingress_class.go @@ -0,0 +1,513 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package settings + +import ( + "context" + "net/http" + "strings" + "sync" + + "github.com/onsi/ginkgo" + "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" + networkingv1 "k8s.io/api/networking/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/ingress-nginx/internal/ingress/controller/ingressclass" + "k8s.io/ingress-nginx/test/e2e/framework" +) + +var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() { + f := framework.NewDefaultFramework("ingress-class") + + var doOnce sync.Once + + otherIngressClassName := "test-new-ingress-class" + otherController := "k8s.io/other-class" + + ginkgo.BeforeEach(func() { + f.NewEchoDeploymentWithReplicas(1) + + doOnce.Do(func() { + _, err := f.KubeClientSet.NetworkingV1().IngressClasses(). + Create(context.TODO(), &networkingv1.IngressClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherIngressClassName, + }, + Spec: networkingv1.IngressClassSpec{ + Controller: otherController, + }, + }, metav1.CreateOptions{}) + + if !apierrors.IsAlreadyExists(err) { + assert.Nil(ginkgo.GinkgoT(), err, "creating IngressClass") + } + }) + }) + + ginkgo.Context("With default ingress class config", func() { + ginkgo.It("should ignore Ingress with a different class annotation", func() { + invalidHost := "foo" + annotations := map[string]string{ + ingressclass.IngressKey: "testclass", + } + ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, annotations) + // We should drop the ingressClassName here as we just want to rely on the annotation in this test + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + validHost := "bar" + annotationClass := map[string]string{ + ingressclass.IngressKey: ingressclass.DefaultAnnotationValue, + } + ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotationClass) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name foo") && + strings.Contains(cfg, "server_name bar") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", invalidHost). + Expect(). + Status(http.StatusNotFound) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHost). + Expect(). + Status(http.StatusOK) + }) + + ginkgo.It("should ignore Ingress with different controller class", func() { + invalidHost := "foo-1" + ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = &otherIngressClassName + f.EnsureIngress(ing) + + validHost := "bar-1" + ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil) + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name foo-1") && + strings.Contains(cfg, "server_name bar-1") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", invalidHost). + Expect(). + Status(http.StatusNotFound) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHost). + Expect(). + Status(http.StatusOK) + }) + + ginkgo.It("should accept both Ingresses with default IngressClassName and IngressClass annotation", func() { + validHostAnnotation := "foo-ok" + annotationClass := map[string]string{ + ingressclass.IngressKey: ingressclass.DefaultAnnotationValue, + } + ing := framework.NewSingleIngress(validHostAnnotation, "/", validHostAnnotation, f.Namespace, framework.EchoService, 80, annotationClass) + // We need to drop the Class here as we just want the annotation + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + validHostClass := "bar-ok" + ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil) + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name foo-ok") && + strings.Contains(cfg, "server_name bar-ok") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHostAnnotation). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHostClass). + Expect(). + Status(http.StatusOK) + }) + + ginkgo.It("should ignore Ingress without IngressClass configuration", func() { + invalidHost := "foo-invalid" + ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + validHostClass := "bar-valid" + ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil) + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name foo-invalid") && + strings.Contains(cfg, "server_name bar-valid") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", invalidHost). + Expect(). + Status(http.StatusNotFound) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHostClass). + Expect(). + Status(http.StatusOK) + }) + + ginkgo.It("should delete Ingress when class is removed", func() { + hostAnnotation := "foo-annotation" + + annotations := map[string]string{ + ingressclass.IngressKey: ingressclass.DefaultAnnotationValue, + } + ing := framework.NewSingleIngress(hostAnnotation, "/", hostAnnotation, f.Namespace, framework.EchoService, 80, annotations) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + hostClass := "foo-class" + ing = framework.NewSingleIngress(hostClass, "/", hostClass, f.Namespace, framework.EchoService, 80, nil) + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name foo-annotation") && + strings.Contains(cfg, "server_name foo-class") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostAnnotation). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostClass). + Expect(). + Status(http.StatusOK) + + ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostAnnotation, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + delete(ing.Annotations, ingressclass.IngressKey) + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingWithClass, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostClass, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingWithClass.Spec.IngressClassName = nil + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ingWithClass.Namespace).Update(context.TODO(), ingWithClass, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + framework.Sleep() + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name foo-annotation") && + !strings.Contains(cfg, "server_name foo-class") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostAnnotation). + Expect(). + Status(http.StatusNotFound) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostClass). + Expect(). + Status(http.StatusNotFound) + }) + + ginkgo.It("should serve Ingress when class is added", func() { + hostNoAnnotation := "foo-no-annotation" + + ing := framework.NewSingleIngress(hostNoAnnotation, "/", hostNoAnnotation, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + hostNoClass := "foo-no-class" + ing = framework.NewSingleIngress(hostNoClass, "/", hostNoClass, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name foo-no-nnotation") && + !strings.Contains(cfg, "server_name foo-no-class") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostNoAnnotation). + Expect(). + Status(http.StatusNotFound) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostNoClass). + Expect(). + Status(http.StatusNotFound) + + ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostNoAnnotation, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + annotation := map[string]string{ + ingressclass.IngressKey: ingressclass.DefaultAnnotationValue, + } + ing.Annotations = annotation + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingWithClass, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostNoClass, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingWithClass.Spec.IngressClassName = framework.GetIngressClassName(f.Namespace) + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ingWithClass.Namespace).Update(context.TODO(), ingWithClass, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + framework.Sleep() + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name foo-no-annotation") && + strings.Contains(cfg, "server_name foo-no-class") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostNoAnnotation). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostNoClass). + Expect(). + Status(http.StatusOK) + }) + + ginkgo.It("should serve Ingress when class is updated between annotation and ingressClassName", func() { + hostAnnotation2class := "foo-annotation2class" + annotationClass := map[string]string{ + ingressclass.IngressKey: ingressclass.DefaultAnnotationValue, + } + ing := framework.NewSingleIngress(hostAnnotation2class, "/", hostAnnotation2class, f.Namespace, framework.EchoService, 80, annotationClass) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + hostClass2Annotation := "foo-class2annotation" + ing = framework.NewSingleIngress(hostClass2Annotation, "/", hostClass2Annotation, f.Namespace, framework.EchoService, 80, nil) + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name foo-annotation2class") && + strings.Contains(cfg, "server_name foo-class2annotation") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostAnnotation2class). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostClass2Annotation). + Expect(). + Status(http.StatusOK) + + ingAnnotation2Class, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostAnnotation2class, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + delete(ingAnnotation2Class.Annotations, ingressclass.IngressKey) + ingAnnotation2Class.Spec.IngressClassName = framework.GetIngressClassName(ingAnnotation2Class.Namespace) + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ingAnnotation2Class.Namespace).Update(context.TODO(), ingAnnotation2Class, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingClass2Annotation, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostClass2Annotation, metav1.GetOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + ingClass2Annotation.Spec.IngressClassName = nil + ingClass2Annotation.Annotations = annotationClass + _, err = f.KubeClientSet.NetworkingV1().Ingresses(ingClass2Annotation.Namespace).Update(context.TODO(), ingClass2Annotation, metav1.UpdateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err) + + framework.Sleep() + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name foo-annotation2class") && + strings.Contains(cfg, "server_name foo-class2annotation") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostAnnotation2class). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", hostClass2Annotation). + Expect(). + Status(http.StatusOK) + }) + + }) + + ginkgo.Context("With specific ingress-class flags", func() { + ginkgo.BeforeEach(func() { + err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { + args := []string{} + for _, v := range deployment.Spec.Template.Spec.Containers[0].Args { + if strings.Contains(v, "--ingress-class") && strings.Contains(v, "--controller-class") { + continue + } + + args = append(args, v) + } + + args = append(args, "--ingress-class=testclass") + args = append(args, "--controller-class=k8s.io/other-class") + deployment.Spec.Template.Spec.Containers[0].Args = args + _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) + + return err + }) + assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags") + }) + + ginkgo.It("should ignore Ingress with no class and accept the correctly configured Ingresses", func() { + invalidHost := "bar" + + ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + validHost := "foo" + annotations := map[string]string{ + ingressclass.IngressKey: "testclass", + } + ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotations) + // Delete the IngressClass as we want just the annotation here + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + validHostClass := "foobar123" + ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = &otherIngressClassName + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return !strings.Contains(cfg, "server_name bar") && + strings.Contains(cfg, "server_name foo") && + strings.Contains(cfg, "server_name foobar123") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHost). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHostClass). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", invalidHost). + Expect(). + Status(http.StatusNotFound) + }) + + }) + + ginkgo.Context("With watch-ingress-without-class flag", func() { + ginkgo.BeforeEach(func() { + err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { + args := []string{} + for _, v := range deployment.Spec.Template.Spec.Containers[0].Args { + if strings.Contains(v, "--watch-ingress-without-class") && strings.Contains(v, "--controller-class") { + continue + } + + args = append(args, v) + } + + args = append(args, "--watch-ingress-without-class") + deployment.Spec.Template.Spec.Containers[0].Args = args + _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) + + return err + }) + assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags") + }) + + ginkgo.It("should watch Ingress with no class and ignore ingress with a different class", func() { + validHost := "bar" + + ing := framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + invalidHost := "foo" + annotations := map[string]string{ + ingressclass.IngressKey: "testclass123", + } + ing = framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, annotations) + ing.Spec.IngressClassName = nil + f.EnsureIngress(ing) + + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "server_name bar") && + !strings.Contains(cfg, "server_name foo") + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", validHost). + Expect(). + Status(http.StatusOK) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", invalidHost). + Expect(). + Status(http.StatusNotFound) + }) + + }) +}) diff --git a/test/e2e/settings/no_auth_locations.go b/test/e2e/settings/no_auth_locations.go index de36490888f..2d32b05d6bf 100644 --- a/test/e2e/settings/no_auth_locations.go +++ b/test/e2e/settings/no_auth_locations.go @@ -106,7 +106,7 @@ func buildBasicAuthIngressWithSecondPath(host, namespace, secretName, pathName s }, }, Spec: networking.IngressSpec{ - IngressClassName: &namespace, + IngressClassName: framework.GetIngressClassName(namespace), Rules: []networking.IngressRule{ { Host: host, diff --git a/test/e2e/settings/server_tokens.go b/test/e2e/settings/server_tokens.go index c0ce8a6ec2d..e84639b0818 100644 --- a/test/e2e/settings/server_tokens.go +++ b/test/e2e/settings/server_tokens.go @@ -57,7 +57,7 @@ var _ = framework.DescribeSetting("server-tokens", func() { Annotations: map[string]string{}, }, Spec: networking.IngressSpec{ - IngressClassName: &f.Namespace, + IngressClassName: &f.IngressClass, Rules: []networking.IngressRule{ { Host: serverTokens, diff --git a/test/e2e/status/update.go b/test/e2e/status/update.go index 07d30243f83..23679afdc29 100644 --- a/test/e2e/status/update.go +++ b/test/e2e/status/update.go @@ -94,7 +94,7 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() { err = f.KubeClientSet.CoreV1(). ConfigMaps(f.Namespace). - Delete(context.TODO(), "ingress-controller-leader-nginx", metav1.DeleteOptions{}) + Delete(context.TODO(), "ingress-controller-leader", metav1.DeleteOptions{}) assert.Nil(ginkgo.GinkgoT(), err, "unexpected error deleting leader election configmap") _, cmd, err = f.KubectlProxy(port) diff --git a/test/e2e/wait-for-nginx.sh b/test/e2e/wait-for-nginx.sh index 8b0abd1b91b..9a37d1ffcfb 100755 --- a/test/e2e/wait-for-nginx.sh +++ b/test/e2e/wait-for-nginx.sh @@ -74,7 +74,9 @@ controller: service: type: NodePort electionID: ingress-controller-leader - ingressClass: $NAMESPACE + ingressClassResource: + # We will create and remove each IC/ClusterRole/ClusterRoleBinding per test so there's no conflict + enabled: false extraArgs: tcp-services-configmap: $NAMESPACE/tcp-services # e2e tests do not require information about ingress status