Skip to content

Commit 78b7142

Browse files
committed
MEDIUM: allow defining user annotations on configmap, and ingress
note: by default ingress ones are disabled with --enable-user-annotations-on-ingress, you can enable them
1 parent 2570ddd commit 78b7142

File tree

8 files changed

+87
-12
lines changed

8 files changed

+87
-12
lines changed

.aspell.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ allowed:
6161
- str
6262
- async
6363
- params
64+
- configmap

documentation/controller.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Image can be run with arguments:
5050
| [`--input-file`](#--input-file) :construction:(dev) | |
5151
| [`--output-file`](#--output-file) :construction:(dev) | |
5252
| [`--disable-ingress-status-update`](#--disable-ingress-status-update) | `false` |
53+
| [`--enable-user-annotations-on-ingress`](#--enable-user-annotations-on-ingress) :construction:(dev) | |
5354

5455

5556
### `--configmap`
@@ -906,3 +907,25 @@ Example:
906907

907908
***
908909

910+
### `--enable-user-annotations-on-ingress`
911+
912+
913+
> :construction: this is only available from next version, currently available in dev build
914+
915+
Enable support for user annotations on ingress resources.
916+
Use with caution when using the same annotation on multiple ingresses for same service.
917+
918+
Possible values:
919+
920+
- Boolean value, just need to declare the flag
921+
922+
Example:
923+
924+
```yaml
925+
--enable-user-annotations-on-ingress
926+
```
927+
928+
<p align='right'><a href='#haproxy-kubernetes-ingress-controller'>:arrow_up_small: back to top</a></p>
929+
930+
***
931+

documentation/doc.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,14 @@ image_arguments:
430430
default: false
431431
version_min: "3.0"
432432
example: --disable-ingress-status-update
433+
- argument: --enable-user-annotations-on-ingress
434+
description: |-
435+
Enable support for user annotations on ingress resources.
436+
Use with caution when using the same annotation on multiple ingresses for same service.
437+
example: --enable-user-annotations-on-ingress
438+
version_min: "3.2"
439+
values:
440+
- Boolean value, just need to declare the flag
433441
groups:
434442
config-snippet:
435443
header: |-

documentation/user-annotations.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,34 @@ its similar as with other configuration values, except we define it as configmap
342342
`frontend.<frontend-name>.<org>/<user-annotation-name>`
343343

344344
the only difference is extra information what frontend this settings belong to. With HAProxy Ingress controller, you have 3 different frontends: `http`, `https` and `stats`, each can be customized with user annotations.
345+
346+
347+
## Where can user annotations can be defined ?
348+
349+
### Frontend Annotations
350+
351+
Frontend Annotations can be defined in Ingress Controller configmap. not as a key-value, but as a annotation of configmap
352+
353+
```yaml
354+
apiVersion: v1
355+
kind: ConfigMap
356+
metadata:
357+
name: haproxy-kubernetes-ingress
358+
namespace: haproxy-controller
359+
annotations:
360+
frontend.<frontend-name>.<org>/<user-annotation-name>: <value>
361+
```
362+
363+
### Backend Annotations
364+
365+
you can define them on:
366+
367+
- `configmap` - this will be applied for each backend
368+
- ⚠ `ingress` - this will be applied on services used in ingress. **use with precaution.**
369+
- setting user annotations on ingress level is disabled by default!
370+
- use `--enable-user-annotations-on-ingress` to enable it. Setting different annotation values in different ingresses for same service will trigger **inconsistencies**, so this is not encouraged. use `service` annotations.
371+
- `service` - this will be applied just on service
372+
373+
#### what happens if you try to use same annotation on multiple places
374+
375+
Service annotation have highest priority, only if service one does not exist, ingress one will be applied, same goes for configmap, it will be used only if ingress and service annotation do not exist.

pkg/annotations/common/main.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,9 @@ func GetValuesAndIndices(annotationName string, customAnnotationPrefix string, a
9292
if strings.HasPrefix(k, customAnnotationPrefix) {
9393
// Remove the prefix from the key
9494
annotationName := strings.TrimPrefix(k, customAnnotationPrefix)
95-
if _, ok := customResult[annotationName]; ok {
96-
// If the key already exists, prepend the value (so service is most important one)
97-
customResult[annotationName] = v + "\n" + customResult[annotationName]
98-
} else {
99-
// Otherwise, set the value
95+
if _, ok := customResult[annotationName]; !ok {
96+
// add it only if we do not have it yet,
97+
// this is due to priority, Service > Ingress > ConfigMap
10098
customResult[annotationName] = v
10199
}
102100
}

pkg/k8s/informers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ func (k k8s) addIngressHandlers(eventChan chan k8ssync.SyncDataEvent, informer c
637637
_, err := informer.AddEventHandler(
638638
cache.ResourceEventHandlerFuncs{
639639
AddFunc: func(obj interface{}) {
640-
item, err := store.ConvertToIngress(obj)
640+
item, err := store.ConvertToIngress(obj, osArgs.EnableUserAnnotationsIngress)
641641
if err != nil {
642642
logger.Errorf("%s: Invalid data from k8s api, %s", k8ssync.INGRESS, obj)
643643
return
@@ -654,7 +654,7 @@ func (k k8s) addIngressHandlers(eventChan chan k8ssync.SyncDataEvent, informer c
654654
eventChan <- ToSyncDataEvent(item, item, uid, resourceVersion)
655655
},
656656
DeleteFunc: func(obj interface{}) {
657-
item, err := store.ConvertToIngress(obj)
657+
item, err := store.ConvertToIngress(obj, osArgs.EnableUserAnnotationsIngress)
658658
if err != nil {
659659
logger.Errorf("%s: Invalid data from k8s api, %s", k8ssync.INGRESS, obj)
660660
return
@@ -671,7 +671,7 @@ func (k k8s) addIngressHandlers(eventChan chan k8ssync.SyncDataEvent, informer c
671671
eventChan <- ToSyncDataEvent(item, item, uid, resourceVersion)
672672
},
673673
UpdateFunc: func(oldObj, newObj interface{}) {
674-
item, err := store.ConvertToIngress(newObj)
674+
item, err := store.ConvertToIngress(newObj, osArgs.EnableUserAnnotationsIngress)
675675
if err != nil {
676676
logger.Errorf("%s: Invalid data from k8s api, %s", k8ssync.INGRESS, oldObj)
677677
return

pkg/store/convert.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ const (
3535

3636
// ConvertToIngress detects the interface{} provided by the SharedInformer and select
3737
// the proper strategy to convert and return the resource as a store.Ingress struct
38-
func ConvertToIngress(resource interface{}) (ingress *Ingress, err error) {
38+
func ConvertToIngress(resource interface{}, enableUserAnnotations bool) (ingress *Ingress, err error) {
3939
switch t := resource.(type) {
4040
case *networkingv1.Ingress:
41-
ingress = ingressNetworkingV1Strategy{ig: resource.(*networkingv1.Ingress)}.ConvertIngress()
41+
ingress = ingressNetworkingV1Strategy{ig: resource.(*networkingv1.Ingress)}.ConvertIngress(enableUserAnnotations)
4242
default:
4343
err = fmt.Errorf("unrecognized type for: %T", t)
4444
}
@@ -82,14 +82,14 @@ type ingressNetworkingV1Strategy struct {
8282
class *networkingv1.IngressClass
8383
}
8484

85-
func (n ingressNetworkingV1Strategy) ConvertIngress() *Ingress {
85+
func (n ingressNetworkingV1Strategy) ConvertIngress(enableUserAnnotations bool) *Ingress {
8686
ing := &Ingress{
8787
IngressCore: IngressCore{
8888
APIVersion: NETWORKINGV1,
8989
Namespace: n.ig.GetNamespace(),
9090
Name: n.ig.GetName(),
9191
Class: getIgClass(n.ig.Spec.IngressClassName),
92-
Annotations: CopyAnnotations(n.ig.GetAnnotations()),
92+
Annotations: CopyAnnotationsWithFilter(n.ig.GetAnnotations(), enableUserAnnotations),
9393
Rules: func(ingressRules []networkingv1.IngressRule) map[string]*IngressRule {
9494
rules := make(map[string]*IngressRule)
9595
for _, k8sRule := range ingressRules {
@@ -196,8 +196,21 @@ func getIgClass(className *string) string {
196196

197197
// CopyAnnotations returns a copy of annotations map and removes prefixe from annotations name
198198
func CopyAnnotations(in map[string]string) map[string]string {
199+
return CopyAnnotationsWithFilter(in, true)
200+
}
201+
202+
// CopyAnnotationsWithFilter returns a copy of annotations map and removes prefixe from annotations name
203+
func CopyAnnotationsWithFilter(in map[string]string, enableUserAnnotations bool) map[string]string {
199204
out := make(map[string]string, len(in))
200205
for name, value := range in {
206+
if !enableUserAnnotations {
207+
if strings.HasPrefix(name, "backend.") {
208+
continue
209+
}
210+
if strings.HasPrefix(name, "frontend.") {
211+
continue
212+
}
213+
}
201214
out[cleanAnnotation(name)] = value
202215
}
203216
return out

pkg/utils/flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,5 @@ type OSArgs struct {
123123
CRDInputFile string `long:"input-file" description:"The file path of a CRD manifest to convert"`
124124
CRDOutputFile string `long:"output-file" description:"The file path of the converted (to the most recent version) CRD manifest"`
125125
DisableIngressStatusUpdate bool `long:"disable-ingress-status-update" description:"If true, disables updating the status field of Ingress resources"`
126+
EnableUserAnnotationsIngress bool `long:"enable-user-annotations-on-ingress" description:"allow custom user annotations on ingress"`
126127
}

0 commit comments

Comments
 (0)