Merge pull request #74998 from mbohlool/pippin

Webhook configurations can choose which version of Review request they accept
This commit is contained in:
Kubernetes Prow Robot
2019-03-08 03:01:26 -08:00
committed by GitHub
33 changed files with 1777 additions and 783 deletions

View File

@@ -43,6 +43,7 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
i := int32(30)
obj.TimeoutSeconds = &i
}
obj.AdmissionReviewVersions = []string{"v1beta1"}
},
}
}

View File

@@ -239,6 +239,15 @@ type Webhook struct {
// The timeout value must be between 1 and 30 seconds.
// +optional
TimeoutSeconds *int32
// AdmissionReviewVersions is an ordered list of preferred `AdmissionReview`
// versions the Webhook expects. API server will try to use first version in
// the list which it supports. If none of the versions specified in this list
// supported by API server, validation will fail for this object.
// If the webhook configuration has already been persisted with a version apiserver
// does not understand, calls to the webhook will fail and be subject to the failure policy.
// +optional
AdmissionReviewVersions []string
}
// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make

View File

@@ -44,6 +44,10 @@ func SetDefaults_Webhook(obj *admissionregistrationv1beta1.Webhook) {
obj.TimeoutSeconds = new(int32)
*obj.TimeoutSeconds = 30
}
if len(obj.AdmissionReviewVersions) == 0 {
obj.AdmissionReviewVersions = []string{admissionregistrationv1beta1.SchemeGroupVersion.Version}
}
}
func SetDefaults_Rule(obj *admissionregistrationv1beta1.Rule) {

View File

@@ -304,6 +304,7 @@ func autoConvert_v1beta1_Webhook_To_admissionregistration_Webhook(in *v1beta1.We
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
out.SideEffects = (*admissionregistration.SideEffectClass)(unsafe.Pointer(in.SideEffects))
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
out.AdmissionReviewVersions = *(*[]string)(unsafe.Pointer(&in.AdmissionReviewVersions))
return nil
}
@@ -322,6 +323,7 @@ func autoConvert_admissionregistration_Webhook_To_v1beta1_Webhook(in *admissionr
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
out.SideEffects = (*v1beta1.SideEffectClass)(unsafe.Pointer(in.SideEffects))
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
out.AdmissionReviewVersions = *(*[]string)(unsafe.Pointer(&in.AdmissionReviewVersions))
return nil
}

View File

@@ -22,6 +22,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/apis/admissionregistration/validation",
deps = [
"//pkg/apis/admissionregistration:go_default_library",
"//pkg/apis/admissionregistration/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",

View File

@@ -24,9 +24,11 @@ import (
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/kubernetes/pkg/apis/admissionregistration"
"k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1"
)
func hasWildcard(slice []string) bool {
@@ -150,18 +152,71 @@ func validateRule(rule *admissionregistration.Rule, fldPath *field.Path, allowSu
return allErrors
}
var AcceptedAdmissionReviewVersions = []string{v1beta1.SchemeGroupVersion.Version}
func isAcceptedAdmissionReviewVersion(v string) bool {
for _, version := range AcceptedAdmissionReviewVersions {
if v == version {
return true
}
}
return false
}
func validateAdmissionReviewVersions(versions []string, requireRecognizedVersion bool, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{}
// Currently only v1beta1 accepted in AdmissionReviewVersions
if len(versions) < 1 {
allErrors = append(allErrors, field.Required(fldPath, ""))
} else {
seen := map[string]bool{}
hasAcceptedVersion := false
for i, v := range versions {
if seen[v] {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), v, "duplicate version"))
continue
}
seen[v] = true
for _, errString := range utilvalidation.IsDNS1035Label(v) {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), v, errString))
}
if isAcceptedAdmissionReviewVersion(v) {
hasAcceptedVersion = true
}
}
if requireRecognizedVersion && !hasAcceptedVersion {
allErrors = append(allErrors, field.Invalid(
fldPath, versions,
fmt.Sprintf("none of the versions accepted by this server. accepted version(s) are %v",
strings.Join(AcceptedAdmissionReviewVersions, ", "))))
}
}
return allErrors
}
func ValidateValidatingWebhookConfiguration(e *admissionregistration.ValidatingWebhookConfiguration) field.ErrorList {
return validateValidatingWebhookConfiguration(e, true)
}
func validateValidatingWebhookConfiguration(e *admissionregistration.ValidatingWebhookConfiguration, requireRecognizedVersion bool) field.ErrorList {
allErrors := genericvalidation.ValidateObjectMeta(&e.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
for i, hook := range e.Webhooks {
allErrors = append(allErrors, validateWebhook(&hook, field.NewPath("webhooks").Index(i))...)
allErrors = append(allErrors, validateAdmissionReviewVersions(hook.AdmissionReviewVersions, requireRecognizedVersion, field.NewPath("webhooks").Index(i).Child("admissionReviewVersions"))...)
}
return allErrors
}
func ValidateMutatingWebhookConfiguration(e *admissionregistration.MutatingWebhookConfiguration) field.ErrorList {
return validateMutatingWebhookConfiguration(e, true)
}
func validateMutatingWebhookConfiguration(e *admissionregistration.MutatingWebhookConfiguration, requireRecognizedVersion bool) field.ErrorList {
allErrors := genericvalidation.ValidateObjectMeta(&e.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
for i, hook := range e.Webhooks {
allErrors = append(allErrors, validateWebhook(&hook, field.NewPath("webhooks").Index(i))...)
allErrors = append(allErrors, validateAdmissionReviewVersions(hook.AdmissionReviewVersions, requireRecognizedVersion, field.NewPath("webhooks").Index(i).Child("admissionReviewVersions"))...)
}
return allErrors
}
@@ -247,10 +302,28 @@ func validateRuleWithOperations(ruleWithOperations *admissionregistration.RuleWi
return allErrors
}
// hasAcceptedAdmissionReviewVersions returns true if all webhooks have at least one
// admission review version this apiserver accepts.
func hasAcceptedAdmissionReviewVersions(webhooks []admissionregistration.Webhook) bool {
for _, hook := range webhooks {
hasRecognizedVersion := false
for _, version := range hook.AdmissionReviewVersions {
if isAcceptedAdmissionReviewVersion(version) {
hasRecognizedVersion = true
break
}
}
if !hasRecognizedVersion && len(hook.AdmissionReviewVersions) > 0 {
return false
}
}
return true
}
func ValidateValidatingWebhookConfigurationUpdate(newC, oldC *admissionregistration.ValidatingWebhookConfiguration) field.ErrorList {
return ValidateValidatingWebhookConfiguration(newC)
return validateValidatingWebhookConfiguration(newC, hasAcceptedAdmissionReviewVersions(oldC.Webhooks))
}
func ValidateMutatingWebhookConfigurationUpdate(newC, oldC *admissionregistration.MutatingWebhookConfiguration) field.ErrorList {
return ValidateMutatingWebhookConfiguration(newC)
return validateMutatingWebhookConfiguration(newC, hasAcceptedAdmissionReviewVersions(oldC.Webhooks))
}

File diff suppressed because it is too large Load Diff

View File

@@ -267,6 +267,11 @@ func (in *Webhook) DeepCopyInto(out *Webhook) {
*out = new(int32)
**out = **in
}
if in.AdmissionReviewVersions != nil {
in, out := &in.AdmissionReviewVersions, &out.AdmissionReviewVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}