Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove duplicate validation from CRD & Webhook #872

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 4 additions & 48 deletions apis/v1alpha2/validation/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ limitations under the License.
package validation

import (
"net"
"strings"

"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"

gatewayv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
Expand All @@ -29,49 +25,9 @@ import (
// ValidateGateway validates gw according to the Gateway API specification.
// For additional details of the Gateway spec, refer to:
// https://gateway-api.sigs.k8s.io/spec/#gateway.networking.k8s.io/v1alpha2.Gateway
//
// Validation that is not possible with CRD annotations may be added here in the future.
// See https://github.com/kubernetes-sigs/gateway-api/issues/868 for more information.
func ValidateGateway(gw *gatewayv1a2.Gateway) field.ErrorList {
return validateGatewaySpec(&gw.Spec, field.NewPath("spec"))
}

// validateGatewaySpec validates whether required fields of spec are set according to the
// Gateway API specification.
func validateGatewaySpec(spec *gatewayv1a2.GatewaySpec, path *field.Path) field.ErrorList {
// TODO [danehans]: Add additional validation of spec fields.
return validateGatewayListeners(spec.Listeners, path.Child("listeners"))
}

// validateGatewayListeners validates whether required fields of listeners are set according
// to the Gateway API specification.
func validateGatewayListeners(listeners []gatewayv1a2.Listener, path *field.Path) field.ErrorList {
// TODO [danehans]: Add additional validation of listener fields.
return validateListenerHostname(listeners, path)
}

// validateListenerHostname validates each listener hostname is not an IP address and is one
// of the following:
// - A fully qualified domain name of a network host, as defined by RFC 3986.
// - A DNS subdomain as defined by RFC 1123.
// - A wildcard DNS subdomain as defined by RFC 1034 (section 4.3.3).
func validateListenerHostname(listeners []gatewayv1a2.Listener, path *field.Path) field.ErrorList {
var errs field.ErrorList
for i, h := range listeners {
// When unspecified, “”, or *, all hostnames are matched.
if h.Hostname == nil || (*h.Hostname == "" || *h.Hostname == "*") {
continue
}
hostname := string(*h.Hostname)
if ip := net.ParseIP(hostname); ip != nil {
errs = append(errs, field.Invalid(path.Index(i).Child("hostname"), hostname, "must be a DNS hostname, not an IP address"))
}
if strings.Contains(hostname, "*") {
for _, msg := range validation.IsWildcardDNS1123Subdomain(hostname) {
errs = append(errs, field.Invalid(path.Index(i).Child("hostname"), hostname, msg))
}
} else {
for _, msg := range validation.IsDNS1123Subdomain(hostname) {
errs = append(errs, field.Invalid(path.Index(i).Child("hostname"), hostname, msg))
}
}
}
return errs
return nil
}
162 changes: 0 additions & 162 deletions apis/v1alpha2/validation/gateway_test.go

This file was deleted.

108 changes: 0 additions & 108 deletions pkg/admission/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ func TestServeHTTPInvalidMethod(t *testing.T) {
}

func TestServeHTTPSubmissions(t *testing.T) {

const invalidHostname = "!@!.foo.com"
const lowercaseRFC1123ErrorMessage = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')"

for _, apiVersion := range []string{
"admission.k8s.io/v1",
"admission.k8s.io/v1",
Expand Down Expand Up @@ -173,58 +169,6 @@ func TestServeHTTPSubmissions(t *testing.T) {
Result: &metav1.Status{},
},
},
{
name: "invalid v1alpha1 Gateway resource with bad listener hostname",
reqBody: dedent.Dedent(`{
"kind": "AdmissionReview",
"apiVersion": "` + apiVersion + `",
"request": {
"uid": "7313cd05-eddc-4150-b88c-971a0d53b2ab",
"resource": {
"group": "networking.x-k8s.io",
"version": "v1alpha1",
"resource": "gateways"
},
"object": {
"kind": "Gateway",
"apiVersion": "networking.x-k8s.io/v1alpha1",
"metadata": {
"name": "gateway-1",
"labels": {
"app": "foo"
}
},
"spec": {
"gatewayClassName": "contour-class",
"listeners": [
{
"port": 80,
"protocol": "HTTP",
"hostname": "` + invalidHostname + `",
"routes": {
"group": "networking.x-k8s.io",
"kind": "HTTPRoute",
"namespaces": {
"from": "All"
}
}
}
]
}
},
"operation": "CREATE"
}
}`),
wantRespCode: http.StatusOK,
wantSuccessResponse: admission.AdmissionResponse{
UID: "7313cd05-eddc-4150-b88c-971a0d53b2ab",
Allowed: false,
Result: &metav1.Status{
Code: 400,
Message: fmt.Sprintf("spec.listeners[0].hostname: Invalid value: %q: %s", invalidHostname, lowercaseRFC1123ErrorMessage),
},
},
},
{
name: "valid v1alpha2 Gateway resource",
reqBody: dedent.Dedent(`{
Expand Down Expand Up @@ -274,58 +218,6 @@ func TestServeHTTPSubmissions(t *testing.T) {
Result: &metav1.Status{},
},
},
{
name: "invalid v1alpha2 Gateway resource with bad listener hostname",
reqBody: dedent.Dedent(`{
"kind": "AdmissionReview",
"apiVersion": "` + apiVersion + `",
"request": {
"uid": "7313cd05-eddc-4150-b88c-971a0d53b2ab",
"resource": {
"group": "gateway.networking.k8s.io",
"version": "v1alpha2",
"resource": "gateways"
},
"object": {
"kind": "Gateway",
"apiVersion": "gateway.networking.k8s.io/v1alpha2",
"metadata": {
"name": "gateway-1",
"labels": {
"app": "foo"
}
},
"spec": {
"gatewayClassName": "contour-class",
"listeners": [
{
"port": 80,
"protocol": "HTTP",
"hostname": "` + invalidHostname + `",
"routes": {
"group": "gateway.networking.k8s.io",
"kind": "HTTPRoute",
"namespaces": {
"from": "All"
}
}
}
]
}
},
"operation": "CREATE"
}
}`),
wantRespCode: http.StatusOK,
wantSuccessResponse: admission.AdmissionResponse{
UID: "7313cd05-eddc-4150-b88c-971a0d53b2ab",
Allowed: false,
Result: &metav1.Status{
Code: 400,
Message: fmt.Sprintf("spec.listeners[0].hostname: Invalid value: %q: %s", invalidHostname, lowercaseRFC1123ErrorMessage),
},
},
},
{
name: "valid HTTPRoute resource",
reqBody: dedent.Dedent(`{
Expand Down