Skip to content

Commit cb3083b

Browse files
feat(ingress) : add common_lb_config as an ingress config annotation (#1203)
## Summary this allows healthy_panic_threshold to be set on pomerium routes, by exposing the `common_lb_config` on the ingress annotations: ```yaml // ... annotations: <ingress-prefix>/healthy_panic_threshold : <float64> ``` ## Related issues <!-- For example... Fixes #159 --> ## Checklist - [x] reference any related issues - [ ] updated docs - [x] updated unit tests - [ ] updated UPGRADING.md - [x] add appropriate tag (`improvement` / `bug` / etc) - [x] ready for review Signed-off-by: alexandreLamarre <alamarre@pomerium.com>
1 parent 5ad748a commit cb3083b

4 files changed

Lines changed: 73 additions & 3 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/iancoleman/strcase v0.3.0
1717
github.com/martinlindhe/base36 v1.1.1
1818
github.com/open-policy-agent/opa v1.7.1
19+
github.com/pomerium/csrf v1.7.0
1920
github.com/pomerium/pomerium v0.28.1-0.20250717151855-4de63aa74657
2021
github.com/rs/zerolog v1.34.0
2122
github.com/sergi/go-diff v1.4.0
@@ -177,7 +178,6 @@ require (
177178
github.com/pkg/errors v0.9.1 // indirect
178179
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
179180
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
180-
github.com/pomerium/csrf v1.7.0 // indirect
181181
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524 // indirect
182182
github.com/pomerium/envoy-custom v1.34.1-rc3 // indirect
183183
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 // indirect

pomerium/ingress_annotations.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ var (
6565
"outlier_detection",
6666
"ring_hash_lb_config",
6767
})
68+
commonLbConfig = boolMap([]string{
69+
"healthy_panic_threshold",
70+
})
6871
tlsAnnotations = boolMap([]string{
6972
model.TLSClientSecret,
7073
model.TLSCustomCASecret,
@@ -109,7 +112,7 @@ func boolMap(keys []string) map[string]bool {
109112
}
110113

111114
type keys struct {
112-
Base, Envoy, Policy, TLS, Etc, Secret, MCPServer, MCPClient map[string]string
115+
Base, Envoy, Policy, CommonLb, TLS, Etc, Secret, MCPServer, MCPClient map[string]string
113116
}
114117

115118
func removeKeyPrefix(src map[string]string, prefix string) (*keys, error) {
@@ -118,6 +121,7 @@ func removeKeyPrefix(src map[string]string, prefix string) (*keys, error) {
118121
Base: make(map[string]string),
119122
Envoy: make(map[string]string),
120123
Policy: make(map[string]string),
124+
CommonLb: make(map[string]string),
121125
TLS: make(map[string]string),
122126
Etc: make(map[string]string),
123127
Secret: make(map[string]string),
@@ -142,6 +146,7 @@ func removeKeyPrefix(src map[string]string, prefix string) (*keys, error) {
142146
}{
143147
{baseAnnotations, kv.Base},
144148
{envoyAnnotations, kv.Envoy},
149+
{commonLbConfig, kv.CommonLb},
145150
{policyAnnotations, kv.Policy},
146151
{tlsAnnotations, kv.TLS},
147152
{secretAnnotations, kv.Secret},
@@ -179,6 +184,13 @@ func applyAnnotations(
179184
if err = unmarshalAnnotations(r.EnvoyOpts, kv.Envoy); err != nil {
180185
return err
181186
}
187+
if len(kv.CommonLb) > 0 {
188+
r.EnvoyOpts.CommonLbConfig = new(envoy_config_cluster_v3.Cluster_CommonLbConfig)
189+
if err := unmarshalAnnotations(r.EnvoyOpts.CommonLbConfig, kv.CommonLb); err != nil {
190+
return err
191+
}
192+
}
193+
182194
if err = applyTLSAnnotations(r, kv.TLS, ic.Secrets, ic.Ingress.Namespace); err != nil {
183195
return err
184196
}

pomerium/ingress_annotations_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ func TestAnnotations(t *testing.T) {
223223
envoy_config_core_v3.HealthCheck_HttpHealthCheck{},
224224
envoy_config_cluster_v3.Cluster_LeastRequestLbConfig{},
225225
envoy_config_core_v3.RuntimeDouble{},
226+
envoy_config_cluster_v3.Cluster_CommonLbConfig{},
226227
envoy_config_cluster_v3.Cluster_SlowStartConfig{},
227228
wrapperspb.UInt32Value{},
228229
pb.CircuitBreakerThresholds{},
@@ -657,6 +658,53 @@ func TestMCPAnnotations(t *testing.T) {
657658
})
658659
}
659660

661+
func TestCommonLbAnnotation(t *testing.T) {
662+
t.Run("healthy_panic_threshold annotation", func(t *testing.T) {
663+
type testcase struct {
664+
input float64
665+
expected float64
666+
}
667+
668+
tcs := []testcase{
669+
{
670+
input: 50,
671+
expected: 50,
672+
},
673+
{
674+
input: -15.0,
675+
expected: -15.0,
676+
},
677+
{
678+
input: 75.0,
679+
expected: 75.0,
680+
},
681+
}
682+
683+
for _, tc := range tcs {
684+
r := &pb.Route{}
685+
ic := &model.IngressConfig{
686+
AnnotationPrefix: "a",
687+
Ingress: &networkingv1.Ingress{
688+
ObjectMeta: v1.ObjectMeta{
689+
Name: "test-ingress",
690+
Namespace: "default",
691+
Annotations: map[string]string{
692+
"a/healthy_panic_threshold": fmt.Sprintf("%f", tc.input),
693+
},
694+
},
695+
},
696+
}
697+
err := applyAnnotations(r, ic)
698+
require.NoError(t, err)
699+
700+
require.NotNil(t, r.EnvoyOpts)
701+
require.NotNil(t, r.EnvoyOpts.CommonLbConfig)
702+
require.NotNil(t, r.EnvoyOpts.CommonLbConfig.HealthyPanicThreshold)
703+
require.Equal(t, r.EnvoyOpts.CommonLbConfig.HealthyPanicThreshold.Value, tc.expected)
704+
}
705+
})
706+
}
707+
660708
func TestNameAnnotation(t *testing.T) {
661709
t.Run("custom name annotation", func(t *testing.T) {
662710
r := &pb.Route{}

pomerium/proto.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ func unmarshalAnnotations(dst proto.Message, kvs map[string]string) error {
3737
}
3838

3939
func preprocessAnnotationMessage(md protoreflect.MessageDescriptor, data any) any {
40-
switch md.FullName() {
40+
name := md.FullName()
41+
switch name {
4142
case "google.protobuf.Duration":
4243
// convert go duration strings into protojson duration strings
4344
if v, ok := data.(string); ok {
@@ -47,6 +48,15 @@ func preprocessAnnotationMessage(md protoreflect.MessageDescriptor, data any) an
4748
if v, ok := data.([]any); ok {
4849
return map[string]any{"values": v}
4950
}
51+
case "envoy.type.v3.Percent":
52+
// convert percentage value to percentage message {"value" : <double>}
53+
v, ok := data.(float64)
54+
if ok {
55+
return map[string]float64{
56+
"value": v,
57+
}
58+
}
59+
fallthrough
5060
default:
5161
// preprocess all the fields
5262
if v, ok := data.(map[string]any); ok {

0 commit comments

Comments
 (0)