ingress: add alternate resource backend

Signed-off-by: Christopher M. Luciano <cmluciano@us.ibm.com>
This commit is contained in:
Christopher M. Luciano
2020-02-24 14:15:55 -05:00
parent 8508875e4d
commit 912f05bafb
23 changed files with 1014 additions and 365 deletions

View File

@@ -198,7 +198,8 @@ var ValidateIngressName = apimachineryvalidation.NameIsDNSSubdomain
// IngressValidationOptions cover beta to GA transitions for HTTP PathType
type IngressValidationOptions struct {
requireRegexPath bool
requireRegexPath bool
allowResourceBackend bool
}
// ValidateIngress validates Ingresses on create and update.
@@ -215,6 +216,8 @@ func ValidateIngressCreate(ingress *networking.Ingress, requestGV schema.GroupVe
opts = IngressValidationOptions{
// TODO(robscott): Remove regex validation for 1.19.
requireRegexPath: true,
// TODO(cmluciano): Allow resource backend for 1.19.
allowResourceBackend: false,
}
allErrs = append(allErrs, validateIngress(ingress, opts, requestGV)...)
annotationVal, annotationIsSet := ingress.Annotations[annotationIngressClass]
@@ -233,7 +236,8 @@ func ValidateIngressUpdate(ingress, oldIngress *networking.Ingress, requestGV sc
// TODO(robscott): Remove regex validation for 1.19.
// Only require regex path validation for this Ingress if the previous
// version of the Ingress also passed that validation.
requireRegexPath: allPathsPassRegexValidation(oldIngress),
requireRegexPath: allPathsPassRegexValidation(oldIngress),
allowResourceBackend: resourceBackendPresent(oldIngress),
}
allErrs = append(allErrs, validateIngress(ingress, opts, requestGV)...)
@@ -269,7 +273,7 @@ func ValidateIngressSpec(spec *networking.IngressSpec, fldPath *field.Path, opts
allErrs = append(allErrs, field.Invalid(fldPath, spec.Rules, errMsg))
}
if spec.Backend != nil {
allErrs = append(allErrs, validateIngressBackend(spec.Backend, fldPath.Child("backend"))...)
allErrs = append(allErrs, validateIngressBackend(spec.Backend, fldPath.Child("backend"), opts)...)
}
if len(spec.Rules) > 0 {
allErrs = append(allErrs, validateIngressRules(spec.Rules, fldPath.Child("rules"), opts)...)
@@ -381,22 +385,34 @@ func validateHTTPIngressPath(path *networking.HTTPIngressPath, fldPath *field.Pa
}
}
allErrs = append(allErrs, validateIngressBackend(&path.Backend, fldPath.Child("backend"))...)
allErrs = append(allErrs, validateIngressBackend(&path.Backend, fldPath.Child("backend"), opts)...)
return allErrs
}
// validateIngressBackend tests if a given backend is valid.
func validateIngressBackend(backend *networking.IngressBackend, fldPath *field.Path) field.ErrorList {
func validateIngressBackend(backend *networking.IngressBackend, fldPath *field.Path, opts IngressValidationOptions) field.ErrorList {
allErrs := field.ErrorList{}
// All backends must reference a single local service by name, and a single service port by name or number.
if len(backend.ServiceName) == 0 {
return append(allErrs, field.Required(fldPath.Child("serviceName"), ""))
hasResourceBackend := backend.Resource != nil
hasServiceBackend := len(backend.ServiceName) > 0 || backend.ServicePort.IntVal != 0 || len(backend.ServicePort.StrVal) > 0
switch {
case hasResourceBackend && hasServiceBackend:
return append(allErrs, field.Invalid(fldPath, "", "cannot set both resource and service backends"))
case hasResourceBackend && !opts.allowResourceBackend:
return append(allErrs, field.Forbidden(fldPath.Child("resource"), "not supported; only service backends are supported in this version"))
case hasResourceBackend:
allErrs = append(allErrs, validateIngressTypedLocalObjectReference(backend.Resource, fldPath.Child("resource"))...)
default:
if len(backend.ServiceName) == 0 {
return append(allErrs, field.Required(fldPath.Child("serviceName"), ""))
}
for _, msg := range apivalidation.ValidateServiceName(backend.ServiceName, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceName"), backend.ServiceName, msg))
}
allErrs = append(allErrs, apivalidation.ValidatePortNumOrName(backend.ServicePort, fldPath.Child("servicePort"))...)
}
for _, msg := range apivalidation.ValidateServiceName(backend.ServiceName, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceName"), backend.ServiceName, msg))
}
allErrs = append(allErrs, apivalidation.ValidatePortNumOrName(backend.ServicePort, fldPath.Child("servicePort"))...)
return allErrs
}
@@ -426,7 +442,7 @@ func validateIngressClassSpec(spec *networking.IngressClassSpec, fldPath *field.
allErrs = append(allErrs, field.TooLong(fldPath.Child("controller"), spec.Controller, maxLenIngressClassController))
}
allErrs = append(allErrs, validation.IsDomainPrefixedPath(fldPath.Child("controller"), spec.Controller)...)
allErrs = append(allErrs, validateIngressClassParameters(spec.Parameters, fldPath.Child("parameters"))...)
allErrs = append(allErrs, validateIngressTypedLocalObjectReference(spec.Parameters, fldPath.Child("parameters"))...)
return allErrs
}
@@ -436,8 +452,8 @@ func validateIngressClassSpecUpdate(newSpec, oldSpec *networking.IngressClassSpe
return apivalidation.ValidateImmutableField(newSpec.Controller, oldSpec.Controller, fldPath.Child("controller"))
}
// validateIngressClassParameters ensures that Parameters fields are valid.
func validateIngressClassParameters(params *api.TypedLocalObjectReference, fldPath *field.Path) field.ErrorList {
// validateIngressTypedLocalObjectReference ensures that Parameters fields are valid.
func validateIngressTypedLocalObjectReference(params *api.TypedLocalObjectReference, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if params == nil {
@@ -487,3 +503,20 @@ func allPathsPassRegexValidation(ingress *networking.Ingress) bool {
}
return true
}
func resourceBackendPresent(ingress *networking.Ingress) bool {
if ingress.Spec.Backend != nil && ingress.Spec.Backend.Resource != nil {
return true
}
for _, rule := range ingress.Spec.Rules {
if rule.HTTP == nil {
continue
}
for _, path := range rule.HTTP.Paths {
if path.Backend.Resource != nil {
return true
}
}
}
return false
}