Skip to content

Commit 25bb559

Browse files
committed
[api] lowercase Backend.spec.protocol on write
The xDS translator switches on Spec.Protocol case-sensitively (pkg/gateway/gatewayapi/route.go). A stray "H2" slipped past the kubebuilder enum and silently fell through the switch, so the upstream TLS context was never applied and Envoy spoke plaintext to port 443 — the server reset the connection and the gateway returned 503s. Add a Defaulter on Backend (v1alpha + v1alpha2) that lowercases Spec.Protocol before validation runs. "H2", "H2c", "TLS" now persist as their lowercase enum values and match the translator. Unknown values get lowercased too so they at least show up consistently in logs and describe output. No behavior change for routes whose Backend was already stored with a valid lowercase value.
1 parent c823174 commit 25bb559

3 files changed

Lines changed: 49 additions & 0 deletions

File tree

api/core/v1alpha/backend_validate.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net"
7+
"strings"
78

89
"k8s.io/apimachinery/pkg/runtime"
910
"k8s.io/apimachinery/pkg/util/validation"
@@ -12,10 +13,18 @@ import (
1213
)
1314

1415
var (
16+
_ resourcestrategy.Defaulter = &Backend{}
1517
_ resourcestrategy.Validater = &Backend{}
1618
_ resourcestrategy.ValidateUpdater = &Backend{}
1719
)
1820

21+
// Default normalizes user-supplied fields before validation. The xDS
22+
// translator matches Spec.Protocol case-sensitively, so lowercase on
23+
// write to keep "H2" from silently falling through to plaintext.
24+
func (r *Backend) Default() {
25+
r.Spec.Protocol = BackendProto(strings.ToLower(string(r.Spec.Protocol)))
26+
}
27+
1928
func (r *Backend) Validate(ctx context.Context) field.ErrorList {
2029
return r.validate()
2130
}

api/core/v1alpha2/backend_validate.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net"
7+
"strings"
78

89
"k8s.io/apimachinery/pkg/runtime"
910
"k8s.io/apimachinery/pkg/util/validation"
@@ -12,9 +13,18 @@ import (
1213
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcestrategy"
1314
)
1415

16+
var _ resourcestrategy.Defaulter = &Backend{}
1517
var _ resourcestrategy.Validater = &Backend{}
1618
var _ resourcestrategy.ValidateUpdater = &Backend{}
1719

20+
// Default normalizes user-supplied fields before validation. The xDS
21+
// translator switches on Spec.Protocol case-sensitively, so a stray "H2"
22+
// would silently drop the upstream TLS context and Envoy would send
23+
// plaintext to port 443. Lowercase on write to match the enum.
24+
func (r *Backend) Default() {
25+
r.Spec.Protocol = BackendProto(strings.ToLower(string(r.Spec.Protocol)))
26+
}
27+
1828
func (r *Backend) Validate(ctx context.Context) field.ErrorList {
1929
return r.validate()
2030
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package v1alpha2
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestBackend_Default_NormalizesProtocolCase(t *testing.T) {
8+
tests := []struct {
9+
in, want BackendProto
10+
}{
11+
{"", ""},
12+
{"h2", BackendProtoH2},
13+
{"H2", BackendProtoH2},
14+
{"H2c", BackendProtoH2C},
15+
{"TLS", BackendProtoTLS},
16+
// Unknown values stay lowercased; the xDS translator will fall
17+
// through to its plaintext default, but at least diagnostic logs
18+
// show a stable value rather than whatever case the user typed.
19+
{"HTTP3", "http3"},
20+
}
21+
for _, tt := range tests {
22+
t.Run(string(tt.in), func(t *testing.T) {
23+
b := &Backend{Spec: BackendSpec{Protocol: tt.in, Endpoints: []BackendEndpoint{{FQDN: "example.com"}}}}
24+
b.Default()
25+
if b.Spec.Protocol != tt.want {
26+
t.Fatalf("Default: protocol = %q, want %q", b.Spec.Protocol, tt.want)
27+
}
28+
})
29+
}
30+
}

0 commit comments

Comments
 (0)