Add support for IngressClass and ingress.class annotation
This commit is contained in:
parent
d4e0657991
commit
efbb3f9fc8
17 changed files with 350 additions and 53 deletions
|
|
@ -55,7 +55,7 @@ func (f *Framework) GetLbAlgorithm(serviceName string, servicePort int) (string,
|
|||
|
||||
// ExecIngressPod executes a command inside the first container in ingress controller running pod
|
||||
func (f *Framework) ExecIngressPod(command string) (string, error) {
|
||||
pod, err := getIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/ingress-nginx/internal/k8s"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
|
|
@ -56,6 +57,8 @@ var (
|
|||
type Framework struct {
|
||||
BaseName string
|
||||
|
||||
IsIngressV1Ready bool
|
||||
|
||||
// A Kubernetes and Service Catalog client
|
||||
KubeClientSet kubernetes.Interface
|
||||
KubeConfig *restclient.Config
|
||||
|
|
@ -78,10 +81,13 @@ func NewDefaultFramework(baseName string) *Framework {
|
|||
kubeClient, err := kubernetes.NewForConfig(kubeConfig)
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "creating Kubernetes API client")
|
||||
|
||||
_, isIngressV1Ready := k8s.NetworkingIngressAvailable(kubeClient)
|
||||
|
||||
f := &Framework{
|
||||
BaseName: baseName,
|
||||
KubeConfig: kubeConfig,
|
||||
KubeClientSet: kubeClient,
|
||||
BaseName: baseName,
|
||||
KubeConfig: kubeConfig,
|
||||
KubeClientSet: kubeClient,
|
||||
IsIngressV1Ready: isIngressV1Ready,
|
||||
}
|
||||
|
||||
ginkgo.BeforeEach(f.BeforeEach)
|
||||
|
|
@ -109,7 +115,7 @@ func (f *Framework) BeforeEach() {
|
|||
// AfterEach deletes the namespace, after reading its events.
|
||||
func (f *Framework) AfterEach() {
|
||||
if ginkgo.CurrentGinkgoTestDescription().Failed {
|
||||
pod, err := getIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
if err != nil {
|
||||
Logf("Unexpected error searching for ingress controller pod: %v", err)
|
||||
return
|
||||
|
|
@ -221,7 +227,7 @@ func (f *Framework) WaitForNginxCustomConfiguration(from string, to string, matc
|
|||
}
|
||||
|
||||
func nginxLogs(client kubernetes.Interface, namespace string) (string, error) {
|
||||
pod, err := getIngressNGINXPod(namespace, client)
|
||||
pod, err := GetIngressNGINXPod(namespace, client)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -240,7 +246,7 @@ func (f *Framework) NginxLogs() (string, error) {
|
|||
|
||||
func (f *Framework) matchNginxConditions(name string, matcher func(cfg string) bool) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
pod, err := getIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -272,7 +278,7 @@ func (f *Framework) matchNginxConditions(name string, matcher func(cfg string) b
|
|||
|
||||
func (f *Framework) matchNginxCustomConditions(from string, to string, matcher func(cfg string) bool) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
pod, err := getIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -367,14 +373,14 @@ func (f *Framework) UpdateNginxConfigMapData(key string, value string) {
|
|||
// Grace period to wait for pod shutdown is in seconds.
|
||||
func (f *Framework) DeleteNGINXPod(grace int64) {
|
||||
ns := f.Namespace
|
||||
pod, err := getIngressNGINXPod(ns, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(ns, f.KubeClientSet)
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "expected ingress nginx pod to be running")
|
||||
|
||||
err = f.KubeClientSet.CoreV1().Pods(ns).Delete(context.TODO(), pod.GetName(), *metav1.NewDeleteOptions(grace))
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "deleting ingress nginx pod")
|
||||
|
||||
err = wait.Poll(Poll, DefaultTimeout, func() (bool, error) {
|
||||
pod, err := getIngressNGINXPod(ns, f.KubeClientSet)
|
||||
pod, err := GetIngressNGINXPod(ns, f.KubeClientSet)
|
||||
if err != nil || pod == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,8 @@ func podRunningReady(p *core.Pod) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func getIngressNGINXPod(ns string, kubeClientSet kubernetes.Interface) (*core.Pod, error) {
|
||||
// GetIngressNGINXPod returns the ingress controller running pod
|
||||
func GetIngressNGINXPod(ns string, kubeClientSet kubernetes.Interface) (*core.Pod, error) {
|
||||
l, err := kubeClientSet.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: "app.kubernetes.io/name=ingress-nginx",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,27 +18,51 @@ package settings
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
networking "k8s.io/api/networking/v1beta1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/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")
|
||||
|
||||
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{})
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeploymentWithReplicas(1)
|
||||
})
|
||||
|
||||
ginkgo.Context("Without a specific ingress-class", func() {
|
||||
|
||||
ginkgo.It("should ignore Ingress with class", func() {
|
||||
invalidHost := "foo"
|
||||
annotations := map[string]string{
|
||||
|
|
@ -74,7 +98,15 @@ var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() {
|
|||
ginkgo.BeforeEach(func() {
|
||||
err := framework.UpdateDeployment(f.KubeClientSet, f.Namespace, "nginx-ingress-controller", 1,
|
||||
func(deployment *appsv1.Deployment) error {
|
||||
args := deployment.Spec.Template.Spec.Containers[0].Args
|
||||
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{})
|
||||
|
|
@ -154,4 +186,149 @@ var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() {
|
|||
Status(http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("check scenarios for IngressClass and ingress.class annotation", func() {
|
||||
if !f.IsIngressV1Ready {
|
||||
ginkgo.Skip("Test requires Kubernetes v1.18 or higher")
|
||||
}
|
||||
|
||||
ingressClassName := "test-new-ingress-class"
|
||||
|
||||
ingressClass, err := f.KubeClientSet.NetworkingV1beta1().IngressClasses().
|
||||
Create(context.TODO(), &networking.IngressClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ingressClassName,
|
||||
},
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: k8s.IngressNGINXController,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
|
||||
if ingressClass == nil {
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "creating IngressClass")
|
||||
}
|
||||
|
||||
pod, err := framework.GetIngressNGINXPod(f.Namespace, f.KubeClientSet)
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "searching ingress controller pod")
|
||||
serviceAccount := pod.Spec.ServiceAccountName
|
||||
|
||||
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: serviceAccount,
|
||||
Namespace: f.Namespace,
|
||||
})
|
||||
|
||||
_, err = f.KubeClientSet.RbacV1().ClusterRoleBindings().Update(context.Background(), crb, metav1.UpdateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "searching cluster role binding")
|
||||
|
||||
err = framework.UpdateDeployment(f.KubeClientSet, f.Namespace, "nginx-ingress-controller", 1,
|
||||
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", ingressClassName))
|
||||
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 = &ingressClassName
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host, 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.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
ing.Annotations = map[string]string{
|
||||
class.IngressKey: ingressClassName,
|
||||
}
|
||||
ing.Spec.IngressClassName = nil
|
||||
|
||||
_, err = f.KubeClientSet.NetworkingV1beta1().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))
|
||||
})
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
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.NetworkingV1beta1().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.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
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.NetworkingV1beta1().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.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue