Skip to content

Commit 7320a08

Browse files
committed
MEDIUM: add ingress.class annotation to TCP CR
1 parent 35faf5a commit 7320a08

File tree

6 files changed

+114
-10
lines changed

6 files changed

+114
-10
lines changed

documentation/custom-resource-tcp.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ kind: TCP
3535
metadata:
3636
name: tcp-1
3737
namespace: test
38+
annotations:
39+
ingress.class: haproxy
3840
spec:
3941
- name: tcp-http-echo-8443
4042
frontend:
@@ -103,6 +105,30 @@ Note that in the TCP CR :
103105

104106
Except the frontend keyword `default_backend`, all other lines are not automatically generated but are in a flexible way handled by the `frontend` section in the TCP CR.
105107

108+
## ingress.class
109+
110+
Starting `3.1`, the TCP Custom Resource managed by the Ingress Controller can be filtered using the `ingress.class` annotation.
111+
It behaves the same way as `Ingress`:
112+
113+
| ingress.class controller flag | TCP CR ingress.class annotation | Behavior |
114+
|------------------|---------------------|-----------------|
115+
| '' (not set) | * (any value) | TCP CR managed by IC |
116+
| \<igclass\> | Same value as controller | TCP CR managed by IC |
117+
| \<igclass\> | Value different from controller | TCP CR not managed by IC, frontend and backend deleted if existing |
118+
| \<igclass\> | '' (empty, not set)| if controller `empty-ingress-class` flag is set, TCP CR managed by IC, otherwise ignored (and frontend and backend are deleted)|
119+
120+
121+
### Migration 3.0 to 3.1: action required regarding ingress.class annotation
122+
123+
If some TCP CRs were deployed with Ingress Controller version <= v3.0, and the Ingress Controller has a `ingress.class` flag for the controller, the TCP CRs need to have the same value for the `ingress.class` annotation in the TCP CR.
124+
125+
If the annotation is not set, the corresponding backends and frontends in the haproxy configuration would be deleted:
126+
- except if the controller `empty-ingress-class` flag is set (same behavior as for `Ingress`).
127+
128+
The setting of the `ingress.class` to the TCP CRs should be done **prior to the upgrade to** `v3.1`. It will not be used in v3.0 but needs to be there starting v3.1.
129+
130+
131+
106132
## Pod and Service definitions
107133

108134
with the following Kubernetes Service and Pod manifests:
@@ -258,6 +284,8 @@ kind: TCP
258284
metadata:
259285
name: tcp-2
260286
namespace: test
287+
annotations:
288+
ingress.class: haproxy
261289
spec:
262290
- name: tcp-http-echo-test2-8443
263291
frontend:
@@ -297,6 +325,8 @@ kind: TCP
297325
metadata:
298326
name: tcp-1
299327
namespace: test
328+
annotations:
329+
ingress.class: haproxy
300330
spec:
301331
- name: tcp-http-echo-443
302332
frontend:

documentation/tcp-cr-full-example/tcp-cr-full.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ apiVersion: ingress.v1.haproxy.org/v1
22
kind: TCP
33
metadata:
44
name: tcp-1
5+
annotations:
6+
ingress.class: haproxy
57
spec:
68
- name: tcp-test
79
frontend:

pkg/controller/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (c *HAProxyController) initHandlers() {
5252
&handler.PatternFiles{},
5353
annotations.ConfigSnippetHandler{},
5454
c.updateStatusManager,
55-
handler.TCPCustomResource{},
55+
handler.NewTCPCustomResource(c.osArgs.IngressClass, c.osArgs.EmptyIngressClass),
5656
}
5757

5858
defer func() { c.updateHandlers = append(c.updateHandlers, handler.Refresh{}) }()

pkg/handler/tcp-cr.go

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package handler
1717
import (
1818
"fmt"
1919
"strings"
20+
"sync"
2021

2122
"github.com/haproxytech/client-native/v5/models"
2223
v1 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v1"
@@ -42,19 +43,63 @@ import (
4243

4344
const tcpServicePrefix = "tcpcr"
4445

45-
type TCPCustomResource struct{}
46+
type TCPCustomResource struct {
47+
controllerIngressClass string
48+
allowEmptyIngressClass bool
49+
}
4650

4751
type tcpcontext struct {
4852
k store.K8s
4953
namespace string
5054
h haproxy.HAProxy
5155
}
5256

57+
var syncIngressClassLog sync.Once
58+
59+
func NewTCPCustomResource(controllerIngressClass string, allowEmptyIngressClass bool) TCPCustomResource {
60+
return TCPCustomResource{
61+
controllerIngressClass: controllerIngressClass,
62+
allowEmptyIngressClass: allowEmptyIngressClass,
63+
}
64+
}
65+
66+
func logTCPMigration30To31Warning() {
67+
logger := utils.GetLogger()
68+
// For 3.0, (WARNING)
69+
// Starting from 3.1, if ingress.class is set for controller, you will need to set the ingress.class annotation in the TCP CRD
70+
// - Setting the ingress.class annotation in the TCP CRD in 3.0 is highly recommended before migration to 3.1
71+
// - empty-ingress-class controller option will also impact TCP CRD starting 3.1
72+
logger.Warning("Using TCP CRD without ingress.class annotation will work only in 3.0")
73+
logger.Warning("If you are using TCP CRDS without ingress.class annotation and ingress.class is set for the controller,an action is required before migrating to 3.1")
74+
logger.Warning("Please read https://github.com/haproxytech/kubernetes-ingress/blob/master/documentation/custom-resource-tcp.md for more information")
75+
}
76+
5377
func (handler TCPCustomResource) Update(k store.K8s, h haproxy.HAProxy, a annotations.Annotations) (err error) {
5478
var errs utils.Errors
5579

5680
for _, ns := range k.Namespaces {
5781
for _, tcpCR := range ns.CRs.TCPsPerCR {
82+
//----------------------------------
83+
// ingress.class migration
84+
// To log in 3.0
85+
// Not in 3.1
86+
syncIngressClassLog.Do(func() {
87+
logTCPMigration30To31Warning()
88+
})
89+
90+
// >= v3.1 for ingress.class
91+
// Not in 3.0
92+
// supported := handler.isSupportedIngressClass(tcpCR)
93+
// if !supported {
94+
// for _, atcp := range tcpCR.Items {
95+
// owner := atcp.Owner()
96+
// k.FrontendRC.RemoveOwner(owner)
97+
// }
98+
// continue
99+
// }
100+
// end ingress.class migration
101+
//----------------------------
102+
58103
// Cleanup will done after Haproxy config transaction succeeds
59104
if tcpCR.Status == store.DELETED {
60105
continue
@@ -302,3 +347,25 @@ func (handler TCPCustomResource) reconcileAdditionalBackends(ctx tcpcontext, ser
302347
}
303348
return errors.Result()
304349
}
350+
351+
// func (handler TCPCustomResource) isSupportedIngressClass(tcps *store.TCPs) bool {
352+
// var supported bool
353+
// tcpIgClassAnn := tcps.IngressClass
354+
355+
// switch handler.controllerIngressClass {
356+
// case "", tcpIgClassAnn:
357+
// supported = true
358+
// default: // mismatch osArgs.Ingress and TCP IngressClass annotation
359+
// if tcpIgClassAnn == "" {
360+
// supported = handler.allowEmptyIngressClass
361+
// if !supported {
362+
// utils.GetLogger().Warningf("[SKIP] TCP %s/%s ingress.class annotation='%s' does not match with controller ingress.class flag '%s' and controller flag 'empty-ingress-class' is false",
363+
// tcps.Namespace, tcps.Name, tcpIgClassAnn, handler.controllerIngressClass)
364+
// }
365+
// } else {
366+
// utils.GetLogger().Warningf("[SKIP] TCP %s/%s ingress.class annotation='%s' does not match with controller ingress.class flag '%s'",
367+
// tcps.Namespace, tcps.Name, tcpIgClassAnn, handler.controllerIngressClass)
368+
// }
369+
// }
370+
// return supported
371+
// }

pkg/k8s/cr-tcp.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,11 @@ func convertToStoreTCP(k8sData interface{}, status store.Status) *store.TCPs {
7171
return nil
7272
}
7373
storeTCP := store.TCPs{
74-
Status: status,
75-
Namespace: data.GetNamespace(),
76-
Name: data.GetName(),
77-
Items: make([]*store.TCPResource, 0),
74+
Status: status,
75+
Namespace: data.GetNamespace(),
76+
IngressClass: data.Annotations["ingress.class"],
77+
Name: data.GetName(),
78+
Items: make([]*store.TCPResource, 0),
7879
}
7980
for _, tcp := range data.Spec {
8081
storeTCP.Items = append(storeTCP.Items, &store.TCPResource{

pkg/store/types-tcp-cr.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ type TCPResource struct {
4545
type TCPResourceList []*TCPResource
4646

4747
type TCPs struct {
48-
Status Status `json:"status,omitempty"`
49-
Namespace string `json:"namespace,omitempty"`
50-
Name string `json:"name,omitempty"`
51-
Items TCPResourceList `json:"items"`
48+
Status Status `json:"status,omitempty"`
49+
IngressClass string `json:"ingress_class,omitempty"`
50+
Namespace string `json:"namespace,omitempty"`
51+
Name string `json:"name,omitempty"`
52+
Items TCPResourceList `json:"items"`
5253
}
5354

5455
func (a *TCPs) Equal(b *TCPs, opt ...models.Options) bool {
@@ -64,6 +65,9 @@ func (a *TCPs) Equal(b *TCPs, opt ...models.Options) bool {
6465
if a.Namespace != b.Namespace {
6566
return false
6667
}
68+
if a.IngressClass != b.IngressClass {
69+
return false
70+
}
6771
// Always ordered before being added into the store, so no need to order here
6872
a.Items.Order()
6973
b.Items.Order()

0 commit comments

Comments
 (0)