Skip to content

Commit bb83aa7

Browse files
committed
Webhook: Validate unique port, protocol per hostname for gateway listeners
Signed-off-by: Huang Xin <[email protected]>
1 parent ff862f1 commit bb83aa7

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

apis/v1beta1/validation/gateway.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ func validateGatewayListeners(listeners []gatewayv1b1.Listener, path *field.Path
6262
var errs field.ErrorList
6363
errs = append(errs, validateListenerTLSConfig(listeners, path)...)
6464
errs = append(errs, validateListenerHostname(listeners, path)...)
65+
errs = append(errs, validateUniqueProtocol(listeners, path)...)
66+
errs = append(errs, validateUniquePort(listeners, path)...)
6567
return errs
6668
}
6769

@@ -91,3 +93,57 @@ func validateListenerHostname(listeners []gatewayv1b1.Listener, path *field.Path
9193
}
9294
return errs
9395
}
96+
97+
// validateUniqueProtocol validates each listener hostname
98+
// should not have the duplicate protocols
99+
func validateUniqueProtocol(listeners []gatewayv1b1.Listener, path *field.Path) field.ErrorList {
100+
var errs field.ErrorList
101+
hostnameProtocolUnique := make(map[gatewayv1b1.Hostname]map[gatewayv1b1.ProtocolType]int)
102+
for i, h := range listeners {
103+
if h.Hostname == nil {
104+
continue
105+
}
106+
if len(hostnameProtocolUnique) == 0 {
107+
hostnameProtocolUnique[*h.Hostname] = map[gatewayv1b1.ProtocolType]int{h.Protocol: i}
108+
continue
109+
}
110+
if _, hostnameFound := hostnameProtocolUnique[*h.Hostname]; hostnameFound {
111+
if _, protocolFound := hostnameProtocolUnique[*h.Hostname][h.Protocol]; protocolFound {
112+
errs = append(errs, field.Forbidden(path.Index(i).Child("protocol"), fmt.Sprintf("should be unique in hostname: %v", *h.Hostname)))
113+
return errs
114+
} else {
115+
hostnameProtocolUnique[*h.Hostname][h.Protocol] = i
116+
}
117+
} else {
118+
hostnameProtocolUnique[*h.Hostname] = map[gatewayv1b1.ProtocolType]int{h.Protocol: i}
119+
}
120+
}
121+
return errs
122+
}
123+
124+
// validateUniquePort validates each listener hostname
125+
// should not have the duplicate ports
126+
func validateUniquePort(listeners []gatewayv1b1.Listener, path *field.Path) field.ErrorList {
127+
var errs field.ErrorList
128+
hostnamePortUnique := make(map[gatewayv1b1.Hostname]map[gatewayv1b1.PortNumber]int)
129+
for i, h := range listeners {
130+
if h.Hostname == nil {
131+
continue
132+
}
133+
if len(hostnamePortUnique) == 0 {
134+
hostnamePortUnique[*h.Hostname] = map[gatewayv1b1.PortNumber]int{h.Port: i}
135+
continue
136+
}
137+
if _, hostnameFound := hostnamePortUnique[*h.Hostname]; hostnameFound {
138+
if _, portFound := hostnamePortUnique[*h.Hostname][h.Port]; portFound {
139+
errs = append(errs, field.Forbidden(path.Index(i).Child("port"), fmt.Sprintf("should be unique in hostname: %v", *h.Hostname)))
140+
return errs
141+
} else {
142+
hostnamePortUnique[*h.Hostname][h.Port] = i
143+
}
144+
} else {
145+
hostnamePortUnique[*h.Hostname] = map[gatewayv1b1.PortNumber]int{h.Port: i}
146+
}
147+
}
148+
return errs
149+
}

apis/v1beta1/validation/gateway_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func TestValidateGateway(t *testing.T) {
2929
{
3030
Hostname: nil,
3131
},
32+
{
33+
Hostname: nil,
34+
},
3235
}
3336
addresses := []gatewayv1b1.GatewayAddress{
3437
{
@@ -82,6 +85,30 @@ func TestValidateGateway(t *testing.T) {
8285
},
8386
expectErrsOnFields: []string{"spec.listeners[0].hostname"},
8487
},
88+
"protocal is not unique in hostname": {
89+
mutate: func(gw *gatewayv1b1.Gateway) {
90+
hostname := gatewayv1b1.Hostname("foo.bar.com")
91+
gw.Spec.Listeners[0].Hostname = &hostname
92+
gw.Spec.Listeners[0].Protocol = gatewayv1b1.HTTPProtocolType
93+
gw.Spec.Listeners[0].Port = gatewayv1b1.PortNumber(80)
94+
gw.Spec.Listeners[1].Hostname = &hostname
95+
gw.Spec.Listeners[1].Protocol = gatewayv1b1.HTTPProtocolType
96+
gw.Spec.Listeners[1].Port = gatewayv1b1.PortNumber(81)
97+
},
98+
expectErrsOnFields: []string{"spec.listeners[1].protocol"},
99+
},
100+
"port is not unique in hostname": {
101+
mutate: func(gw *gatewayv1b1.Gateway) {
102+
hostname := gatewayv1b1.Hostname("foo.bar.com")
103+
gw.Spec.Listeners[0].Hostname = &hostname
104+
gw.Spec.Listeners[0].Protocol = gatewayv1b1.HTTPProtocolType
105+
gw.Spec.Listeners[0].Port = gatewayv1b1.PortNumber(80)
106+
gw.Spec.Listeners[1].Hostname = &hostname
107+
gw.Spec.Listeners[1].Protocol = gatewayv1b1.HTTPSProtocolType
108+
gw.Spec.Listeners[1].Port = gatewayv1b1.PortNumber(80)
109+
},
110+
expectErrsOnFields: []string{"spec.listeners[1].port"},
111+
},
85112
}
86113

87114
for name, tc := range testCases {

0 commit comments

Comments
 (0)