diff --git a/e2e/ingress_class_test.go b/e2e/ingress_class_extensions_test.go similarity index 85% rename from e2e/ingress_class_test.go rename to e2e/ingress_class_extensions_test.go index 5a3e3236..1a0d28bf 100644 --- a/e2e/ingress_class_test.go +++ b/e2e/ingress_class_extensions_test.go @@ -18,10 +18,10 @@ import ( capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" ) -var _ = Describe("when Tenant handles Ingress classes", func() { +var _ = Describe("when Tenant handles Ingress classes with extensions/v1beta1", func() { tnt := &capsulev1beta1.Tenant{ ObjectMeta: metav1.ObjectMeta{ - Name: "ingress-class", + Name: "ingress-class-extensions-v1beta1", }, Spec: capsulev1beta1.TenantSpec{ Owners: capsulev1beta1.OwnerListSpec{ @@ -50,8 +50,14 @@ var _ = Describe("when Tenant handles Ingress classes", func() { Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed()) }) - It("should block a non allowed class", func() { - ns := NewNamespace("ingress-class-disallowed") + It("should block a non allowed class for extensions/v1beta1", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min > 22 { + Skip("Running test on Kubernetes " + v + ", extensions/v1beta1 has been deprecated") + } + + ns := NewNamespace("ingress-class-disallowed-extensions-v1beta1") cs := ownerClient(tnt.Spec.Owners[0]) NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) @@ -115,7 +121,13 @@ var _ = Describe("when Tenant handles Ingress classes", func() { }) It("should allow enabled class using the deprecated annotation", func() { - ns := NewNamespace("ingress-class-allowed-annotation") + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min > 22 { + Skip("Running test on Kubernetes " + v + ", extensions/v1beta1 has been deprecated") + } + + ns := NewNamespace("ingress-class-allowed-annotation-extensions-v1beta1") cs := ownerClient(tnt.Spec.Owners[0]) NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) @@ -144,14 +156,15 @@ var _ = Describe("when Tenant handles Ingress classes", func() { }) It("should allow enabled class using the ingressClassName field", func() { - ns := NewNamespace("ingress-class-allowed-annotation") - cs := ownerClient(tnt.Spec.Owners[0]) - maj, min, v := GetKubernetesSemVer() + if maj == 1 && min < 18 { Skip("Running test on Kubernetes " + v + ", doesn't provide .spec.ingressClassName") } + ns := NewNamespace("ingress-class-allowed-annotation-extensions-v1beta1") + cs := ownerClient(tnt.Spec.Owners[0]) + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) @@ -176,7 +189,13 @@ var _ = Describe("when Tenant handles Ingress classes", func() { }) It("should allow enabled Ingress by regex using the deprecated annotation", func() { - ns := NewNamespace("ingress-class-allowed-annotation") + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min > 22 { + Skip("Running test on Kubernetes " + v + ", extensions/v1beta1 has been deprecated") + } + + ns := NewNamespace("ingress-class-allowed-annotation-extensions-v1beta1") cs := ownerClient(tnt.Spec.Owners[0]) ingressClass := "oil-ingress" @@ -204,15 +223,20 @@ var _ = Describe("when Tenant handles Ingress classes", func() { }) It("should allow enabled Ingress by regex using the ingressClassName field", func() { - ns := NewNamespace("ingress-class-allowed-annotation") - cs := ownerClient(tnt.Spec.Owners[0]) - ingressClass := "oil-haproxy" - maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min > 22 { + Skip("Running test on Kubernetes " + v + ", extensions/v1beta1 has been deprecated") + } + if maj == 1 && min < 18 { Skip("Running test on Kubernetes " + v + ", doesn't provide .spec.ingressClassName") } + ns := NewNamespace("ingress-class-allowed-annotation-extensions-v1beta1") + cs := ownerClient(tnt.Spec.Owners[0]) + ingressClass := "oil-haproxy" + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) diff --git a/e2e/ingress_class_networking_test.go b/e2e/ingress_class_networking_test.go new file mode 100644 index 00000000..2d73225b --- /dev/null +++ b/e2e/ingress_class_networking_test.go @@ -0,0 +1,283 @@ +//+build e2e + +// Copyright 2020-2021 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package e2e + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" +) + +var _ = Describe("when Tenant handles Ingress classes with networking.k8s.io/v1", func() { + tnt := &capsulev1beta1.Tenant{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ingress-class-networking-v1", + }, + Spec: capsulev1beta1.TenantSpec{ + Owners: []capsulev1beta1.OwnerSpec{ + { + Name: "ingress", + Kind: "User", + }, + }, + IngressClasses: &capsulev1beta1.AllowedListSpec{ + Exact: []string{ + "nginx", + "haproxy", + }, + Regex: "^oil-.*$", + }, + }, + } + + JustBeforeEach(func() { + EventuallyCreation(func() error { + tnt.ResourceVersion = "" + return k8sClient.Create(context.TODO(), tnt) + }).Should(Succeed()) + }) + JustAfterEach(func() { + Expect(k8sClient.Delete(context.TODO(), tnt)).Should(Succeed()) + }) + + It("should block a non allowed class", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min < 19 { + Skip("Running test on Kubernetes " + v + ", doesn't provide networking.k8s.io/v1") + } + + ns := NewNamespace("ingress-class-disallowed-networking-v1") + cs := ownerClient(tnt.Spec.Owners[0]) + + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) + TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) + + By("non-specifying at all", func() { + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "denied-ingress", + }, + Spec: networkingv1.IngressSpec{ + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed()) + }) + By("defining as deprecated annotation", func() { + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "denied-ingress", + Annotations: map[string]string{ + "kubernetes.io/ingress.class": "the-worst-ingress-available", + }, + }, + Spec: networkingv1.IngressSpec{ + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed()) + }) + By("using the ingressClassName", func() { + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "denied-ingress", + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: pointer.StringPtr("the-worst-ingress-available"), + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed()) + }) + }) + + It("should allow enabled class using the deprecated annotation for networking.k8s.io/v1", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min < 19 { + Skip("Running test on Kubernetes " + v + ", doesn't provide networking.k8s.io/v1") + } + + ns := NewNamespace("ingress-class-allowed-annotation-networking-v1") + cs := ownerClient(tnt.Spec.Owners[0]) + + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) + TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) + + for _, c := range tnt.Spec.IngressClasses.Exact { + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: c, + Annotations: map[string]string{ + "kubernetes.io/ingress.class": c, + }, + }, + Spec: networkingv1.IngressSpec{ + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).Should(Succeed()) + } + }) + + It("should allow enabled class using the ingressClassName field", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min < 19 { + Skip("Running test on Kubernetes " + v + ", doesn't provide networking.k8s.io/v1") + } + + ns := NewNamespace("ingress-class-allowed-annotation-networking-v1") + cs := ownerClient(tnt.Spec.Owners[0]) + + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) + TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) + + for _, c := range tnt.Spec.IngressClasses.Exact { + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: c, + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: &c, + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).Should(Succeed()) + } + }) + + It("should allow enabled Ingress by regex using the deprecated annotation", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min < 19 { + Skip("Running test on Kubernetes " + v + ", doesn't provide networking.k8s.io/v1") + } + + ns := NewNamespace("ingress-class-allowed-annotation-networking-v1") + cs := ownerClient(tnt.Spec.Owners[0]) + ingressClass := "oil-ingress" + + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) + TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) + + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: ingressClass, + Annotations: map[string]string{ + "kubernetes.io/ingress.class": ingressClass, + }, + }, + Spec: networkingv1.IngressSpec{ + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, defaultTimeoutInterval, defaultPollInterval).Should(Succeed()) + }) + + It("should allow enabled Ingress by regex using the ingressClassName field", func() { + maj, min, v := GetKubernetesSemVer() + + if maj == 1 && min < 19 { + Skip("Running test on Kubernetes " + v + ", doesn't provide networking.k8s.io/v1") + } + + ns := NewNamespace("ingress-class-allowed-annotation-networking-v1") + cs := ownerClient(tnt.Spec.Owners[0]) + ingressClass := "oil-haproxy" + + NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed()) + TenantNamespaceList(tnt, defaultTimeoutInterval).Should(ContainElement(ns.GetName())) + + Eventually(func() (err error) { + i := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: ingressClass, + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: &ingressClass, + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "foo", + Port: networkingv1.ServiceBackendPort{ + Number: 8080, + }, + }, + }, + }, + } + _, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), i, metav1.CreateOptions{}) + return + }, 600, defaultPollInterval).Should(Succeed()) + }) +})