Skip to content

Commit 7337633

Browse files
authored
Merge pull request #28 from cybozu-go/ingress-class-name
Class-name filter
2 parents 02dc0b4 + 49e5b78 commit 7337633

File tree

6 files changed

+273
-5
lines changed

6 files changed

+273
-5
lines changed

cmd/root.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func init() {
4949
fs.String("service-name", "", "NamespacedName of the Contour LoadBalancer Service")
5050
fs.String("default-issuer-name", "", "Issuer name used by default")
5151
fs.String("default-issuer-kind", certmanagerv1alpha2.ClusterIssuerKind, "Issuer kind used by default")
52+
fs.String("ingress-class-name", "", "Ingress class name that watched by Contour Plus. If not specified, then all classes are watched")
5253
fs.Bool("leader-election", true, "Enable/disable leader election")
5354
if err := viper.BindPFlags(fs); err != nil {
5455
panic(err)
@@ -76,7 +77,8 @@ In addition to flags, the following environment variables are read:
7677
CP_SERVICE_NAME NamespacedName of the Contour LoadBalancer Service
7778
CP_DEFAULT_ISSUER_NAME Issuer name used by default
7879
CP_DEFAULT_ISSUER_KIND Issuer kind used by default
79-
CP_LEADER_ELECTION Disable leader election if set to "false"`,
80+
CP_LEADER_ELECTION Disable leader election if set to "false"
81+
CP_INGRESS_CLASS_NAME Ingress class name that watched by Contour Plus. If not specified, then all classes are watched`,
8082
RunE: func(cmd *cobra.Command, args []string) error {
8183
cmd.SilenceUsage = true
8284
return subMain()
@@ -124,6 +126,8 @@ func subMain() error {
124126
}
125127
opts.DefaultIssuerKind = defaultIssuerKind
126128

129+
opts.IngressClassName = viper.GetString("ingress-class-name")
130+
127131
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
128132
Scheme: scheme,
129133
MetricsBindAddress: viper.GetString("metrics-addr"),

controllers/httpproxy_controller.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type HTTPProxyReconciler struct {
3232
DefaultIssuerKind string
3333
CreateDNSEndpoint bool
3434
CreateCertificate bool
35+
IngressClassName string
3536
}
3637

3738
// +kubebuilder:rbac:groups=projectcontour.io,resources=httpproxies,verbs=get;list;watch
@@ -65,6 +66,12 @@ func (r *HTTPProxyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
6566
return ctrl.Result{}, nil
6667
}
6768

69+
if r.IngressClassName != "" {
70+
if !r.isClassNameMatched(hp) {
71+
return ctrl.Result{}, nil
72+
}
73+
}
74+
6875
if err := r.reconcileDNSEndpoint(ctx, hp, log); err != nil {
6976
log.Error(err, "unable to reconcile DNSEndpoint")
7077
return ctrl.Result{}, err
@@ -77,6 +84,28 @@ func (r *HTTPProxyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
7784
return ctrl.Result{}, nil
7885
}
7986

87+
func (r *HTTPProxyReconciler) isClassNameMatched(hp *projectcontourv1.HTTPProxy) bool {
88+
ingressClassName := hp.Annotations[ingressClassNameAnnotation]
89+
if ingressClassName != "" {
90+
if ingressClassName != r.IngressClassName {
91+
return false
92+
}
93+
}
94+
95+
contourIngressClassName := hp.Annotations[contourIngressClassNameAnnotation]
96+
if contourIngressClassName != "" {
97+
if contourIngressClassName != r.IngressClassName {
98+
return false
99+
}
100+
}
101+
102+
if contourIngressClassName == "" && ingressClassName == "" {
103+
return false
104+
}
105+
106+
return true
107+
}
108+
80109
func (r *HTTPProxyReconciler) reconcileDNSEndpoint(ctx context.Context, hp *projectcontourv1.HTTPProxy, log logr.Logger) error {
81110
if !r.CreateDNSEndpoint {
82111
return nil

controllers/httpproxy_controller_test.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package controllers
22

33
import (
44
"context"
5+
"fmt"
6+
"testing"
57
"time"
68

79
certmanagerv1alpha2 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
@@ -467,6 +469,97 @@ func testHTTPProxyReconcile() {
467469
Expect(k8sClient.List(context.Background(), crtList, client.InNamespace(ns))).ShouldNot(HaveOccurred())
468470
Expect(crtList.Items).Should(BeEmpty())
469471
})
472+
473+
It(`should not create DNSEndpoint and Certificate if the class name is not the target`, func() {
474+
ns := testNamespacePrefix + randomString(10)
475+
Expect(k8sClient.Create(context.Background(), &corev1.Namespace{
476+
ObjectMeta: ctrl.ObjectMeta{Name: ns},
477+
})).ShouldNot(HaveOccurred())
478+
defer k8sClient.Delete(context.Background(), &corev1.Namespace{
479+
ObjectMeta: ctrl.ObjectMeta{Name: ns},
480+
})
481+
482+
scm, mgr := setupManager()
483+
484+
Expect(SetupReconciler(mgr, scm, ReconcilerOptions{
485+
ServiceKey: testServiceKey,
486+
DefaultIssuerName: "test-issuer",
487+
DefaultIssuerKind: certmanagerv1alpha2.IssuerKind,
488+
CreateDNSEndpoint: true,
489+
CreateCertificate: true,
490+
IngressClassName: "class-name",
491+
})).ShouldNot(HaveOccurred())
492+
493+
stopMgr := startTestManager(mgr)
494+
defer stopMgr()
495+
496+
By("creating HTTPProxy having the annotation")
497+
hpKey := client.ObjectKey{Name: "foo", Namespace: ns}
498+
hp := newDummyHTTPProxy(hpKey)
499+
hp.Annotations[ingressClassNameAnnotation] = "wrong"
500+
Expect(k8sClient.Create(context.Background(), hp)).ShouldNot(HaveOccurred())
501+
502+
By("confirming that DNSEndpoint and Certificate do not exist")
503+
time.Sleep(time.Second)
504+
endpointList := &endpoint.DNSEndpointList{}
505+
Expect(k8sClient.List(context.Background(), endpointList, client.InNamespace(ns))).ShouldNot(HaveOccurred())
506+
Expect(endpointList.Items).Should(BeEmpty())
507+
508+
crtList := &certmanagerv1alpha2.CertificateList{}
509+
Expect(k8sClient.List(context.Background(), crtList, client.InNamespace(ns))).ShouldNot(HaveOccurred())
510+
Expect(crtList.Items).Should(BeEmpty())
511+
512+
By("creating HTTPProxy without the annotation")
513+
hpKey = client.ObjectKey{Name: "bar", Namespace: ns}
514+
hp = newDummyHTTPProxy(hpKey)
515+
Expect(k8sClient.Create(context.Background(), hp)).ShouldNot(HaveOccurred())
516+
517+
By("confirming that DNSEndpoint and Certificate do not exist")
518+
time.Sleep(time.Second)
519+
endpointList = &endpoint.DNSEndpointList{}
520+
Expect(k8sClient.List(context.Background(), endpointList, client.InNamespace(ns))).ShouldNot(HaveOccurred())
521+
Expect(endpointList.Items).Should(BeEmpty())
522+
523+
crtList = &certmanagerv1alpha2.CertificateList{}
524+
Expect(k8sClient.List(context.Background(), crtList, client.InNamespace(ns))).ShouldNot(HaveOccurred())
525+
Expect(crtList.Items).Should(BeEmpty())
526+
})
527+
528+
It(`should create Certificate if the class name equals to the target`, func() {
529+
ns := testNamespacePrefix + randomString(10)
530+
Expect(k8sClient.Create(context.Background(), &corev1.Namespace{
531+
ObjectMeta: ctrl.ObjectMeta{Name: ns},
532+
})).ShouldNot(HaveOccurred())
533+
defer k8sClient.Delete(context.Background(), &corev1.Namespace{
534+
ObjectMeta: ctrl.ObjectMeta{Name: ns},
535+
})
536+
537+
scm, mgr := setupManager()
538+
539+
Expect(SetupReconciler(mgr, scm, ReconcilerOptions{
540+
ServiceKey: testServiceKey,
541+
DefaultIssuerName: "test-issuer",
542+
DefaultIssuerKind: certmanagerv1alpha2.IssuerKind,
543+
CreateCertificate: true,
544+
IngressClassName: "class-name",
545+
})).ShouldNot(HaveOccurred())
546+
547+
stopMgr := startTestManager(mgr)
548+
defer stopMgr()
549+
550+
By("creating HTTPProxy having the annotation")
551+
hpKey := client.ObjectKey{Name: "foo", Namespace: ns}
552+
hp := newDummyHTTPProxy(hpKey)
553+
hp.Annotations[ingressClassNameAnnotation] = "class-name"
554+
Expect(k8sClient.Create(context.Background(), hp)).ShouldNot(HaveOccurred())
555+
556+
By("getting Certificate")
557+
certificate := &certmanagerv1alpha2.Certificate{}
558+
objKey := client.ObjectKey{Name: hpKey.Name, Namespace: hpKey.Namespace}
559+
Eventually(func() error {
560+
return k8sClient.Get(context.Background(), objKey, certificate)
561+
}, 5*time.Second).Should(Succeed())
562+
})
470563
}
471564

472565
func newDummyHTTPProxy(hpKey client.ObjectKey) *projectcontourv1.HTTPProxy {
@@ -487,3 +580,107 @@ func newDummyHTTPProxy(hpKey client.ObjectKey) *projectcontourv1.HTTPProxy {
487580
},
488581
}
489582
}
583+
584+
func TestIsClassNameMatched(t *testing.T) {
585+
tests := []struct {
586+
name string
587+
ingressClassName string
588+
hp *projectcontourv1.HTTPProxy
589+
want bool
590+
}{
591+
{
592+
name: "Annotation is not set",
593+
ingressClassName: "class-name",
594+
hp: &projectcontourv1.HTTPProxy{
595+
ObjectMeta: v1.ObjectMeta{
596+
Annotations: map[string]string{},
597+
},
598+
},
599+
want: false,
600+
},
601+
{
602+
name: "Both annotation are set",
603+
ingressClassName: "class-name",
604+
hp: &projectcontourv1.HTTPProxy{
605+
ObjectMeta: v1.ObjectMeta{
606+
Annotations: map[string]string{
607+
ingressClassNameAnnotation: "class-name",
608+
contourIngressClassNameAnnotation: "class-name",
609+
},
610+
},
611+
},
612+
want: true,
613+
},
614+
{
615+
name: "Both annotation are set but not matched",
616+
ingressClassName: "class-name",
617+
hp: &projectcontourv1.HTTPProxy{
618+
ObjectMeta: v1.ObjectMeta{
619+
Annotations: map[string]string{
620+
ingressClassNameAnnotation: "class-name",
621+
contourIngressClassNameAnnotation: "wrong",
622+
},
623+
},
624+
},
625+
want: false,
626+
},
627+
{
628+
name: fmt.Sprintf("Annotation %s is set", ingressClassNameAnnotation),
629+
ingressClassName: "class-name",
630+
hp: &projectcontourv1.HTTPProxy{
631+
ObjectMeta: v1.ObjectMeta{
632+
Annotations: map[string]string{
633+
ingressClassNameAnnotation: "class-name",
634+
},
635+
},
636+
},
637+
want: true,
638+
},
639+
{
640+
name: fmt.Sprintf("Annotation %s is set but not matched", ingressClassNameAnnotation),
641+
ingressClassName: "class-name",
642+
hp: &projectcontourv1.HTTPProxy{
643+
ObjectMeta: v1.ObjectMeta{
644+
Annotations: map[string]string{
645+
ingressClassNameAnnotation: "wrong",
646+
},
647+
},
648+
},
649+
want: false,
650+
},
651+
{
652+
name: fmt.Sprintf("Annotation %s is set", contourIngressClassNameAnnotation),
653+
ingressClassName: "class-name",
654+
hp: &projectcontourv1.HTTPProxy{
655+
ObjectMeta: v1.ObjectMeta{
656+
Annotations: map[string]string{
657+
contourIngressClassNameAnnotation: "class-name",
658+
},
659+
},
660+
},
661+
want: true,
662+
},
663+
{
664+
name: fmt.Sprintf("Annotation %s is set but not matched", contourIngressClassNameAnnotation),
665+
ingressClassName: "class-name",
666+
hp: &projectcontourv1.HTTPProxy{
667+
ObjectMeta: v1.ObjectMeta{
668+
Annotations: map[string]string{
669+
contourIngressClassNameAnnotation: "wrong",
670+
},
671+
},
672+
},
673+
want: false,
674+
},
675+
}
676+
for _, tt := range tests {
677+
t.Run(tt.name, func(t *testing.T) {
678+
r := &HTTPProxyReconciler{
679+
IngressClassName: tt.ingressClassName,
680+
}
681+
if got := r.isClassNameMatched(tt.hp); got != tt.want {
682+
t.Errorf("HTTPProxyReconciler.isClassNameMatched() = %v, want %v", got, tt.want)
683+
}
684+
})
685+
}
686+
}

controllers/ingressroute_controller.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import (
2121
)
2222

2323
const (
24-
excludeAnnotation = "contour-plus.cybozu.com/exclude"
25-
testACMETLSAnnotation = "kubernetes.io/tls-acme"
26-
issuerNameAnnotation = "cert-manager.io/issuer"
27-
clusterIssuerNameAnnotation = "cert-manager.io/cluster-issuer"
24+
excludeAnnotation = "contour-plus.cybozu.com/exclude"
25+
testACMETLSAnnotation = "kubernetes.io/tls-acme"
26+
issuerNameAnnotation = "cert-manager.io/issuer"
27+
clusterIssuerNameAnnotation = "cert-manager.io/cluster-issuer"
28+
ingressClassNameAnnotation = "kubernetes.io/ingress.class"
29+
contourIngressClassNameAnnotation = "projectcontour.io/ingress.class"
2830
)
2931

3032
// IngressRouteReconciler reconciles a IngressRoute object
@@ -39,6 +41,7 @@ type IngressRouteReconciler struct {
3941
DefaultIssuerKind string
4042
CreateDNSEndpoint bool
4143
CreateCertificate bool
44+
IngressClassName string
4245
}
4346

4447
// +kubebuilder:rbac:groups=contour.heptio.com,resources=ingressroutes,verbs=get;list;watch
@@ -71,6 +74,12 @@ func (r *IngressRouteReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error
7174
return ctrl.Result{}, nil
7275
}
7376

77+
if r.IngressClassName != "" {
78+
if !r.isClassNameMatched(ir) {
79+
return ctrl.Result{}, nil
80+
}
81+
}
82+
7483
err = r.reconcileDNSEndpoint(ctx, ir, log)
7584
if err != nil {
7685
log.Error(err, "unable to reconcile DNSEndpoint")
@@ -85,6 +94,28 @@ func (r *IngressRouteReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error
8594
return ctrl.Result{}, nil
8695
}
8796

97+
func (r *IngressRouteReconciler) isClassNameMatched(ir *contourv1beta1.IngressRoute) bool {
98+
ingressClassName := ir.Annotations[ingressClassNameAnnotation]
99+
if ingressClassName != "" {
100+
if ingressClassName != r.IngressClassName {
101+
return false
102+
}
103+
}
104+
105+
contourIngressClassName := ir.Annotations[contourIngressClassNameAnnotation]
106+
if contourIngressClassName != "" {
107+
if contourIngressClassName != r.IngressClassName {
108+
return false
109+
}
110+
}
111+
112+
if contourIngressClassName == "" && ingressClassName == "" {
113+
return false
114+
}
115+
116+
return true
117+
}
118+
88119
func (r *IngressRouteReconciler) reconcileDNSEndpoint(ctx context.Context, ir *contourv1beta1.IngressRoute, log logr.Logger) error {
89120
if !r.CreateDNSEndpoint {
90121
return nil

controllers/setup.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type ReconcilerOptions struct {
2222
DefaultIssuerKind string
2323
CreateDNSEndpoint bool
2424
CreateCertificate bool
25+
IngressClassName string
2526
}
2627

2728
// SetupScheme initializes a schema
@@ -69,6 +70,7 @@ func SetupReconciler(mgr manager.Manager, scheme *runtime.Scheme, opts Reconcile
6970
DefaultIssuerKind: opts.DefaultIssuerKind,
7071
CreateDNSEndpoint: opts.CreateDNSEndpoint,
7172
CreateCertificate: opts.CreateCertificate,
73+
IngressClassName: opts.IngressClassName,
7274
}
7375
err := ingressRouteReconciler.SetupWithManager(mgr)
7476
if err != nil {
@@ -85,6 +87,7 @@ func SetupReconciler(mgr manager.Manager, scheme *runtime.Scheme, opts Reconcile
8587
DefaultIssuerKind: opts.DefaultIssuerKind,
8688
CreateDNSEndpoint: opts.CreateDNSEndpoint,
8789
CreateCertificate: opts.CreateCertificate,
90+
IngressClassName: opts.IngressClassName,
8891
}
8992
err = httpProxyReconciler.SetupWithManager(mgr)
9093
if err != nil {

0 commit comments

Comments
 (0)