Merge pull request #74998 from mbohlool/pippin
Webhook configurations can choose which version of Review request they accept
This commit is contained in:
@@ -43,6 +43,7 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
i := int32(30)
|
||||
obj.TimeoutSeconds = &i
|
||||
}
|
||||
obj.AdmissionReviewVersions = []string{"v1beta1"}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user