Merge pull request #74998 from mbohlool/pippin

Webhook configurations can choose which version of Review request they accept
pull/564/head
Kubernetes Prow Robot 2019-03-08 03:01:26 -08:00 committed by GitHub
commit e318642946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1777 additions and 783 deletions

View File

@ -201,6 +201,13 @@
"io.k8s.api.admissionregistration.v1beta1.Webhook": {
"description": "Webhook describes an admission webhook and the resources and operations it applies to.",
"properties": {
"admissionReviewVersions": {
"description": "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 a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. Default to `['v1beta1']`.",
"items": {
"type": "string"
},
"type": "array"
},
"clientConfig": {
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1beta1.WebhookClientConfig",
"description": "ClientConfig defines how to communicate with the hook. Required"
@ -16161,6 +16168,13 @@
"io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceConversion": {
"description": "CustomResourceConversion describes how to convert different versions of a CR.",
"properties": {
"conversionReviewVersions": {
"description": "ConversionReviewVersions is an ordered list of preferred `ConversionReview` 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, conversion will fail for this object. If a persisted Webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail. Default to `['v1beta1']`.",
"items": {
"type": "string"
},
"type": "array"
},
"strategy": {
"description": "`strategy` specifies the conversion strategy. Allowed values are: - `None`: The converter only change the apiVersion and would not touch any other field in the CR. - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information is needed for this option.",
"type": "string"

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
}

View File

@ -78,9 +78,7 @@ func (mutatingWebhookConfigurationStrategy) AllowCreateOnUpdate() bool {
// ValidateUpdate is the default update validation for an end user.
func (mutatingWebhookConfigurationStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
validationErrorList := validation.ValidateMutatingWebhookConfiguration(obj.(*admissionregistration.MutatingWebhookConfiguration))
updateErrorList := validation.ValidateMutatingWebhookConfigurationUpdate(obj.(*admissionregistration.MutatingWebhookConfiguration), old.(*admissionregistration.MutatingWebhookConfiguration))
return append(validationErrorList, updateErrorList...)
return validation.ValidateMutatingWebhookConfigurationUpdate(obj.(*admissionregistration.MutatingWebhookConfiguration), old.(*admissionregistration.MutatingWebhookConfiguration))
}
// AllowUnconditionalUpdate is the default update policy for mutatingWebhookConfiguration objects. Status update should

View File

@ -63,8 +63,7 @@ func (validatingWebhookConfigurationStrategy) PrepareForUpdate(ctx context.Conte
// Validate validates a new validatingWebhookConfiguration.
func (validatingWebhookConfigurationStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
ic := obj.(*admissionregistration.ValidatingWebhookConfiguration)
return validation.ValidateValidatingWebhookConfiguration(ic)
return validation.ValidateValidatingWebhookConfiguration(obj.(*admissionregistration.ValidatingWebhookConfiguration))
}
// Canonicalize normalizes the object after validation.
@ -78,9 +77,7 @@ func (validatingWebhookConfigurationStrategy) AllowCreateOnUpdate() bool {
// ValidateUpdate is the default update validation for an end user.
func (validatingWebhookConfigurationStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
validationErrorList := validation.ValidateValidatingWebhookConfiguration(obj.(*admissionregistration.ValidatingWebhookConfiguration))
updateErrorList := validation.ValidateValidatingWebhookConfigurationUpdate(obj.(*admissionregistration.ValidatingWebhookConfiguration), old.(*admissionregistration.ValidatingWebhookConfiguration))
return append(validationErrorList, updateErrorList...)
return validation.ValidateValidatingWebhookConfigurationUpdate(obj.(*admissionregistration.ValidatingWebhookConfiguration), old.(*admissionregistration.ValidatingWebhookConfiguration))
}
// AllowUnconditionalUpdate is the default update policy for validatingWebhookConfiguration objects. Status update should

View File

@ -473,6 +473,21 @@ func (m *Webhook) MarshalTo(dAtA []byte) (int, error) {
i++
i = encodeVarintGenerated(dAtA, i, uint64(*m.TimeoutSeconds))
}
if len(m.AdmissionReviewVersions) > 0 {
for _, s := range m.AdmissionReviewVersions {
dAtA[i] = 0x42
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
@ -665,6 +680,12 @@ func (m *Webhook) Size() (n int) {
if m.TimeoutSeconds != nil {
n += 1 + sovGenerated(uint64(*m.TimeoutSeconds))
}
if len(m.AdmissionReviewVersions) > 0 {
for _, s := range m.AdmissionReviewVersions {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -791,6 +812,7 @@ func (this *Webhook) String() string {
`NamespaceSelector:` + strings.Replace(fmt.Sprintf("%v", this.NamespaceSelector), "LabelSelector", "k8s_io_apimachinery_pkg_apis_meta_v1.LabelSelector", 1) + `,`,
`SideEffects:` + valueToStringGenerated(this.SideEffects) + `,`,
`TimeoutSeconds:` + valueToStringGenerated(this.TimeoutSeconds) + `,`,
`AdmissionReviewVersions:` + fmt.Sprintf("%v", this.AdmissionReviewVersions) + `,`,
`}`,
}, "")
return s
@ -1905,6 +1927,35 @@ func (m *Webhook) Unmarshal(dAtA []byte) error {
}
}
m.TimeoutSeconds = &v
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AdmissionReviewVersions", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AdmissionReviewVersions = append(m.AdmissionReviewVersions, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -2180,66 +2231,67 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 962 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0xcf, 0x8f, 0xdb, 0x44,
0x14, 0x5e, 0x37, 0x09, 0x89, 0x27, 0xbb, 0x6d, 0x77, 0xf8, 0x21, 0xb3, 0xaa, 0xec, 0x28, 0x07,
0x14, 0x09, 0x6a, 0xb3, 0x0b, 0x42, 0xa8, 0x02, 0xa1, 0xf5, 0x42, 0x61, 0xa5, 0x6d, 0xbb, 0x4c,
0x4a, 0x2b, 0x21, 0x0e, 0x4c, 0x9c, 0x97, 0x64, 0x88, 0xe3, 0xb1, 0x3c, 0xe3, 0x94, 0xbd, 0x21,
0xf1, 0x0f, 0xf0, 0x5f, 0xf0, 0x57, 0x70, 0xe0, 0xb6, 0xc7, 0x72, 0x40, 0xf4, 0x64, 0xb1, 0xe6,
0xcc, 0x81, 0xeb, 0x9e, 0xd0, 0xd8, 0x4e, 0x9c, 0x6c, 0xba, 0xdb, 0xf4, 0xc2, 0x81, 0x9b, 0xe7,
0x7b, 0xef, 0xfb, 0xde, 0xfb, 0x66, 0xe6, 0x8d, 0xd1, 0x97, 0xe3, 0x0f, 0x85, 0xcd, 0xb8, 0x33,
0x8e, 0x7b, 0x10, 0x05, 0x20, 0x41, 0x38, 0x53, 0x08, 0xfa, 0x3c, 0x72, 0x8a, 0x00, 0x0d, 0x99,
0x43, 0xfb, 0x13, 0x26, 0x04, 0xe3, 0x41, 0x04, 0x43, 0x26, 0x64, 0x44, 0x25, 0xe3, 0x81, 0x33,
0xdd, 0xed, 0x81, 0xa4, 0xbb, 0xce, 0x10, 0x02, 0x88, 0xa8, 0x84, 0xbe, 0x1d, 0x46, 0x5c, 0x72,
0xdc, 0xc9, 0x99, 0x36, 0x0d, 0x99, 0xfd, 0x5c, 0xa6, 0x5d, 0x30, 0x77, 0x6e, 0x0f, 0x99, 0x1c,
0xc5, 0x3d, 0xdb, 0xe3, 0x13, 0x67, 0xc8, 0x87, 0xdc, 0xc9, 0x04, 0x7a, 0xf1, 0x20, 0x5b, 0x65,
0x8b, 0xec, 0x2b, 0x17, 0xde, 0x79, 0xbf, 0x6c, 0x69, 0x42, 0xbd, 0x11, 0x0b, 0x20, 0x3a, 0x71,
0xc2, 0xf1, 0x50, 0x01, 0xc2, 0x99, 0x80, 0xa4, 0xce, 0x74, 0xa5, 0x9d, 0x1d, 0xe7, 0x32, 0x56,
0x14, 0x07, 0x92, 0x4d, 0x60, 0x85, 0xf0, 0xc1, 0x8b, 0x08, 0xc2, 0x1b, 0xc1, 0x84, 0x5e, 0xe4,
0xb5, 0x7f, 0xd7, 0xd0, 0xad, 0x7b, 0xb1, 0xa4, 0x92, 0x05, 0xc3, 0xc7, 0xd0, 0x1b, 0x71, 0x3e,
0x3e, 0xe0, 0xc1, 0x80, 0x0d, 0xe3, 0xdc, 0x36, 0xfe, 0x16, 0x35, 0x54, 0x93, 0x7d, 0x2a, 0xa9,
0xa1, 0xb5, 0xb4, 0x4e, 0x73, 0xef, 0x5d, 0xbb, 0xdc, 0xab, 0x79, 0x2d, 0x3b, 0x1c, 0x0f, 0x15,
0x20, 0x6c, 0x95, 0x6d, 0x4f, 0x77, 0xed, 0x07, 0xbd, 0xef, 0xc0, 0x93, 0xf7, 0x40, 0x52, 0x17,
0x9f, 0x26, 0xd6, 0x46, 0x9a, 0x58, 0xa8, 0xc4, 0xc8, 0x5c, 0x15, 0x77, 0x51, 0xa3, 0xa8, 0x2c,
0x8c, 0x6b, 0xad, 0x4a, 0xa7, 0xb9, 0xb7, 0x6b, 0xaf, 0x7b, 0x1a, 0x76, 0xc1, 0x74, 0xab, 0xaa,
0x04, 0x69, 0x3c, 0x29, 0x84, 0xda, 0x7f, 0x6b, 0xa8, 0x75, 0x95, 0xaf, 0x23, 0x26, 0x24, 0xfe,
0x66, 0xc5, 0x9b, 0xbd, 0x9e, 0x37, 0xc5, 0xce, 0x9c, 0xdd, 0x2c, 0x9c, 0x35, 0x66, 0xc8, 0x82,
0xaf, 0x31, 0xaa, 0x31, 0x09, 0x93, 0x99, 0xa9, 0xbb, 0xeb, 0x9b, 0xba, 0xaa, 0x71, 0x77, 0xab,
0x28, 0x59, 0x3b, 0x54, 0xe2, 0x24, 0xaf, 0xd1, 0xfe, 0x55, 0x43, 0x55, 0x12, 0xfb, 0x80, 0xdf,
0x46, 0x3a, 0x0d, 0xd9, 0xe7, 0x11, 0x8f, 0x43, 0x61, 0x68, 0xad, 0x4a, 0x47, 0x77, 0xb7, 0xd2,
0xc4, 0xd2, 0xf7, 0x8f, 0x0f, 0x73, 0x90, 0x94, 0x71, 0xbc, 0x8b, 0x9a, 0x34, 0x64, 0x8f, 0x20,
0x52, 0xad, 0xe4, 0x8d, 0xea, 0xee, 0x8d, 0x34, 0xb1, 0x9a, 0xfb, 0xc7, 0x87, 0x33, 0x98, 0x2c,
0xe6, 0x28, 0xfd, 0x08, 0x04, 0x8f, 0x23, 0x0f, 0x84, 0x51, 0x29, 0xf5, 0xc9, 0x0c, 0x24, 0x65,
0x1c, 0xbf, 0x83, 0x6a, 0xc2, 0xe3, 0x21, 0x18, 0xd5, 0x96, 0xd6, 0xd1, 0xdd, 0x37, 0x54, 0xdb,
0x5d, 0x05, 0x9c, 0x27, 0x96, 0x9e, 0x7d, 0x3c, 0x3c, 0x09, 0x81, 0xe4, 0x49, 0xed, 0x9f, 0x35,
0x84, 0x95, 0x87, 0xc7, 0x4c, 0x8e, 0x1e, 0x84, 0x90, 0xfb, 0x15, 0xf8, 0x13, 0x84, 0xf8, 0x7c,
0x55, 0x58, 0xb2, 0xb2, 0xdb, 0x34, 0x47, 0xcf, 0x13, 0x6b, 0x6b, 0xbe, 0xca, 0x24, 0x17, 0x28,
0xf8, 0x18, 0x55, 0xa3, 0xd8, 0x07, 0xe3, 0xda, 0xca, 0x11, 0xbf, 0xe0, 0x1c, 0x54, 0x33, 0xee,
0x66, 0xb1, 0xdf, 0xd9, 0xf6, 0x92, 0x4c, 0xa9, 0xfd, 0xa3, 0x86, 0x6e, 0x76, 0x21, 0x9a, 0x32,
0x0f, 0x08, 0x0c, 0x20, 0x82, 0xc0, 0x03, 0xec, 0x20, 0x3d, 0xa0, 0x13, 0x10, 0x21, 0xf5, 0x20,
0xbb, 0x4e, 0xba, 0xbb, 0x5d, 0x70, 0xf5, 0xfb, 0xb3, 0x00, 0x29, 0x73, 0x70, 0x0b, 0x55, 0xd5,
0x22, 0xeb, 0x4b, 0x2f, 0xeb, 0xa8, 0x5c, 0x92, 0x45, 0xf0, 0x2d, 0x54, 0x0d, 0xa9, 0x1c, 0x19,
0x95, 0x2c, 0xa3, 0xa1, 0xa2, 0xc7, 0x54, 0x8e, 0x48, 0x86, 0xb6, 0xff, 0xd0, 0x90, 0xf9, 0x88,
0xfa, 0xac, 0xff, 0xbf, 0x9b, 0xde, 0x7f, 0x34, 0xd4, 0xbe, 0xda, 0xd9, 0x7f, 0x30, 0xbf, 0x93,
0xe5, 0xf9, 0xfd, 0x62, 0x7d, 0x5b, 0x57, 0xb7, 0x7e, 0xc9, 0x04, 0xff, 0x56, 0x45, 0xf5, 0x22,
0x7d, 0x7e, 0x33, 0xb4, 0x4b, 0x6f, 0xc6, 0x13, 0xb4, 0xe9, 0xf9, 0x0c, 0x02, 0x99, 0x4b, 0x17,
0x77, 0xfb, 0xe3, 0x97, 0xde, 0xfa, 0x83, 0x05, 0x11, 0xf7, 0xb5, 0xa2, 0xd0, 0xe6, 0x22, 0x4a,
0x96, 0x0a, 0x61, 0x8a, 0x6a, 0x6a, 0x04, 0xf2, 0xd9, 0x6f, 0xee, 0x7d, 0xf4, 0x72, 0xd3, 0xb4,
0x3c, 0xda, 0xe5, 0x4e, 0xa8, 0x98, 0x20, 0xb9, 0x32, 0x3e, 0x42, 0x5b, 0x03, 0xca, 0xfc, 0x38,
0x82, 0x63, 0xee, 0x33, 0xef, 0xa4, 0x78, 0x3d, 0xde, 0x4a, 0x13, 0x6b, 0xeb, 0xee, 0x62, 0xe0,
0x3c, 0xb1, 0xb6, 0x97, 0x80, 0x6c, 0xf4, 0x97, 0xc9, 0xf8, 0x7b, 0xb4, 0x3d, 0x1f, 0xb9, 0x2e,
0xf8, 0xe0, 0x49, 0x1e, 0x19, 0xb5, 0x6c, 0xbb, 0xde, 0x5b, 0xf3, 0xb6, 0xd0, 0x1e, 0xf8, 0x33,
0xaa, 0xfb, 0x7a, 0x9a, 0x58, 0xdb, 0xf7, 0x2f, 0x2a, 0x92, 0xd5, 0x22, 0xf8, 0x53, 0xd4, 0x14,
0xac, 0x0f, 0x9f, 0x0d, 0x06, 0xe0, 0x49, 0x61, 0xbc, 0x92, 0xb9, 0x68, 0xab, 0xd7, 0xb5, 0x5b,
0xc2, 0xe7, 0x89, 0x75, 0xa3, 0x5c, 0x1e, 0xf8, 0x54, 0x08, 0xb2, 0x48, 0xc3, 0x77, 0xd0, 0x75,
0xf5, 0x03, 0xe7, 0xb1, 0xec, 0x82, 0xc7, 0x83, 0xbe, 0x30, 0xea, 0x2d, 0xad, 0x53, 0x73, 0x71,
0x9a, 0x58, 0xd7, 0x1f, 0x2e, 0x45, 0xc8, 0x85, 0xcc, 0xf6, 0x2f, 0x1a, 0x7a, 0xf5, 0x39, 0x07,
0x8d, 0x29, 0xaa, 0x8b, 0xfc, 0xf9, 0x2a, 0xe6, 0xe6, 0xce, 0xfa, 0xc7, 0x78, 0xf1, 0xdd, 0x73,
0x9b, 0x69, 0x62, 0xd5, 0x67, 0xe8, 0x4c, 0x17, 0x77, 0x50, 0xc3, 0xa3, 0x6e, 0x1c, 0xf4, 0x8b,
0x87, 0x77, 0xd3, 0xdd, 0x54, 0x73, 0x76, 0xb0, 0x9f, 0x63, 0x64, 0x1e, 0xc5, 0x6f, 0xa2, 0x4a,
0x1c, 0xf9, 0xc5, 0x1b, 0x57, 0x4f, 0x13, 0xab, 0xf2, 0x15, 0x39, 0x22, 0x0a, 0x73, 0x6f, 0x9f,
0x9e, 0x99, 0x1b, 0x4f, 0xcf, 0xcc, 0x8d, 0x67, 0x67, 0xe6, 0xc6, 0x0f, 0xa9, 0xa9, 0x9d, 0xa6,
0xa6, 0xf6, 0x34, 0x35, 0xb5, 0x67, 0xa9, 0xa9, 0xfd, 0x99, 0x9a, 0xda, 0x4f, 0x7f, 0x99, 0x1b,
0x5f, 0xd7, 0x8b, 0xd6, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xbb, 0xeb, 0xd8, 0xb0, 0x18, 0x0a,
0x00, 0x00,
// 989 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6f, 0xe3, 0x44,
0x14, 0xaf, 0x37, 0x09, 0x49, 0x26, 0xed, 0xee, 0x76, 0xf8, 0xb3, 0xa1, 0xac, 0xec, 0x28, 0x07,
0x14, 0x09, 0xd6, 0xa6, 0x05, 0x21, 0xb4, 0x02, 0xa1, 0xba, 0xb0, 0x50, 0xa9, 0xbb, 0x5b, 0x26,
0xfb, 0x47, 0x42, 0x1c, 0x98, 0x38, 0x2f, 0xc9, 0x10, 0xc7, 0x63, 0x79, 0xc6, 0x29, 0xbd, 0x21,
0xf1, 0x05, 0xf8, 0x16, 0xf0, 0x25, 0x38, 0x70, 0xeb, 0x71, 0x2f, 0x88, 0x3d, 0x59, 0xd4, 0x9c,
0x39, 0x70, 0xed, 0x09, 0x8d, 0xed, 0xd8, 0x49, 0xd3, 0x76, 0xb3, 0x17, 0x0e, 0xdc, 0x3c, 0xbf,
0xf7, 0x7e, 0xef, 0xbd, 0xdf, 0xcc, 0x7b, 0xcf, 0xe8, 0xab, 0xf1, 0x47, 0xc2, 0x64, 0xdc, 0x1a,
0x87, 0x3d, 0x08, 0x3c, 0x90, 0x20, 0xac, 0x29, 0x78, 0x7d, 0x1e, 0x58, 0x99, 0x81, 0xfa, 0xcc,
0xa2, 0xfd, 0x09, 0x13, 0x82, 0x71, 0x2f, 0x80, 0x21, 0x13, 0x32, 0xa0, 0x92, 0x71, 0xcf, 0x9a,
0x6e, 0xf7, 0x40, 0xd2, 0x6d, 0x6b, 0x08, 0x1e, 0x04, 0x54, 0x42, 0xdf, 0xf4, 0x03, 0x2e, 0x39,
0xee, 0xa4, 0x4c, 0x93, 0xfa, 0xcc, 0xbc, 0x90, 0x69, 0x66, 0xcc, 0xad, 0x3b, 0x43, 0x26, 0x47,
0x61, 0xcf, 0x74, 0xf8, 0xc4, 0x1a, 0xf2, 0x21, 0xb7, 0x92, 0x00, 0xbd, 0x70, 0x90, 0x9c, 0x92,
0x43, 0xf2, 0x95, 0x06, 0xde, 0xfa, 0xa0, 0x28, 0x69, 0x42, 0x9d, 0x11, 0xf3, 0x20, 0x38, 0xb6,
0xfc, 0xf1, 0x50, 0x01, 0xc2, 0x9a, 0x80, 0xa4, 0xd6, 0x74, 0xa9, 0x9c, 0x2d, 0xeb, 0x32, 0x56,
0x10, 0x7a, 0x92, 0x4d, 0x60, 0x89, 0xf0, 0xe1, 0x8b, 0x08, 0xc2, 0x19, 0xc1, 0x84, 0x9e, 0xe7,
0xb5, 0x7f, 0xd7, 0xd0, 0xed, 0xfb, 0xa1, 0xa4, 0x92, 0x79, 0xc3, 0xa7, 0xd0, 0x1b, 0x71, 0x3e,
0xde, 0xe3, 0xde, 0x80, 0x0d, 0xc3, 0x54, 0x36, 0xfe, 0x16, 0xd5, 0x54, 0x91, 0x7d, 0x2a, 0x69,
0x53, 0x6b, 0x69, 0x9d, 0xc6, 0xce, 0x7b, 0x66, 0x71, 0x57, 0x79, 0x2e, 0xd3, 0x1f, 0x0f, 0x15,
0x20, 0x4c, 0xe5, 0x6d, 0x4e, 0xb7, 0xcd, 0x87, 0xbd, 0xef, 0xc0, 0x91, 0xf7, 0x41, 0x52, 0x1b,
0x9f, 0x44, 0xc6, 0x5a, 0x1c, 0x19, 0xa8, 0xc0, 0x48, 0x1e, 0x15, 0x77, 0x51, 0x2d, 0xcb, 0x2c,
0x9a, 0xd7, 0x5a, 0xa5, 0x4e, 0x63, 0x67, 0xdb, 0x5c, 0xf5, 0x35, 0xcc, 0x8c, 0x69, 0x97, 0x55,
0x0a, 0x52, 0x3b, 0xca, 0x02, 0xb5, 0xff, 0xd6, 0x50, 0xeb, 0x2a, 0x5d, 0x07, 0x4c, 0x48, 0xfc,
0xcd, 0x92, 0x36, 0x73, 0x35, 0x6d, 0x8a, 0x9d, 0x28, 0xbb, 0x99, 0x29, 0xab, 0xcd, 0x90, 0x39,
0x5d, 0x63, 0x54, 0x61, 0x12, 0x26, 0x33, 0x51, 0xf7, 0x56, 0x17, 0x75, 0x55, 0xe1, 0xf6, 0x46,
0x96, 0xb2, 0xb2, 0xaf, 0x82, 0x93, 0x34, 0x47, 0xfb, 0x37, 0x0d, 0x95, 0x49, 0xe8, 0x02, 0x7e,
0x07, 0xd5, 0xa9, 0xcf, 0xbe, 0x08, 0x78, 0xe8, 0x8b, 0xa6, 0xd6, 0x2a, 0x75, 0xea, 0xf6, 0x46,
0x1c, 0x19, 0xf5, 0xdd, 0xc3, 0xfd, 0x14, 0x24, 0x85, 0x1d, 0x6f, 0xa3, 0x06, 0xf5, 0xd9, 0x13,
0x08, 0x54, 0x29, 0x69, 0xa1, 0x75, 0xfb, 0x46, 0x1c, 0x19, 0x8d, 0xdd, 0xc3, 0xfd, 0x19, 0x4c,
0xe6, 0x7d, 0x54, 0xfc, 0x00, 0x04, 0x0f, 0x03, 0x07, 0x44, 0xb3, 0x54, 0xc4, 0x27, 0x33, 0x90,
0x14, 0x76, 0xfc, 0x2e, 0xaa, 0x08, 0x87, 0xfb, 0xd0, 0x2c, 0xb7, 0xb4, 0x4e, 0xdd, 0x7e, 0x43,
0x95, 0xdd, 0x55, 0xc0, 0x59, 0x64, 0xd4, 0x93, 0x8f, 0x47, 0xc7, 0x3e, 0x90, 0xd4, 0xa9, 0xfd,
0xb3, 0x86, 0xb0, 0xd2, 0xf0, 0x94, 0xc9, 0xd1, 0x43, 0x1f, 0x52, 0xbd, 0x02, 0x7f, 0x8a, 0x10,
0xcf, 0x4f, 0x99, 0x24, 0x23, 0xe9, 0xa6, 0x1c, 0x3d, 0x8b, 0x8c, 0x8d, 0xfc, 0x94, 0x84, 0x9c,
0xa3, 0xe0, 0x43, 0x54, 0x0e, 0x42, 0x17, 0x9a, 0xd7, 0x96, 0x9e, 0xf8, 0x05, 0xef, 0xa0, 0x8a,
0xb1, 0xd7, 0xb3, 0xfb, 0x4e, 0xae, 0x97, 0x24, 0x91, 0xda, 0x3f, 0x6a, 0xe8, 0x66, 0x17, 0x82,
0x29, 0x73, 0x80, 0xc0, 0x00, 0x02, 0xf0, 0x1c, 0xc0, 0x16, 0xaa, 0x7b, 0x74, 0x02, 0xc2, 0xa7,
0x0e, 0x24, 0xed, 0x54, 0xb7, 0x37, 0x33, 0x6e, 0xfd, 0xc1, 0xcc, 0x40, 0x0a, 0x1f, 0xdc, 0x42,
0x65, 0x75, 0x48, 0xea, 0xaa, 0x17, 0x79, 0x94, 0x2f, 0x49, 0x2c, 0xf8, 0x36, 0x2a, 0xfb, 0x54,
0x8e, 0x9a, 0xa5, 0xc4, 0xa3, 0xa6, 0xac, 0x87, 0x54, 0x8e, 0x48, 0x82, 0xb6, 0xff, 0xd0, 0x90,
0xfe, 0x84, 0xba, 0xac, 0xff, 0xbf, 0x9b, 0xde, 0x7f, 0x34, 0xd4, 0xbe, 0x5a, 0xd9, 0x7f, 0x30,
0xbf, 0x93, 0xc5, 0xf9, 0xfd, 0x72, 0x75, 0x59, 0x57, 0x97, 0x7e, 0xc9, 0x04, 0xff, 0x52, 0x41,
0xd5, 0xcc, 0x3d, 0xef, 0x0c, 0xed, 0xd2, 0xce, 0x38, 0x42, 0xeb, 0x8e, 0xcb, 0xc0, 0x93, 0x69,
0xe8, 0xac, 0xb7, 0x3f, 0x79, 0xe9, 0xab, 0xdf, 0x9b, 0x0b, 0x62, 0xbf, 0x96, 0x25, 0x5a, 0x9f,
0x47, 0xc9, 0x42, 0x22, 0x4c, 0x51, 0x45, 0x8d, 0x40, 0x3a, 0xfb, 0x8d, 0x9d, 0x8f, 0x5f, 0x6e,
0x9a, 0x16, 0x47, 0xbb, 0xb8, 0x09, 0x65, 0x13, 0x24, 0x8d, 0x8c, 0x0f, 0xd0, 0xc6, 0x80, 0x32,
0x37, 0x0c, 0xe0, 0x90, 0xbb, 0xcc, 0x39, 0xce, 0xb6, 0xc7, 0xdb, 0x71, 0x64, 0x6c, 0xdc, 0x9b,
0x37, 0x9c, 0x45, 0xc6, 0xe6, 0x02, 0x90, 0x8c, 0xfe, 0x22, 0x19, 0x7f, 0x8f, 0x36, 0xf3, 0x91,
0xeb, 0x82, 0x0b, 0x8e, 0xe4, 0x41, 0xb3, 0x92, 0x5c, 0xd7, 0xfb, 0x2b, 0x76, 0x0b, 0xed, 0x81,
0x3b, 0xa3, 0xda, 0xaf, 0xc7, 0x91, 0xb1, 0xf9, 0xe0, 0x7c, 0x44, 0xb2, 0x9c, 0x04, 0x7f, 0x86,
0x1a, 0x82, 0xf5, 0xe1, 0xf3, 0xc1, 0x00, 0x1c, 0x29, 0x9a, 0xaf, 0x24, 0x2a, 0xda, 0x6a, 0xbb,
0x76, 0x0b, 0xf8, 0x2c, 0x32, 0x6e, 0x14, 0xc7, 0x3d, 0x97, 0x0a, 0x41, 0xe6, 0x69, 0xf8, 0x2e,
0xba, 0xae, 0x7e, 0xe0, 0x3c, 0x94, 0x5d, 0x70, 0xb8, 0xd7, 0x17, 0xcd, 0x6a, 0x4b, 0xeb, 0x54,
0x6c, 0x1c, 0x47, 0xc6, 0xf5, 0x47, 0x0b, 0x16, 0x72, 0xce, 0x13, 0x3f, 0x46, 0xb7, 0xf2, 0x37,
0x21, 0x30, 0x65, 0x70, 0x94, 0xef, 0xfa, 0x5a, 0xb2, 0x47, 0xdf, 0x8a, 0x23, 0xe3, 0xd6, 0xee,
0xc5, 0x2e, 0xe4, 0x32, 0x6e, 0xfb, 0x57, 0x0d, 0xbd, 0x7a, 0x41, 0xff, 0x60, 0x8a, 0xaa, 0x22,
0xdd, 0x8a, 0xd9, 0x38, 0xde, 0x5d, 0xbd, 0x3b, 0xce, 0xaf, 0x53, 0xbb, 0x11, 0x47, 0x46, 0x75,
0x86, 0xce, 0xe2, 0xe2, 0x0e, 0xaa, 0x39, 0xd4, 0x0e, 0xbd, 0x7e, 0xb6, 0xcf, 0xd7, 0xed, 0x75,
0x35, 0xbe, 0x7b, 0xbb, 0x29, 0x46, 0x72, 0x2b, 0x7e, 0x13, 0x95, 0xc2, 0xc0, 0xcd, 0x56, 0x67,
0x35, 0x8e, 0x8c, 0xd2, 0x63, 0x72, 0x40, 0x14, 0x66, 0xdf, 0x39, 0x39, 0xd5, 0xd7, 0x9e, 0x9d,
0xea, 0x6b, 0xcf, 0x4f, 0xf5, 0xb5, 0x1f, 0x62, 0x5d, 0x3b, 0x89, 0x75, 0xed, 0x59, 0xac, 0x6b,
0xcf, 0x63, 0x5d, 0xfb, 0x33, 0xd6, 0xb5, 0x9f, 0xfe, 0xd2, 0xd7, 0xbe, 0xae, 0x66, 0xa5, 0xfd,
0x1b, 0x00, 0x00, 0xff, 0xff, 0xbb, 0xc0, 0x7c, 0xc4, 0x6f, 0x0a, 0x00, 0x00,
}

View File

@ -237,6 +237,17 @@ message Webhook {
// Default to 30 seconds.
// +optional
optional int32 timeoutSeconds = 7;
// 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 a persisted webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail
// and be subject to the failure policy.
// Default to `['v1beta1']`.
// +optional
repeated string admissionReviewVersions = 8;
}
// WebhookClientConfig contains the information to make a TLS

View File

@ -248,6 +248,17 @@ type Webhook struct {
// Default to 30 seconds.
// +optional
TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty" protobuf:"varint,7,opt,name=timeoutSeconds"`
// 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 a persisted webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail
// and be subject to the failure policy.
// Default to `['v1beta1']`.
// +optional
AdmissionReviewVersions []string `json:"admissionReviewVersions,omitempty" protobuf:"bytes,8,rep,name=admissionReviewVersions"`
}
// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make

View File

@ -100,14 +100,15 @@ func (ValidatingWebhookConfigurationList) SwaggerDoc() map[string]string {
}
var map_Webhook = map[string]string{
"": "Webhook describes an admission webhook and the resources and operations it applies to.",
"name": "The name of the admission webhook. Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where \"imagepolicy\" is the name of the webhook, and kubernetes.io is the name of the organization. Required.",
"clientConfig": "ClientConfig defines how to communicate with the hook. Required",
"rules": "Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches _any_ Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects.",
"failurePolicy": "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Ignore.",
"namespaceSelector": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
"sideEffects": "SideEffects states whether this webhookk has side effects. Acceptable values are: Unknown, None, Some, NoneOnDryRun Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission change and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. Defaults to Unknown.",
"timeoutSeconds": "TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 30 seconds.",
"": "Webhook describes an admission webhook and the resources and operations it applies to.",
"name": "The name of the admission webhook. Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where \"imagepolicy\" is the name of the webhook, and kubernetes.io is the name of the organization. Required.",
"clientConfig": "ClientConfig defines how to communicate with the hook. Required",
"rules": "Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches _any_ Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects.",
"failurePolicy": "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Ignore.",
"namespaceSelector": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
"sideEffects": "SideEffects states whether this webhookk has side effects. Acceptable values are: Unknown, None, Some, NoneOnDryRun Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission change and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. Defaults to Unknown.",
"timeoutSeconds": "TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 30 seconds.",
"admissionReviewVersions": "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 a persisted webhook configuration specifies allowed versions and does not include any versions known to the API Server, calls to the webhook will fail and be subject to the failure policy. Default to `['v1beta1']`.",
}
func (Webhook) SwaggerDoc() map[string]string {

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
}

View File

@ -66,6 +66,9 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
Strategy: apiextensions.NoneConverter,
}
}
if obj.Conversion.Strategy == apiextensions.WebhookConverter && len(obj.Conversion.ConversionReviewVersions) == 0 {
obj.Conversion.ConversionReviewVersions = []string{"v1beta1"}
}
},
func(obj *apiextensions.CustomResourceDefinition, c fuzz.Continue) {
c.FuzzNoCustom(obj)

View File

@ -84,6 +84,15 @@ type CustomResourceConversion struct {
// `webhookClientConfig` is the instructions for how to call the webhook if strategy is `Webhook`.
WebhookClientConfig *WebhookClientConfig
// ConversionReviewVersions is an ordered list of preferred `ConversionReview`
// 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, conversion will fail for this object.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
// +optional
ConversionReviewVersions []string
}
// WebhookClientConfig contains the information to make a TLS

View File

@ -68,6 +68,9 @@ func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec)
Strategy: NoneConverter,
}
}
if obj.Conversion.Strategy == WebhookConverter && len(obj.Conversion.ConversionReviewVersions) == 0 {
obj.Conversion.ConversionReviewVersions = []string{SchemeGroupVersion.Version}
}
}
// hasPerVersionColumns returns true if a CRD uses per-version columns.

View File

@ -416,6 +416,21 @@ func (m *CustomResourceConversion) MarshalTo(dAtA []byte) (int, error) {
}
i += n4
}
if len(m.ConversionReviewVersions) > 0 {
for _, s := range m.ConversionReviewVersions {
dAtA[i] = 0x1a
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
@ -1691,6 +1706,12 @@ func (m *CustomResourceConversion) Size() (n int) {
l = m.WebhookClientConfig.Size()
n += 1 + l + sovGenerated(uint64(l))
}
if len(m.ConversionReviewVersions) > 0 {
for _, s := range m.ConversionReviewVersions {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -2202,6 +2223,7 @@ func (this *CustomResourceConversion) String() string {
s := strings.Join([]string{`&CustomResourceConversion{`,
`Strategy:` + fmt.Sprintf("%v", this.Strategy) + `,`,
`WebhookClientConfig:` + strings.Replace(fmt.Sprintf("%v", this.WebhookClientConfig), "WebhookClientConfig", "WebhookClientConfig", 1) + `,`,
`ConversionReviewVersions:` + fmt.Sprintf("%v", this.ConversionReviewVersions) + `,`,
`}`,
}, "")
return s
@ -3217,6 +3239,35 @@ func (m *CustomResourceConversion) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ConversionReviewVersions", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ConversionReviewVersions = append(m.ConversionReviewVersions, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -7285,178 +7336,179 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 2762 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x73, 0x1c, 0x47,
0x15, 0xf7, 0xec, 0x6a, 0xa5, 0x55, 0x4b, 0xb2, 0xa4, 0x76, 0xe4, 0x8c, 0x85, 0xbd, 0x2b, 0xad,
0x71, 0x4a, 0x04, 0x7b, 0x15, 0x9b, 0x84, 0x84, 0x54, 0x71, 0xd0, 0x4a, 0x4a, 0x4a, 0xc6, 0xfa,
0xa0, 0xd7, 0x76, 0x80, 0x7c, 0xb6, 0x66, 0x7b, 0x57, 0x63, 0xcd, 0x97, 0xa7, 0x67, 0x56, 0x52,
0x05, 0x28, 0x48, 0x2a, 0x05, 0x45, 0x01, 0xa1, 0x88, 0x2f, 0x14, 0x70, 0x00, 0x8a, 0x0b, 0x07,
0x38, 0xc0, 0x0d, 0xfe, 0x00, 0x1f, 0x53, 0x9c, 0x52, 0x1c, 0xb6, 0xf0, 0xe6, 0x5f, 0xa0, 0x8a,
0x2a, 0x9d, 0xa8, 0xfe, 0x98, 0x9e, 0xd9, 0xd9, 0x5d, 0x5b, 0x15, 0xef, 0xc6, 0xdc, 0x34, 0xef,
0xbd, 0x7e, 0xbf, 0xd7, 0xaf, 0xdf, 0x7b, 0xfd, 0xfa, 0xad, 0x40, 0x7d, 0xff, 0x25, 0x5a, 0x36,
0xdd, 0xe5, 0xfd, 0x70, 0x97, 0xf8, 0x0e, 0x09, 0x08, 0x5d, 0x6e, 0x12, 0xa7, 0xe6, 0xfa, 0xcb,
0x92, 0x81, 0x3d, 0x93, 0x1c, 0x06, 0xc4, 0xa1, 0xa6, 0xeb, 0xd0, 0x2b, 0xd8, 0x33, 0x29, 0xf1,
0x9b, 0xc4, 0x5f, 0xf6, 0xf6, 0x1b, 0x8c, 0x47, 0x3b, 0x05, 0x96, 0x9b, 0x57, 0x77, 0x49, 0x80,
0xaf, 0x2e, 0x37, 0x88, 0x43, 0x7c, 0x1c, 0x90, 0x5a, 0xd9, 0xf3, 0xdd, 0xc0, 0x85, 0x5f, 0x17,
0xea, 0xca, 0x1d, 0xd2, 0x6f, 0x2b, 0x75, 0x65, 0x6f, 0xbf, 0xc1, 0x78, 0xb4, 0x53, 0xa0, 0x2c,
0xd5, 0xcd, 0x5f, 0x69, 0x98, 0xc1, 0x5e, 0xb8, 0x5b, 0x36, 0x5c, 0x7b, 0xb9, 0xe1, 0x36, 0xdc,
0x65, 0xae, 0x75, 0x37, 0xac, 0xf3, 0x2f, 0xfe, 0xc1, 0xff, 0x12, 0x68, 0xf3, 0xcf, 0xc7, 0xc6,
0xdb, 0xd8, 0xd8, 0x33, 0x1d, 0xe2, 0x1f, 0xc5, 0x16, 0xdb, 0x24, 0xc0, 0xcb, 0xcd, 0x2e, 0x1b,
0xe7, 0x97, 0xfb, 0xad, 0xf2, 0x43, 0x27, 0x30, 0x6d, 0xd2, 0xb5, 0xe0, 0xab, 0x8f, 0x5a, 0x40,
0x8d, 0x3d, 0x62, 0xe3, 0xf4, 0xba, 0xd2, 0xb1, 0x06, 0x66, 0x57, 0x5d, 0xa7, 0x49, 0x7c, 0xb6,
0x4b, 0x44, 0xee, 0x86, 0x84, 0x06, 0xb0, 0x02, 0xb2, 0xa1, 0x59, 0xd3, 0xb5, 0x05, 0x6d, 0x69,
0xbc, 0xf2, 0xdc, 0xfd, 0x56, 0xf1, 0x54, 0xbb, 0x55, 0xcc, 0xde, 0xda, 0x58, 0x3b, 0x6e, 0x15,
0x17, 0xfb, 0x21, 0x05, 0x47, 0x1e, 0xa1, 0xe5, 0x5b, 0x1b, 0x6b, 0x88, 0x2d, 0x86, 0xaf, 0x82,
0xd9, 0x1a, 0xa1, 0xa6, 0x4f, 0x6a, 0x2b, 0x3b, 0x1b, 0xb7, 0x85, 0x7e, 0x3d, 0xc3, 0x35, 0x9e,
0x93, 0x1a, 0x67, 0xd7, 0xd2, 0x02, 0xa8, 0x7b, 0x0d, 0xfc, 0x16, 0x18, 0x73, 0x77, 0xef, 0x10,
0x23, 0xa0, 0x7a, 0x76, 0x21, 0xbb, 0x34, 0x71, 0xed, 0x4a, 0x39, 0x3e, 0x41, 0x65, 0x02, 0x3f,
0x36, 0xb9, 0xd9, 0x32, 0xc2, 0x07, 0xeb, 0xd1, 0xc9, 0x55, 0xa6, 0x25, 0xda, 0xd8, 0xb6, 0xd0,
0x82, 0x22, 0x75, 0xa5, 0x3f, 0x64, 0x00, 0x4c, 0x6e, 0x9e, 0x7a, 0xae, 0x43, 0xc9, 0x40, 0x76,
0x4f, 0xc1, 0x8c, 0xc1, 0x35, 0x07, 0xa4, 0x26, 0x71, 0xf5, 0xcc, 0x67, 0xb1, 0x5e, 0x97, 0xf8,
0x33, 0xab, 0x29, 0x75, 0xa8, 0x0b, 0x00, 0xde, 0x04, 0xa3, 0x3e, 0xa1, 0xa1, 0x15, 0xe8, 0xd9,
0x05, 0x6d, 0x69, 0xe2, 0xda, 0xe5, 0xbe, 0x50, 0x3c, 0xbe, 0x59, 0xf0, 0x95, 0x9b, 0x57, 0xcb,
0xd5, 0x00, 0x07, 0x21, 0xad, 0x9c, 0x96, 0x48, 0xa3, 0x88, 0xeb, 0x40, 0x52, 0x57, 0xe9, 0xc7,
0x19, 0x30, 0x93, 0xf4, 0x52, 0xd3, 0x24, 0x07, 0xf0, 0x00, 0x8c, 0xf9, 0x22, 0x58, 0xb8, 0x9f,
0x26, 0xae, 0xed, 0x94, 0x1f, 0x2b, 0xad, 0xca, 0x5d, 0x41, 0x58, 0x99, 0x60, 0x67, 0x26, 0x3f,
0x50, 0x84, 0x06, 0xdf, 0x05, 0x79, 0x5f, 0x1e, 0x14, 0x8f, 0xa6, 0x89, 0x6b, 0xdf, 0x1c, 0x20,
0xb2, 0x50, 0x5c, 0x99, 0x6c, 0xb7, 0x8a, 0xf9, 0xe8, 0x0b, 0x29, 0xc0, 0xd2, 0x47, 0x19, 0x50,
0x58, 0x0d, 0x69, 0xe0, 0xda, 0x88, 0x50, 0x37, 0xf4, 0x0d, 0xb2, 0xea, 0x5a, 0xa1, 0xed, 0xac,
0x91, 0xba, 0xe9, 0x98, 0x01, 0x8b, 0xd6, 0x05, 0x30, 0xe2, 0x60, 0x9b, 0xc8, 0xe8, 0x99, 0x94,
0x3e, 0x1d, 0xd9, 0xc2, 0x36, 0x41, 0x9c, 0xc3, 0x24, 0x58, 0xb0, 0xc8, 0x5c, 0x50, 0x12, 0x37,
0x8f, 0x3c, 0x82, 0x38, 0x07, 0x3e, 0x03, 0x46, 0xeb, 0xae, 0x6f, 0x63, 0x71, 0x8e, 0xe3, 0xf1,
0xc9, 0xbc, 0xc2, 0xa9, 0x48, 0x72, 0xe1, 0x0b, 0x60, 0xa2, 0x46, 0xa8, 0xe1, 0x9b, 0x1e, 0x83,
0xd6, 0x47, 0xb8, 0xf0, 0x19, 0x29, 0x3c, 0xb1, 0x16, 0xb3, 0x50, 0x52, 0x0e, 0x5e, 0x06, 0x79,
0xcf, 0x37, 0x5d, 0xdf, 0x0c, 0x8e, 0xf4, 0xdc, 0x82, 0xb6, 0x94, 0xab, 0xcc, 0xc8, 0x35, 0xf9,
0x1d, 0x49, 0x47, 0x4a, 0x02, 0x2e, 0x80, 0xfc, 0xf5, 0xea, 0xf6, 0xd6, 0x0e, 0x0e, 0xf6, 0xf4,
0x51, 0x8e, 0x30, 0xc2, 0xa4, 0x51, 0xfe, 0x8e, 0xa4, 0x96, 0xde, 0xcb, 0x00, 0x3d, 0xed, 0x95,
0xc8, 0xa5, 0xf0, 0x15, 0x90, 0xa7, 0x01, 0xab, 0x38, 0x8d, 0x23, 0xe9, 0x93, 0x67, 0x23, 0xb0,
0xaa, 0xa4, 0x1f, 0xb7, 0x8a, 0x67, 0xe3, 0x15, 0x11, 0x95, 0xfb, 0x43, 0xad, 0x85, 0xbf, 0xd5,
0xc0, 0x99, 0x03, 0xb2, 0xbb, 0xe7, 0xba, 0xfb, 0xab, 0x96, 0x49, 0x9c, 0x60, 0xd5, 0x75, 0xea,
0x66, 0x43, 0xc6, 0x00, 0x7a, 0xcc, 0x18, 0x78, 0xad, 0x5b, 0x73, 0xe5, 0xe9, 0x76, 0xab, 0x78,
0xa6, 0x07, 0x03, 0xf5, 0xb2, 0xa3, 0xf4, 0x7e, 0x36, 0xed, 0x84, 0x44, 0x50, 0xbc, 0x03, 0xf2,
0x2c, 0xd9, 0x6a, 0x38, 0xc0, 0x32, 0x5d, 0x9e, 0x3b, 0x59, 0x6a, 0x8a, 0xcc, 0xde, 0x24, 0x01,
0xae, 0x40, 0xe9, 0x36, 0x10, 0xd3, 0x90, 0xd2, 0x0a, 0xbf, 0x07, 0x46, 0xa8, 0x47, 0x0c, 0xe9,
0x8e, 0xd7, 0x1f, 0x37, 0x25, 0xfa, 0x6c, 0xa4, 0xea, 0x11, 0x23, 0x8e, 0x58, 0xf6, 0x85, 0x38,
0x2c, 0xfc, 0x40, 0x03, 0xa3, 0x94, 0x97, 0x11, 0x59, 0x7a, 0xde, 0x1c, 0x96, 0x05, 0xa9, 0x5a,
0x25, 0xbe, 0x91, 0x04, 0x2f, 0xfd, 0x27, 0x03, 0x16, 0xfb, 0x2d, 0x5d, 0x75, 0x9d, 0x9a, 0x38,
0x8e, 0x0d, 0x99, 0x81, 0x22, 0x1e, 0x5f, 0x48, 0x66, 0xe0, 0x71, 0xab, 0x78, 0xe9, 0x91, 0x0a,
0x12, 0xa9, 0xfa, 0x35, 0xb5, 0x6f, 0x91, 0xce, 0x8b, 0x9d, 0x86, 0x1d, 0xb7, 0x8a, 0xd3, 0x6a,
0x59, 0xa7, 0xad, 0xb0, 0x09, 0xa0, 0x85, 0x69, 0x70, 0xd3, 0xc7, 0x0e, 0x15, 0x6a, 0x4d, 0x9b,
0x48, 0xf7, 0x3d, 0x7b, 0xb2, 0xf0, 0x60, 0x2b, 0x2a, 0xf3, 0x12, 0x12, 0xde, 0xe8, 0xd2, 0x86,
0x7a, 0x20, 0xb0, 0xea, 0xe2, 0x13, 0x4c, 0x55, 0xc1, 0x48, 0xd4, 0x7d, 0x46, 0x45, 0x92, 0x0b,
0xbf, 0x04, 0xc6, 0x6c, 0x42, 0x29, 0x6e, 0x10, 0x5e, 0x25, 0xc6, 0xe3, 0x8b, 0x74, 0x53, 0x90,
0x51, 0xc4, 0x67, 0x5d, 0xc4, 0xf9, 0x7e, 0x5e, 0xbb, 0x61, 0xd2, 0x00, 0xbe, 0xd1, 0x95, 0x00,
0xe5, 0x93, 0xed, 0x90, 0xad, 0xe6, 0xe1, 0xaf, 0x4a, 0x54, 0x44, 0x49, 0x04, 0xff, 0x77, 0x41,
0xce, 0x0c, 0x88, 0x1d, 0xdd, 0xb0, 0xaf, 0x0d, 0x29, 0xf6, 0x2a, 0x53, 0xd2, 0x86, 0xdc, 0x06,
0x43, 0x43, 0x02, 0xb4, 0xf4, 0xc7, 0x0c, 0xb8, 0xd0, 0x6f, 0x09, 0x2b, 0xfb, 0x94, 0x79, 0xdc,
0xb3, 0x42, 0x1f, 0x5b, 0x32, 0xe2, 0x94, 0xc7, 0x77, 0x38, 0x15, 0x49, 0x2e, 0x2b, 0xcc, 0xd4,
0x74, 0x1a, 0xa1, 0x85, 0x7d, 0x19, 0x4e, 0x6a, 0xd7, 0x55, 0x49, 0x47, 0x4a, 0x02, 0x96, 0x01,
0xa0, 0x7b, 0xae, 0x1f, 0x70, 0x0c, 0xde, 0x1a, 0x8d, 0x57, 0x4e, 0xb3, 0x02, 0x51, 0x55, 0x54,
0x94, 0x90, 0x60, 0xf7, 0xce, 0xbe, 0xe9, 0xd4, 0xe4, 0xa9, 0xab, 0x2c, 0xfe, 0x86, 0xe9, 0xd4,
0x10, 0xe7, 0x30, 0x7c, 0xcb, 0xa4, 0x01, 0xa3, 0xc8, 0x23, 0xef, 0xf0, 0x3a, 0x97, 0x54, 0x12,
0x0c, 0xdf, 0x60, 0xb5, 0xd9, 0xf5, 0x4d, 0x42, 0xf5, 0xd1, 0x18, 0x7f, 0x55, 0x51, 0x51, 0x42,
0xa2, 0xf4, 0xeb, 0x7c, 0xff, 0x20, 0x61, 0xa5, 0x04, 0x5e, 0x04, 0xb9, 0x86, 0xef, 0x86, 0x9e,
0xf4, 0x92, 0xf2, 0xf6, 0xab, 0x8c, 0x88, 0x04, 0x8f, 0x45, 0x65, 0xb3, 0xa3, 0x99, 0x54, 0x51,
0x19, 0xb5, 0x90, 0x11, 0x1f, 0xfe, 0x50, 0x03, 0x39, 0x47, 0x3a, 0x87, 0x85, 0xdc, 0x1b, 0x43,
0x8a, 0x0b, 0xee, 0xde, 0xd8, 0x5c, 0xe1, 0x79, 0x81, 0x0c, 0x9f, 0x07, 0x39, 0x6a, 0xb8, 0x1e,
0x91, 0x5e, 0x2f, 0x44, 0x42, 0x55, 0x46, 0x3c, 0x6e, 0x15, 0xa7, 0x22, 0x75, 0x9c, 0x80, 0x84,
0x30, 0xfc, 0x91, 0x06, 0x40, 0x13, 0x5b, 0x66, 0x0d, 0xf3, 0x8b, 0x3d, 0xc7, 0xcd, 0x1f, 0x6c,
0x58, 0xdf, 0x56, 0xea, 0xc5, 0xa1, 0xc5, 0xdf, 0x28, 0x01, 0x0d, 0x3f, 0xd4, 0xc0, 0x24, 0x0d,
0x77, 0x7d, 0xb9, 0x8a, 0xf2, 0x16, 0x60, 0xe2, 0xda, 0xb7, 0x07, 0x6a, 0x4b, 0x35, 0x01, 0x50,
0x99, 0x69, 0xb7, 0x8a, 0x93, 0x49, 0x0a, 0xea, 0x30, 0x00, 0xfe, 0x54, 0x03, 0x79, 0x79, 0xc2,
0x54, 0x1f, 0xe3, 0x09, 0xff, 0xd6, 0x90, 0x0e, 0x56, 0x46, 0x54, 0x9c, 0x05, 0x92, 0x40, 0x91,
0xb2, 0x00, 0xfe, 0x5d, 0x03, 0x3a, 0xae, 0x89, 0x02, 0x8f, 0xad, 0x1d, 0xdf, 0x74, 0x02, 0xe2,
0x8b, 0xae, 0x90, 0xea, 0x79, 0x6e, 0xde, 0x60, 0xef, 0xc2, 0x74, 0xc7, 0x59, 0x59, 0x90, 0xd6,
0xe9, 0x2b, 0x7d, 0xcc, 0x40, 0x7d, 0x0d, 0xe4, 0x81, 0x66, 0xa8, 0xd6, 0x4b, 0x1f, 0x1f, 0x42,
0xa0, 0xc5, 0x9d, 0x9d, 0xac, 0x0e, 0x71, 0xbb, 0x9d, 0x80, 0x2e, 0x7d, 0x98, 0x4d, 0xb7, 0xd6,
0xe9, 0x4b, 0x1f, 0xde, 0x13, 0xc6, 0x8a, 0xad, 0x50, 0x5d, 0xe3, 0xce, 0x7d, 0x67, 0x48, 0x67,
0xaf, 0x6e, 0xed, 0xb8, 0xf1, 0x52, 0x24, 0x8a, 0x12, 0x76, 0xc0, 0x5f, 0x69, 0x60, 0x0a, 0x1b,
0x06, 0xf1, 0x02, 0x52, 0x13, 0xb5, 0x38, 0xf3, 0x39, 0x94, 0x9b, 0x39, 0x69, 0xd5, 0xd4, 0x4a,
0x12, 0x1a, 0x75, 0x5a, 0x02, 0x5f, 0x06, 0xa7, 0x69, 0xe0, 0xfa, 0xa4, 0x16, 0x45, 0xae, 0xbc,
0x27, 0x60, 0xbb, 0x55, 0x3c, 0x5d, 0xed, 0xe0, 0xa0, 0x94, 0x64, 0xe9, 0xd3, 0x11, 0x50, 0x7c,
0x44, 0x66, 0x9c, 0xe0, 0xb5, 0xf3, 0x0c, 0x18, 0xe5, 0xdb, 0xad, 0x71, 0xaf, 0xe4, 0x13, 0x9d,
0x1b, 0xa7, 0x22, 0xc9, 0x65, 0x75, 0x9d, 0xe1, 0xb3, 0x6e, 0x23, 0xcb, 0x05, 0x55, 0x5d, 0xaf,
0x0a, 0x32, 0x8a, 0xf8, 0xf0, 0x5d, 0x30, 0x2a, 0xa6, 0x19, 0xbc, 0xa8, 0x0e, 0xb1, 0x30, 0x02,
0x6e, 0x27, 0x87, 0x42, 0x12, 0xb2, 0xbb, 0x20, 0xe6, 0x9e, 0x74, 0x41, 0x7c, 0x68, 0x05, 0x1a,
0xfd, 0x3f, 0xaf, 0x40, 0xa5, 0xff, 0x6a, 0xe9, 0xbc, 0x4f, 0x6c, 0xb5, 0x6a, 0x60, 0x8b, 0xc0,
0x35, 0x30, 0xc3, 0x1e, 0x19, 0x88, 0x78, 0x96, 0x69, 0x60, 0xca, 0x5f, 0xa2, 0x22, 0xe0, 0xd4,
0x70, 0xa4, 0x9a, 0xe2, 0xa3, 0xae, 0x15, 0xf0, 0x3a, 0x80, 0xa2, 0xf1, 0xee, 0xd0, 0x23, 0x7a,
0x08, 0xd5, 0x42, 0x57, 0xbb, 0x24, 0x50, 0x8f, 0x55, 0x70, 0x15, 0xcc, 0x5a, 0x78, 0x97, 0x58,
0x55, 0x62, 0x11, 0x23, 0x70, 0x7d, 0xae, 0x4a, 0xbc, 0xd5, 0xe7, 0xda, 0xad, 0xe2, 0xec, 0x8d,
0x34, 0x13, 0x75, 0xcb, 0x97, 0x16, 0xd3, 0xe9, 0x95, 0xdc, 0xb8, 0x78, 0xce, 0xfc, 0x2e, 0x03,
0xe6, 0xfb, 0x47, 0x06, 0x7c, 0x2f, 0x7e, 0x75, 0x89, 0xa6, 0xfa, 0xad, 0x61, 0x45, 0xa1, 0x7c,
0x76, 0x81, 0xee, 0x27, 0x17, 0xfc, 0x3e, 0xeb, 0x70, 0xb0, 0x15, 0x4d, 0x63, 0xde, 0x1c, 0x9a,
0x09, 0x0c, 0xa4, 0x32, 0x2e, 0x9a, 0x27, 0x6c, 0xf1, 0x5e, 0x09, 0x5b, 0xa4, 0xf4, 0x27, 0x2d,
0xfd, 0xf0, 0x8e, 0x33, 0x18, 0xfe, 0x4c, 0x03, 0xd3, 0xae, 0x47, 0x9c, 0x95, 0x9d, 0x8d, 0xdb,
0x5f, 0x11, 0x99, 0x2c, 0x5d, 0xb5, 0xf5, 0x98, 0x76, 0x5e, 0xaf, 0x6e, 0x6f, 0x09, 0x85, 0x3b,
0xbe, 0xeb, 0xd1, 0xca, 0x99, 0x76, 0xab, 0x38, 0xbd, 0xdd, 0x09, 0x85, 0xd2, 0xd8, 0x25, 0x1b,
0xcc, 0xad, 0x1f, 0x06, 0xc4, 0x77, 0xb0, 0xb5, 0xe6, 0x1a, 0xa1, 0x4d, 0x9c, 0x40, 0x18, 0x9a,
0x1a, 0xe5, 0x68, 0x27, 0x1c, 0xe5, 0x5c, 0x00, 0xd9, 0xd0, 0xb7, 0x64, 0x14, 0x4f, 0xa8, 0x51,
0x25, 0xba, 0x81, 0x18, 0xbd, 0xb4, 0x08, 0x46, 0x98, 0x9d, 0xf0, 0x1c, 0xc8, 0xfa, 0xf8, 0x80,
0x6b, 0x9d, 0xac, 0x8c, 0x31, 0x11, 0x84, 0x0f, 0x10, 0xa3, 0x95, 0xfe, 0x75, 0x1e, 0x4c, 0xa7,
0xf6, 0x02, 0xe7, 0x41, 0x46, 0xcd, 0x3f, 0x81, 0x54, 0x9a, 0xd9, 0x58, 0x43, 0x19, 0xb3, 0x06,
0x5f, 0x54, 0xc5, 0x57, 0x80, 0x16, 0x55, 0x3d, 0xe7, 0x54, 0xd6, 0xd2, 0xc6, 0xea, 0x98, 0x21,
0x51, 0xe1, 0x64, 0x36, 0x90, 0xba, 0xcc, 0x12, 0x61, 0x03, 0xa9, 0x23, 0x46, 0xfb, 0xac, 0x73,
0xac, 0x68, 0x90, 0x96, 0x3b, 0xc1, 0x20, 0x6d, 0xf4, 0xa1, 0x83, 0xb4, 0x8b, 0x20, 0x17, 0x98,
0x81, 0x45, 0xf4, 0xb1, 0xce, 0x97, 0xc7, 0x4d, 0x46, 0x44, 0x82, 0x07, 0xef, 0x80, 0xb1, 0x1a,
0xa9, 0xe3, 0xd0, 0x0a, 0xf4, 0x3c, 0x0f, 0xa1, 0xd5, 0x01, 0x84, 0x90, 0x98, 0x72, 0xae, 0x09,
0xbd, 0x28, 0x02, 0x80, 0x97, 0xc0, 0x98, 0x8d, 0x0f, 0x4d, 0x3b, 0xb4, 0x79, 0x4f, 0xa6, 0x09,
0xb1, 0x4d, 0x41, 0x42, 0x11, 0x8f, 0x55, 0x46, 0x72, 0x68, 0x58, 0x21, 0x35, 0x9b, 0x44, 0x32,
0x75, 0xc0, 0x6f, 0x4f, 0x55, 0x19, 0xd7, 0x53, 0x7c, 0xd4, 0xb5, 0x82, 0x83, 0x99, 0x0e, 0x5f,
0x3c, 0x91, 0x00, 0x13, 0x24, 0x14, 0xf1, 0x3a, 0xc1, 0xa4, 0xfc, 0x64, 0x3f, 0x30, 0xb9, 0xb8,
0x6b, 0x05, 0xfc, 0x32, 0x18, 0xb7, 0xf1, 0xe1, 0x0d, 0xe2, 0x34, 0x82, 0x3d, 0x7d, 0x6a, 0x41,
0x5b, 0xca, 0x56, 0xa6, 0xda, 0xad, 0xe2, 0xf8, 0x66, 0x44, 0x44, 0x31, 0x9f, 0x0b, 0x9b, 0x8e,
0x14, 0x3e, 0x9d, 0x10, 0x8e, 0x88, 0x28, 0xe6, 0xb3, 0x0e, 0xc2, 0xc3, 0x01, 0x4b, 0x2e, 0x7d,
0xba, 0xf3, 0x65, 0xb8, 0x23, 0xc8, 0x28, 0xe2, 0xc3, 0x25, 0x90, 0xb7, 0xf1, 0x21, 0x7f, 0xc5,
0xeb, 0x33, 0x5c, 0x2d, 0x9f, 0xf8, 0x6e, 0x4a, 0x1a, 0x52, 0x5c, 0x2e, 0x69, 0x3a, 0x42, 0x72,
0x36, 0x21, 0x29, 0x69, 0x48, 0x71, 0x59, 0x10, 0x87, 0x8e, 0x79, 0x37, 0x24, 0x42, 0x18, 0x72,
0xcf, 0xa8, 0x20, 0xbe, 0x15, 0xb3, 0x50, 0x52, 0x8e, 0xbd, 0xa2, 0xed, 0xd0, 0x0a, 0x4c, 0xcf,
0x22, 0xdb, 0x75, 0xfd, 0x0c, 0xf7, 0x3f, 0xef, 0x93, 0x37, 0x15, 0x15, 0x25, 0x24, 0x20, 0x01,
0x23, 0xc4, 0x09, 0x6d, 0xfd, 0x29, 0x7e, 0xb1, 0x0f, 0x24, 0x04, 0x55, 0xe6, 0xac, 0x3b, 0xa1,
0x8d, 0xb8, 0x7a, 0xf8, 0x22, 0x98, 0xb2, 0xf1, 0x21, 0x2b, 0x07, 0xc4, 0x0f, 0xd8, 0xfb, 0x7e,
0x8e, 0x6f, 0x7e, 0x96, 0x75, 0x9c, 0x9b, 0x49, 0x06, 0xea, 0x94, 0xe3, 0x0b, 0x4d, 0x27, 0xb1,
0xf0, 0x6c, 0x62, 0x61, 0x92, 0x81, 0x3a, 0xe5, 0x98, 0xa7, 0x7d, 0x72, 0x37, 0x34, 0x7d, 0x52,
0xd3, 0x9f, 0xe6, 0x4d, 0xaa, 0x9c, 0xc2, 0x0b, 0x1a, 0x52, 0x5c, 0xd8, 0x8c, 0xc6, 0x3d, 0x3a,
0x4f, 0xc3, 0x5b, 0x83, 0xad, 0xe4, 0xdb, 0xfe, 0x8a, 0xef, 0xe3, 0x23, 0x71, 0xd3, 0x24, 0x07,
0x3d, 0x90, 0x82, 0x1c, 0xb6, 0xac, 0xed, 0xba, 0x7e, 0x8e, 0xfb, 0x7e, 0xd0, 0x37, 0x88, 0xaa,
0x3a, 0x2b, 0x0c, 0x04, 0x09, 0x2c, 0x06, 0xea, 0x3a, 0x2c, 0x34, 0xe6, 0x87, 0x0b, 0xba, 0xcd,
0x40, 0x90, 0xc0, 0xe2, 0x3b, 0x75, 0x8e, 0xb6, 0xeb, 0xfa, 0x17, 0x86, 0xbc, 0x53, 0x06, 0x82,
0x04, 0x16, 0x34, 0x41, 0xd6, 0x71, 0x03, 0xfd, 0xfc, 0x50, 0xae, 0x67, 0x7e, 0xe1, 0x6c, 0xb9,
0x01, 0x62, 0x18, 0xf0, 0x97, 0x1a, 0x00, 0x5e, 0x1c, 0xa2, 0x17, 0x06, 0x32, 0x45, 0x48, 0x41,
0x96, 0xe3, 0xd8, 0x5e, 0x77, 0x02, 0xff, 0x28, 0x7e, 0x47, 0x26, 0x72, 0x20, 0x61, 0x05, 0xfc,
0xbd, 0x06, 0x9e, 0x4a, 0xb6, 0xc9, 0xca, 0xbc, 0x02, 0xf7, 0xc8, 0xcd, 0x41, 0x87, 0x79, 0xc5,
0x75, 0xad, 0x8a, 0xde, 0x6e, 0x15, 0x9f, 0x5a, 0xe9, 0x81, 0x8a, 0x7a, 0xda, 0x02, 0xff, 0xac,
0x81, 0x59, 0x59, 0x45, 0x13, 0x16, 0x16, 0xb9, 0x03, 0xc9, 0xa0, 0x1d, 0x98, 0xc6, 0x11, 0x7e,
0x54, 0xbf, 0x1e, 0x77, 0xf1, 0x51, 0xb7, 0x69, 0xf0, 0x6f, 0x1a, 0x98, 0xac, 0x11, 0x8f, 0x38,
0x35, 0xe2, 0x18, 0xcc, 0xd6, 0x85, 0x81, 0x8c, 0x0d, 0xd2, 0xb6, 0xae, 0x25, 0x20, 0x84, 0x99,
0x65, 0x69, 0xe6, 0x64, 0x92, 0x75, 0xdc, 0x2a, 0x9e, 0x8d, 0x97, 0x26, 0x39, 0xa8, 0xc3, 0x4a,
0xf8, 0x91, 0x06, 0xa6, 0xe3, 0x03, 0x10, 0x57, 0xca, 0xe2, 0x10, 0xe3, 0x80, 0xb7, 0xaf, 0x2b,
0x9d, 0x80, 0x28, 0x6d, 0x01, 0xfc, 0x8b, 0xc6, 0x3a, 0xb5, 0xe8, 0xdd, 0x47, 0xf5, 0x12, 0xf7,
0xe5, 0xdb, 0x03, 0xf7, 0xa5, 0x42, 0x10, 0xae, 0xbc, 0x1c, 0xb7, 0x82, 0x8a, 0x73, 0xdc, 0x2a,
0xce, 0x25, 0x3d, 0xa9, 0x18, 0x28, 0x69, 0x21, 0xfc, 0x89, 0x06, 0x26, 0x49, 0xdc, 0x71, 0x53,
0xfd, 0xe2, 0x40, 0x9c, 0xd8, 0xb3, 0x89, 0x17, 0x2f, 0xf5, 0x04, 0x8b, 0xa2, 0x0e, 0x6c, 0xd6,
0x41, 0x92, 0x43, 0x6c, 0x7b, 0x16, 0xd1, 0xbf, 0x38, 0xe0, 0x0e, 0x72, 0x5d, 0xe8, 0x45, 0x11,
0x00, 0xbc, 0x0c, 0xf2, 0x4e, 0x68, 0x59, 0x78, 0xd7, 0x22, 0xfa, 0x25, 0xde, 0x8b, 0xa8, 0x29,
0xe6, 0x96, 0xa4, 0x23, 0x25, 0x31, 0xcf, 0xde, 0x49, 0xa9, 0x3c, 0x83, 0x33, 0x20, 0xbb, 0x4f,
0xe4, 0x8f, 0xb6, 0x88, 0xfd, 0x09, 0x6b, 0x20, 0xd7, 0xc4, 0x56, 0x18, 0x3d, 0xf5, 0x06, 0x5c,
0xa3, 0x91, 0x50, 0xfe, 0x72, 0xe6, 0x25, 0x6d, 0xfe, 0x9e, 0x06, 0xce, 0xf6, 0x4e, 0xff, 0x27,
0x6a, 0xd6, 0x6f, 0x34, 0x30, 0xdb, 0x95, 0xe9, 0x3d, 0x2c, 0xba, 0xdb, 0x69, 0xd1, 0xeb, 0x83,
0x4e, 0xd9, 0x6a, 0xe0, 0x9b, 0x4e, 0x83, 0xf7, 0x29, 0x49, 0xf3, 0x7e, 0xae, 0x81, 0x99, 0x74,
0xf2, 0x3c, 0x49, 0x7f, 0x95, 0xee, 0x65, 0xc0, 0xd9, 0xde, 0xed, 0x15, 0xf4, 0xd5, 0x3b, 0x72,
0x38, 0xef, 0xf1, 0x5e, 0xb3, 0xbb, 0x0f, 0x34, 0x30, 0x71, 0x47, 0xc9, 0x45, 0x3f, 0x17, 0x0e,
0x7c, 0x12, 0x10, 0x55, 0xab, 0x98, 0x41, 0x51, 0x12, 0xb7, 0xf4, 0x57, 0x0d, 0xcc, 0xf5, 0x2c,
0xc3, 0xec, 0xc1, 0x8a, 0x2d, 0xcb, 0x3d, 0x10, 0x03, 0x9d, 0xc4, 0xb4, 0x74, 0x85, 0x53, 0x91,
0xe4, 0x26, 0xbc, 0x97, 0xf9, 0xbc, 0xbc, 0x57, 0xfa, 0x87, 0x06, 0xce, 0x3f, 0x2c, 0x12, 0x9f,
0xc8, 0x91, 0x2e, 0x81, 0xbc, 0x6c, 0xa1, 0x8e, 0xf8, 0x71, 0xca, 0x57, 0x83, 0x2c, 0x1a, 0xfc,
0xff, 0x58, 0xc4, 0x5f, 0xa5, 0xf7, 0x35, 0x30, 0x53, 0x25, 0x7e, 0xd3, 0x34, 0x08, 0x22, 0x75,
0xe2, 0x13, 0xc7, 0x20, 0x70, 0x19, 0x8c, 0xf3, 0xdf, 0xe9, 0x3c, 0x6c, 0x44, 0x43, 0xec, 0x59,
0xe9, 0xf2, 0xf1, 0xad, 0x88, 0x81, 0x62, 0x19, 0x35, 0xf0, 0xce, 0xf4, 0x1d, 0x78, 0x9f, 0x07,
0x23, 0x5e, 0x3c, 0x0e, 0xcc, 0x33, 0x2e, 0x9f, 0x00, 0x72, 0x6a, 0xe9, 0x9f, 0x1a, 0xe8, 0xf5,
0x3f, 0x25, 0xb0, 0x09, 0xc6, 0xa8, 0x30, 0x4e, 0x3a, 0x6f, 0xfb, 0x31, 0x9d, 0x97, 0xde, 0xaa,
0xb8, 0x26, 0x22, 0x6a, 0x04, 0xc6, 0xfc, 0x67, 0xe0, 0x4a, 0xe8, 0xd4, 0xe4, 0x00, 0x6f, 0x52,
0xf8, 0x6f, 0x75, 0x45, 0xd0, 0x90, 0xe2, 0xc2, 0x73, 0x62, 0xd4, 0x94, 0x98, 0xdf, 0x44, 0x63,
0xa6, 0xca, 0x95, 0xfb, 0x0f, 0x0a, 0xa7, 0x3e, 0x7e, 0x50, 0x38, 0xf5, 0xc9, 0x83, 0xc2, 0xa9,
0x1f, 0xb4, 0x0b, 0xda, 0xfd, 0x76, 0x41, 0xfb, 0xb8, 0x5d, 0xd0, 0x3e, 0x69, 0x17, 0xb4, 0x7f,
0xb7, 0x0b, 0xda, 0x2f, 0x3e, 0x2d, 0x9c, 0xfa, 0xce, 0x98, 0x34, 0xed, 0x7f, 0x01, 0x00, 0x00,
0xff, 0xff, 0x3a, 0x56, 0xbb, 0xc0, 0xe9, 0x29, 0x00, 0x00,
// 2783 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xdf, 0x6f, 0x23, 0x57,
0xf5, 0xdf, 0xb1, 0xe3, 0xc4, 0xb9, 0x49, 0x36, 0xc9, 0xdd, 0x66, 0x3b, 0x9b, 0x6f, 0x6a, 0x27,
0xee, 0xb7, 0x55, 0x28, 0xbb, 0x4e, 0xbb, 0xb4, 0xb4, 0x54, 0xe2, 0x21, 0x76, 0xd2, 0x2a, 0x65,
0xf3, 0x83, 0xeb, 0xdd, 0xb6, 0xd0, 0x9f, 0x37, 0xe3, 0x6b, 0x67, 0x36, 0xf3, 0x6b, 0xe7, 0xce,
0x38, 0x89, 0x0a, 0x08, 0xa8, 0x2a, 0x10, 0x02, 0x8a, 0xe8, 0xbe, 0x20, 0xe0, 0x01, 0x10, 0x2f,
0x3c, 0xc0, 0x03, 0xbc, 0xc1, 0x1f, 0xb0, 0x8f, 0x15, 0x4f, 0x15, 0x42, 0x16, 0xeb, 0xfe, 0x0b,
0x48, 0x48, 0x79, 0x42, 0xf7, 0xc7, 0xdc, 0x19, 0x8f, 0xed, 0xdd, 0xa8, 0x6b, 0x77, 0x79, 0xcb,
0x9c, 0x73, 0xee, 0xf9, 0x9c, 0x7b, 0xee, 0x39, 0xe7, 0x9e, 0x7b, 0x1c, 0xd0, 0x38, 0x7c, 0x81,
0x96, 0x4d, 0x77, 0xed, 0x30, 0xdc, 0x27, 0xbe, 0x43, 0x02, 0x42, 0xd7, 0x5a, 0xc4, 0xa9, 0xbb,
0xfe, 0x9a, 0x64, 0x60, 0xcf, 0x24, 0xc7, 0x01, 0x71, 0xa8, 0xe9, 0x3a, 0xf4, 0x0a, 0xf6, 0x4c,
0x4a, 0xfc, 0x16, 0xf1, 0xd7, 0xbc, 0xc3, 0x26, 0xe3, 0xd1, 0x6e, 0x81, 0xb5, 0xd6, 0x33, 0xfb,
0x24, 0xc0, 0xcf, 0xac, 0x35, 0x89, 0x43, 0x7c, 0x1c, 0x90, 0x7a, 0xd9, 0xf3, 0xdd, 0xc0, 0x85,
0x5f, 0x15, 0xea, 0xca, 0x5d, 0xd2, 0xef, 0x28, 0x75, 0x65, 0xef, 0xb0, 0xc9, 0x78, 0xb4, 0x5b,
0xa0, 0x2c, 0xd5, 0x2d, 0x5e, 0x69, 0x9a, 0xc1, 0x41, 0xb8, 0x5f, 0x36, 0x5c, 0x7b, 0xad, 0xe9,
0x36, 0xdd, 0x35, 0xae, 0x75, 0x3f, 0x6c, 0xf0, 0x2f, 0xfe, 0xc1, 0xff, 0x12, 0x68, 0x8b, 0xcf,
0xc6, 0xc6, 0xdb, 0xd8, 0x38, 0x30, 0x1d, 0xe2, 0x9f, 0xc4, 0x16, 0xdb, 0x24, 0xc0, 0x6b, 0xad,
0x1e, 0x1b, 0x17, 0xd7, 0x06, 0xad, 0xf2, 0x43, 0x27, 0x30, 0x6d, 0xd2, 0xb3, 0xe0, 0xcb, 0xf7,
0x5b, 0x40, 0x8d, 0x03, 0x62, 0xe3, 0xf4, 0xba, 0xd2, 0xa9, 0x06, 0xe6, 0xab, 0xae, 0xd3, 0x22,
0x3e, 0xdb, 0x25, 0x22, 0xb7, 0x42, 0x42, 0x03, 0x58, 0x01, 0xd9, 0xd0, 0xac, 0xeb, 0xda, 0xb2,
0xb6, 0x3a, 0x59, 0x79, 0xfa, 0x4e, 0xbb, 0x78, 0xae, 0xd3, 0x2e, 0x66, 0x6f, 0x6c, 0x6d, 0x9c,
0xb6, 0x8b, 0x2b, 0x83, 0x90, 0x82, 0x13, 0x8f, 0xd0, 0xf2, 0x8d, 0xad, 0x0d, 0xc4, 0x16, 0xc3,
0x97, 0xc1, 0x7c, 0x9d, 0x50, 0xd3, 0x27, 0xf5, 0xf5, 0xbd, 0xad, 0x57, 0x85, 0x7e, 0x3d, 0xc3,
0x35, 0x5e, 0x92, 0x1a, 0xe7, 0x37, 0xd2, 0x02, 0xa8, 0x77, 0x0d, 0x7c, 0x1d, 0x4c, 0xb8, 0xfb,
0x37, 0x89, 0x11, 0x50, 0x3d, 0xbb, 0x9c, 0x5d, 0x9d, 0xba, 0x7a, 0xa5, 0x1c, 0x9f, 0xa0, 0x32,
0x81, 0x1f, 0x9b, 0xdc, 0x6c, 0x19, 0xe1, 0xa3, 0xcd, 0xe8, 0xe4, 0x2a, 0xb3, 0x12, 0x6d, 0x62,
0x57, 0x68, 0x41, 0x91, 0xba, 0xd2, 0xef, 0x32, 0x00, 0x26, 0x37, 0x4f, 0x3d, 0xd7, 0xa1, 0x64,
0x28, 0xbb, 0xa7, 0x60, 0xce, 0xe0, 0x9a, 0x03, 0x52, 0x97, 0xb8, 0x7a, 0xe6, 0xb3, 0x58, 0xaf,
0x4b, 0xfc, 0xb9, 0x6a, 0x4a, 0x1d, 0xea, 0x01, 0x80, 0xd7, 0xc1, 0xb8, 0x4f, 0x68, 0x68, 0x05,
0x7a, 0x76, 0x59, 0x5b, 0x9d, 0xba, 0x7a, 0x79, 0x20, 0x14, 0x8f, 0x6f, 0x16, 0x7c, 0xe5, 0xd6,
0x33, 0xe5, 0x5a, 0x80, 0x83, 0x90, 0x56, 0xce, 0x4b, 0xa4, 0x71, 0xc4, 0x75, 0x20, 0xa9, 0xab,
0xf4, 0xc3, 0x0c, 0x98, 0x4b, 0x7a, 0xa9, 0x65, 0x92, 0x23, 0x78, 0x04, 0x26, 0x7c, 0x11, 0x2c,
0xdc, 0x4f, 0x53, 0x57, 0xf7, 0xca, 0x0f, 0x94, 0x56, 0xe5, 0x9e, 0x20, 0xac, 0x4c, 0xb1, 0x33,
0x93, 0x1f, 0x28, 0x42, 0x83, 0xef, 0x81, 0xbc, 0x2f, 0x0f, 0x8a, 0x47, 0xd3, 0xd4, 0xd5, 0xaf,
0x0f, 0x11, 0x59, 0x28, 0xae, 0x4c, 0x77, 0xda, 0xc5, 0x7c, 0xf4, 0x85, 0x14, 0x60, 0xe9, 0xa3,
0x0c, 0x28, 0x54, 0x43, 0x1a, 0xb8, 0x36, 0x22, 0xd4, 0x0d, 0x7d, 0x83, 0x54, 0x5d, 0x2b, 0xb4,
0x9d, 0x0d, 0xd2, 0x30, 0x1d, 0x33, 0x60, 0xd1, 0xba, 0x0c, 0xc6, 0x1c, 0x6c, 0x13, 0x19, 0x3d,
0xd3, 0xd2, 0xa7, 0x63, 0x3b, 0xd8, 0x26, 0x88, 0x73, 0x98, 0x04, 0x0b, 0x16, 0x99, 0x0b, 0x4a,
0xe2, 0xfa, 0x89, 0x47, 0x10, 0xe7, 0xc0, 0x27, 0xc1, 0x78, 0xc3, 0xf5, 0x6d, 0x2c, 0xce, 0x71,
0x32, 0x3e, 0x99, 0x97, 0x38, 0x15, 0x49, 0x2e, 0x7c, 0x0e, 0x4c, 0xd5, 0x09, 0x35, 0x7c, 0xd3,
0x63, 0xd0, 0xfa, 0x18, 0x17, 0xbe, 0x20, 0x85, 0xa7, 0x36, 0x62, 0x16, 0x4a, 0xca, 0xc1, 0xcb,
0x20, 0xef, 0xf9, 0xa6, 0xeb, 0x9b, 0xc1, 0x89, 0x9e, 0x5b, 0xd6, 0x56, 0x73, 0x95, 0x39, 0xb9,
0x26, 0xbf, 0x27, 0xe9, 0x48, 0x49, 0xc0, 0x65, 0x90, 0x7f, 0xa5, 0xb6, 0xbb, 0xb3, 0x87, 0x83,
0x03, 0x7d, 0x9c, 0x23, 0x8c, 0x31, 0x69, 0x94, 0xbf, 0x29, 0xa9, 0xa5, 0x7f, 0x66, 0x80, 0x9e,
0xf6, 0x4a, 0xe4, 0x52, 0xf8, 0x12, 0xc8, 0xd3, 0x80, 0x55, 0x9c, 0xe6, 0x89, 0xf4, 0xc9, 0x53,
0x11, 0x58, 0x4d, 0xd2, 0x4f, 0xdb, 0xc5, 0x8b, 0xf1, 0x8a, 0x88, 0xca, 0xfd, 0xa1, 0xd6, 0xc2,
0x5f, 0x6b, 0xe0, 0xc2, 0x11, 0xd9, 0x3f, 0x70, 0xdd, 0xc3, 0xaa, 0x65, 0x12, 0x27, 0xa8, 0xba,
0x4e, 0xc3, 0x6c, 0xca, 0x18, 0x40, 0x0f, 0x18, 0x03, 0xaf, 0xf5, 0x6a, 0xae, 0x3c, 0xda, 0x69,
0x17, 0x2f, 0xf4, 0x61, 0xa0, 0x7e, 0x76, 0xc0, 0xd7, 0x81, 0x6e, 0xa4, 0x92, 0x44, 0x16, 0x30,
0x51, 0xb6, 0x26, 0x2b, 0x4b, 0x9d, 0x76, 0x51, 0xaf, 0x0e, 0x90, 0x41, 0x03, 0x57, 0x97, 0xde,
0xcf, 0xa6, 0xdd, 0x9b, 0x08, 0xb7, 0x77, 0x41, 0x9e, 0xa5, 0x71, 0x1d, 0x07, 0x58, 0x26, 0xe2,
0xd3, 0x67, 0x4b, 0x7a, 0x51, 0x33, 0xb6, 0x49, 0x80, 0x2b, 0x50, 0x1e, 0x08, 0x88, 0x69, 0x48,
0x69, 0x85, 0xdf, 0x06, 0x63, 0xd4, 0x23, 0x86, 0x74, 0xf4, 0x1b, 0x0f, 0x9a, 0x6c, 0x03, 0x36,
0x52, 0xf3, 0x88, 0x11, 0xe7, 0x02, 0xfb, 0x42, 0x1c, 0x16, 0x7e, 0xa0, 0x81, 0x71, 0xca, 0x0b,
0x94, 0x2c, 0x6a, 0x6f, 0x8d, 0xca, 0x82, 0x54, 0x15, 0x14, 0xdf, 0x48, 0x82, 0x97, 0xfe, 0x9d,
0x01, 0x2b, 0x83, 0x96, 0x56, 0x5d, 0xa7, 0x2e, 0x8e, 0x63, 0x4b, 0xe6, 0xb6, 0x88, 0xf4, 0xe7,
0x92, 0xb9, 0x7d, 0xda, 0x2e, 0x3e, 0x71, 0x5f, 0x05, 0x89, 0x22, 0xf0, 0x15, 0xb5, 0x6f, 0x51,
0x28, 0x56, 0xba, 0x0d, 0x3b, 0x6d, 0x17, 0x67, 0xd5, 0xb2, 0x6e, 0x5b, 0x61, 0x0b, 0x40, 0x0b,
0xd3, 0xe0, 0xba, 0x8f, 0x1d, 0x2a, 0xd4, 0x9a, 0x36, 0x91, 0xee, 0x7b, 0xea, 0x6c, 0xe1, 0xc1,
0x56, 0x54, 0x16, 0x25, 0x24, 0xbc, 0xd6, 0xa3, 0x0d, 0xf5, 0x41, 0x60, 0x75, 0xcb, 0x27, 0x98,
0xaa, 0x52, 0x94, 0xb8, 0x51, 0x18, 0x15, 0x49, 0x2e, 0xfc, 0x02, 0x98, 0xb0, 0x09, 0xa5, 0xb8,
0x49, 0x78, 0xfd, 0x99, 0x8c, 0xaf, 0xe8, 0x6d, 0x41, 0x46, 0x11, 0x9f, 0xf5, 0x27, 0x4b, 0x83,
0xbc, 0x76, 0xcd, 0xa4, 0x01, 0x7c, 0xb3, 0x27, 0x01, 0xca, 0x67, 0xdb, 0x21, 0x5b, 0xcd, 0xc3,
0x5f, 0x15, 0xbf, 0x88, 0x92, 0x08, 0xfe, 0x6f, 0x81, 0x9c, 0x19, 0x10, 0x3b, 0xba, 0xbb, 0x5f,
0x1b, 0x51, 0xec, 0x55, 0x66, 0xa4, 0x0d, 0xb9, 0x2d, 0x86, 0x86, 0x04, 0x68, 0xe9, 0xf7, 0x19,
0xf0, 0xd8, 0xa0, 0x25, 0xec, 0x42, 0xa1, 0xcc, 0xe3, 0x9e, 0x15, 0xfa, 0xd8, 0x92, 0x11, 0xa7,
0x3c, 0xbe, 0xc7, 0xa9, 0x48, 0x72, 0x59, 0xc9, 0xa7, 0xa6, 0xd3, 0x0c, 0x2d, 0xec, 0xcb, 0x70,
0x52, 0xbb, 0xae, 0x49, 0x3a, 0x52, 0x12, 0xb0, 0x0c, 0x00, 0x3d, 0x70, 0xfd, 0x80, 0x63, 0xc8,
0xea, 0x75, 0x9e, 0x15, 0x88, 0x9a, 0xa2, 0xa2, 0x84, 0x04, 0xbb, 0xd1, 0x0e, 0x4d, 0xa7, 0x2e,
0x4f, 0x5d, 0x65, 0xf1, 0xd7, 0x4c, 0xa7, 0x8e, 0x38, 0x87, 0xe1, 0x5b, 0x26, 0x0d, 0x18, 0x45,
0x1e, 0x79, 0x97, 0xd7, 0xb9, 0xa4, 0x92, 0x60, 0xf8, 0x06, 0xab, 0xfa, 0xae, 0x6f, 0x12, 0xaa,
0x8f, 0xc7, 0xf8, 0x55, 0x45, 0x45, 0x09, 0x89, 0xd2, 0x2f, 0xf3, 0x83, 0x83, 0x84, 0x95, 0x12,
0xf8, 0x38, 0xc8, 0x35, 0x7d, 0x37, 0xf4, 0xa4, 0x97, 0x94, 0xb7, 0x5f, 0x66, 0x44, 0x24, 0x78,
0x2c, 0x2a, 0x5b, 0x5d, 0x6d, 0xaa, 0x8a, 0xca, 0xa8, 0x39, 0x8d, 0xf8, 0xf0, 0x7b, 0x1a, 0xc8,
0x39, 0xd2, 0x39, 0x2c, 0xe4, 0xde, 0x1c, 0x51, 0x5c, 0x70, 0xf7, 0xc6, 0xe6, 0x0a, 0xcf, 0x0b,
0x64, 0xf8, 0x2c, 0xc8, 0x51, 0xc3, 0xf5, 0x88, 0xf4, 0x7a, 0x21, 0x12, 0xaa, 0x31, 0xe2, 0x69,
0xbb, 0x38, 0x13, 0xa9, 0xe3, 0x04, 0x24, 0x84, 0xe1, 0x0f, 0x34, 0x00, 0x5a, 0xd8, 0x32, 0xeb,
0x98, 0xb7, 0x0c, 0x39, 0x6e, 0xfe, 0x70, 0xc3, 0xfa, 0x55, 0xa5, 0x5e, 0x1c, 0x5a, 0xfc, 0x8d,
0x12, 0xd0, 0xf0, 0x43, 0x0d, 0x4c, 0xd3, 0x70, 0xdf, 0x97, 0xab, 0x28, 0x6f, 0x2e, 0xa6, 0xae,
0x7e, 0x63, 0xa8, 0xb6, 0xd4, 0x12, 0x00, 0x95, 0xb9, 0x4e, 0xbb, 0x38, 0x9d, 0xa4, 0xa0, 0x2e,
0x03, 0xe0, 0x8f, 0x35, 0x90, 0x6f, 0x45, 0x77, 0xf6, 0x04, 0x4f, 0xf8, 0xb7, 0x47, 0x74, 0xb0,
0x32, 0xa2, 0xe2, 0x2c, 0x50, 0x7d, 0x80, 0xb2, 0x00, 0xfe, 0x55, 0x03, 0x3a, 0xae, 0x8b, 0x02,
0x8f, 0xad, 0x3d, 0xdf, 0x74, 0x02, 0xe2, 0x8b, 0x7e, 0x93, 0xea, 0x79, 0x6e, 0xde, 0x70, 0xef,
0xc2, 0x74, 0x2f, 0x5b, 0x59, 0x96, 0xd6, 0xe9, 0xeb, 0x03, 0xcc, 0x40, 0x03, 0x0d, 0xe4, 0x81,
0x16, 0xb7, 0x34, 0xfa, 0xe4, 0x08, 0x02, 0x2d, 0xee, 0xa5, 0x64, 0x75, 0x88, 0x3b, 0xa8, 0x04,
0x74, 0xe9, 0xc3, 0x6c, 0xba, 0x69, 0x4f, 0x5f, 0xfa, 0xf0, 0xb6, 0x30, 0x56, 0x6c, 0x85, 0xea,
0x1a, 0x77, 0xee, 0xbb, 0x23, 0x3a, 0x7b, 0x75, 0x6b, 0xc7, 0x8d, 0x97, 0x22, 0x51, 0x94, 0xb0,
0x03, 0xfe, 0x42, 0x03, 0x33, 0xd8, 0x30, 0x88, 0x17, 0x90, 0xba, 0xa8, 0xc5, 0x99, 0xcf, 0xa1,
0xdc, 0x2c, 0x48, 0xab, 0x66, 0xd6, 0x93, 0xd0, 0xa8, 0xdb, 0x12, 0xf8, 0x22, 0x38, 0x4f, 0x03,
0xd7, 0x27, 0xf5, 0x54, 0x97, 0x0b, 0x3b, 0xed, 0xe2, 0xf9, 0x5a, 0x17, 0x07, 0xa5, 0x24, 0x4b,
0x9f, 0x8e, 0x81, 0xe2, 0x7d, 0x32, 0xe3, 0x0c, 0xef, 0xa8, 0x27, 0xc1, 0x38, 0xdf, 0x6e, 0x9d,
0x7b, 0x25, 0x9f, 0xe8, 0xdc, 0x38, 0x15, 0x49, 0x2e, 0xab, 0xeb, 0x0c, 0x9f, 0x75, 0x1b, 0x59,
0x2e, 0xa8, 0xea, 0x7a, 0x4d, 0x90, 0x51, 0xc4, 0x87, 0xef, 0x81, 0x71, 0x31, 0x27, 0xe1, 0x45,
0x75, 0x84, 0x85, 0x11, 0x70, 0x3b, 0x39, 0x14, 0x92, 0x90, 0xbd, 0x05, 0x31, 0xf7, 0xb0, 0x0b,
0xe2, 0x3d, 0x2b, 0xd0, 0xf8, 0xff, 0x78, 0x05, 0x2a, 0xfd, 0x47, 0x4b, 0xe7, 0x7d, 0x62, 0xab,
0x35, 0x03, 0x5b, 0x04, 0x6e, 0x80, 0x39, 0xf6, 0xc8, 0x40, 0xc4, 0xb3, 0x4c, 0x03, 0x53, 0xfe,
0xc6, 0x15, 0x01, 0xa7, 0xc6, 0x2e, 0xb5, 0x14, 0x1f, 0xf5, 0xac, 0x80, 0xaf, 0x00, 0x28, 0x1a,
0xef, 0x2e, 0x3d, 0xa2, 0x87, 0x50, 0x2d, 0x74, 0xad, 0x47, 0x02, 0xf5, 0x59, 0x05, 0xab, 0x60,
0xde, 0xc2, 0xfb, 0xc4, 0xaa, 0x11, 0x8b, 0x18, 0x81, 0xeb, 0x73, 0x55, 0x62, 0x0a, 0xb0, 0xd0,
0x69, 0x17, 0xe7, 0xaf, 0xa5, 0x99, 0xa8, 0x57, 0xbe, 0xb4, 0x92, 0x4e, 0xaf, 0xe4, 0xc6, 0xc5,
0x73, 0xe6, 0x37, 0x19, 0xb0, 0x38, 0x38, 0x32, 0xe0, 0xf7, 0xe3, 0x57, 0x97, 0x68, 0xaa, 0xdf,
0x1e, 0x55, 0x14, 0xca, 0x67, 0x17, 0xe8, 0x7d, 0x72, 0xc1, 0xef, 0xb0, 0x0e, 0x07, 0x5b, 0xd1,
0x9c, 0xe7, 0xad, 0x91, 0x99, 0xc0, 0x40, 0x2a, 0x93, 0xa2, 0x79, 0xc2, 0x16, 0xef, 0x95, 0xb0,
0x45, 0x4a, 0x7f, 0xd0, 0xd2, 0x0f, 0xef, 0x38, 0x83, 0xe1, 0x4f, 0x34, 0x30, 0xeb, 0x7a, 0xc4,
0x59, 0xdf, 0xdb, 0x7a, 0xf5, 0x4b, 0x22, 0x93, 0xa5, 0xab, 0x76, 0x1e, 0xd0, 0xce, 0x57, 0x6a,
0xbb, 0x3b, 0x42, 0xe1, 0x9e, 0xef, 0x7a, 0xb4, 0x72, 0xa1, 0xd3, 0x2e, 0xce, 0xee, 0x76, 0x43,
0xa1, 0x34, 0x76, 0xc9, 0x06, 0x0b, 0x9b, 0xc7, 0x01, 0xf1, 0x1d, 0x6c, 0x6d, 0xb8, 0x46, 0x68,
0x13, 0x27, 0x10, 0x86, 0xa6, 0x86, 0x44, 0xda, 0x19, 0x87, 0x44, 0x8f, 0x81, 0x6c, 0xe8, 0x5b,
0x32, 0x8a, 0xa7, 0xd4, 0x10, 0x14, 0x5d, 0x43, 0x8c, 0x5e, 0x5a, 0x01, 0x63, 0xcc, 0x4e, 0x78,
0x09, 0x64, 0x7d, 0x7c, 0xc4, 0xb5, 0x4e, 0x57, 0x26, 0x98, 0x08, 0xc2, 0x47, 0x88, 0xd1, 0x4a,
0xff, 0x58, 0x02, 0xb3, 0xa9, 0xbd, 0xc0, 0x45, 0x90, 0x51, 0x93, 0x55, 0x20, 0x95, 0x66, 0xb6,
0x36, 0x50, 0xc6, 0xac, 0xc3, 0xe7, 0x55, 0xf1, 0x15, 0xa0, 0x45, 0x55, 0xcf, 0x39, 0x95, 0xb5,
0xb4, 0xb1, 0x3a, 0x66, 0x48, 0x54, 0x38, 0x99, 0x0d, 0xa4, 0x21, 0xb3, 0x44, 0xd8, 0x40, 0x1a,
0x88, 0xd1, 0x3e, 0xeb, 0x84, 0x2c, 0x1a, 0xd1, 0xe5, 0xce, 0x30, 0xa2, 0x1b, 0xbf, 0xe7, 0x88,
0xee, 0x71, 0x90, 0x0b, 0xcc, 0xc0, 0x22, 0xfa, 0x44, 0xf7, 0xcb, 0xe3, 0x3a, 0x23, 0x22, 0xc1,
0x83, 0x37, 0xc1, 0x44, 0x9d, 0x34, 0x70, 0x68, 0x05, 0x7a, 0x9e, 0x87, 0x50, 0x75, 0x08, 0x21,
0x24, 0xe6, 0xa7, 0x1b, 0x42, 0x2f, 0x8a, 0x00, 0xe0, 0x13, 0x60, 0xc2, 0xc6, 0xc7, 0xa6, 0x1d,
0xda, 0xbc, 0x27, 0xd3, 0x84, 0xd8, 0xb6, 0x20, 0xa1, 0x88, 0xc7, 0x2a, 0x23, 0x39, 0x36, 0xac,
0x90, 0x9a, 0x2d, 0x22, 0x99, 0x3a, 0xe0, 0xb7, 0xa7, 0xaa, 0x8c, 0x9b, 0x29, 0x3e, 0xea, 0x59,
0xc1, 0xc1, 0x4c, 0x87, 0x2f, 0x9e, 0x4a, 0x80, 0x09, 0x12, 0x8a, 0x78, 0xdd, 0x60, 0x52, 0x7e,
0x7a, 0x10, 0x98, 0x5c, 0xdc, 0xb3, 0x02, 0x7e, 0x11, 0x4c, 0xda, 0xf8, 0xf8, 0x1a, 0x71, 0x9a,
0xc1, 0x81, 0x3e, 0xb3, 0xac, 0xad, 0x66, 0x2b, 0x33, 0x9d, 0x76, 0x71, 0x72, 0x3b, 0x22, 0xa2,
0x98, 0xcf, 0x85, 0x4d, 0x47, 0x0a, 0x9f, 0x4f, 0x08, 0x47, 0x44, 0x14, 0xf3, 0x59, 0x07, 0xe1,
0xe1, 0x80, 0x25, 0x97, 0x3e, 0xdb, 0xfd, 0x32, 0xdc, 0x13, 0x64, 0x14, 0xf1, 0xe1, 0x2a, 0xc8,
0xdb, 0xf8, 0x98, 0xbf, 0xe2, 0xf5, 0x39, 0xae, 0x96, 0xcf, 0x92, 0xb7, 0x25, 0x0d, 0x29, 0x2e,
0x97, 0x34, 0x1d, 0x21, 0x39, 0x9f, 0x90, 0x94, 0x34, 0xa4, 0xb8, 0x2c, 0x88, 0x43, 0xc7, 0xbc,
0x15, 0x12, 0x21, 0x0c, 0xb9, 0x67, 0x54, 0x10, 0xdf, 0x88, 0x59, 0x28, 0x29, 0xc7, 0x5e, 0xd1,
0x76, 0x68, 0x05, 0xa6, 0x67, 0x91, 0xdd, 0x86, 0x7e, 0x81, 0xfb, 0x9f, 0xf7, 0xc9, 0xdb, 0x8a,
0x8a, 0x12, 0x12, 0x90, 0x80, 0x31, 0xe2, 0x84, 0xb6, 0xfe, 0x08, 0xbf, 0xd8, 0x87, 0x12, 0x82,
0x2a, 0x73, 0x36, 0x9d, 0xd0, 0x46, 0x5c, 0x3d, 0x7c, 0x1e, 0xcc, 0xd8, 0xf8, 0x98, 0x95, 0x03,
0xe2, 0x07, 0xec, 0x7d, 0xbf, 0xc0, 0x37, 0x3f, 0xcf, 0x3a, 0xce, 0xed, 0x24, 0x03, 0x75, 0xcb,
0xf1, 0x85, 0xa6, 0x93, 0x58, 0x78, 0x31, 0xb1, 0x30, 0xc9, 0x40, 0xdd, 0x72, 0xcc, 0xd3, 0x3e,
0xb9, 0x15, 0x9a, 0x3e, 0xa9, 0xeb, 0x8f, 0xf2, 0x26, 0x55, 0xce, 0xf7, 0x05, 0x0d, 0x29, 0x2e,
0x6c, 0x45, 0xe3, 0x1e, 0x9d, 0xa7, 0xe1, 0x8d, 0xe1, 0x56, 0xf2, 0x5d, 0x7f, 0xdd, 0xf7, 0xf1,
0x89, 0xb8, 0x69, 0x92, 0x83, 0x1e, 0x48, 0x41, 0x0e, 0x5b, 0xd6, 0x6e, 0x43, 0xbf, 0xc4, 0x7d,
0x3f, 0xec, 0x1b, 0x44, 0x55, 0x9d, 0x75, 0x06, 0x82, 0x04, 0x16, 0x03, 0x75, 0x1d, 0x16, 0x1a,
0x8b, 0xa3, 0x05, 0xdd, 0x65, 0x20, 0x48, 0x60, 0xf1, 0x9d, 0x3a, 0x27, 0xbb, 0x0d, 0xfd, 0xff,
0x46, 0xbc, 0x53, 0x06, 0x82, 0x04, 0x16, 0x34, 0x41, 0xd6, 0x71, 0x03, 0x7d, 0x69, 0x24, 0xd7,
0x33, 0xbf, 0x70, 0x76, 0xdc, 0x00, 0x31, 0x0c, 0xf8, 0x73, 0x0d, 0x00, 0x2f, 0x0e, 0xd1, 0xc7,
0x86, 0x32, 0x45, 0x48, 0x41, 0x96, 0xe3, 0xd8, 0xde, 0x74, 0x02, 0xff, 0x24, 0x7e, 0x47, 0x26,
0x72, 0x20, 0x61, 0x05, 0xfc, 0xad, 0x06, 0x1e, 0x49, 0xb6, 0xc9, 0xca, 0xbc, 0x02, 0xf7, 0xc8,
0xf5, 0x61, 0x87, 0x79, 0xc5, 0x75, 0xad, 0x8a, 0xde, 0x69, 0x17, 0x1f, 0x59, 0xef, 0x83, 0x8a,
0xfa, 0xda, 0x02, 0xff, 0xa8, 0x81, 0x79, 0x59, 0x45, 0x13, 0x16, 0x16, 0xb9, 0x03, 0xc9, 0xb0,
0x1d, 0x98, 0xc6, 0x11, 0x7e, 0x54, 0xbf, 0x4b, 0xf7, 0xf0, 0x51, 0xaf, 0x69, 0xf0, 0x2f, 0x1a,
0x98, 0xae, 0x13, 0x8f, 0x38, 0x75, 0xe2, 0x18, 0xcc, 0xd6, 0xe5, 0xa1, 0x8c, 0x0d, 0xd2, 0xb6,
0x6e, 0x24, 0x20, 0x84, 0x99, 0x65, 0x69, 0xe6, 0x74, 0x92, 0x75, 0xda, 0x2e, 0x5e, 0x8c, 0x97,
0x26, 0x39, 0xa8, 0xcb, 0x4a, 0xf8, 0x91, 0x06, 0x66, 0xe3, 0x03, 0x10, 0x57, 0xca, 0xca, 0x08,
0xe3, 0x80, 0xb7, 0xaf, 0xeb, 0xdd, 0x80, 0x28, 0x6d, 0x01, 0xfc, 0x93, 0xc6, 0x3a, 0xb5, 0xe8,
0xdd, 0x47, 0xf5, 0x12, 0xf7, 0xe5, 0x3b, 0x43, 0xf7, 0xa5, 0x42, 0x10, 0xae, 0xbc, 0x1c, 0xb7,
0x82, 0x8a, 0x73, 0xda, 0x2e, 0x2e, 0x24, 0x3d, 0xa9, 0x18, 0x28, 0x69, 0x21, 0xfc, 0x91, 0x06,
0xa6, 0x49, 0xdc, 0x71, 0x53, 0xfd, 0xf1, 0xa1, 0x38, 0xb1, 0x6f, 0x13, 0x2f, 0x5e, 0xea, 0x09,
0x16, 0x45, 0x5d, 0xd8, 0xac, 0x83, 0x24, 0xc7, 0xd8, 0xf6, 0x2c, 0xa2, 0xff, 0xff, 0x90, 0x3b,
0xc8, 0x4d, 0xa1, 0x17, 0x45, 0x00, 0xf0, 0x32, 0xc8, 0x3b, 0xa1, 0x65, 0xe1, 0x7d, 0x8b, 0xe8,
0x4f, 0xf0, 0x5e, 0x44, 0x4d, 0x31, 0x77, 0x24, 0x1d, 0x29, 0x89, 0x45, 0xf6, 0x4e, 0x4a, 0xe5,
0x19, 0x9c, 0x03, 0xd9, 0x43, 0x22, 0x7f, 0x0e, 0x46, 0xec, 0x4f, 0x58, 0x07, 0xb9, 0x16, 0xb6,
0xc2, 0xe8, 0xa9, 0x37, 0xe4, 0x1a, 0x8d, 0x84, 0xf2, 0x17, 0x33, 0x2f, 0x68, 0x8b, 0xb7, 0x35,
0x70, 0xb1, 0x7f, 0xfa, 0x3f, 0x54, 0xb3, 0x7e, 0xa5, 0x81, 0xf9, 0x9e, 0x4c, 0xef, 0x63, 0xd1,
0xad, 0x6e, 0x8b, 0xde, 0x18, 0x76, 0xca, 0xd6, 0x02, 0xdf, 0x74, 0x9a, 0xbc, 0x4f, 0x49, 0x9a,
0xf7, 0x53, 0x0d, 0xcc, 0xa5, 0x93, 0xe7, 0x61, 0xfa, 0xab, 0x74, 0x3b, 0x03, 0x2e, 0xf6, 0x6f,
0xaf, 0xa0, 0xaf, 0xde, 0x91, 0xa3, 0x79, 0x8f, 0xf7, 0x9b, 0xdd, 0x7d, 0xa0, 0x81, 0xa9, 0x9b,
0x4a, 0x2e, 0xfa, 0xb9, 0x70, 0xe8, 0x93, 0x80, 0xa8, 0x5a, 0xc5, 0x0c, 0x8a, 0x92, 0xb8, 0xa5,
0x3f, 0x6b, 0x60, 0xa1, 0x6f, 0x19, 0x66, 0x0f, 0x56, 0x6c, 0x59, 0xee, 0x91, 0x18, 0xe8, 0x24,
0xa6, 0xa5, 0xeb, 0x9c, 0x8a, 0x24, 0x37, 0xe1, 0xbd, 0xcc, 0xe7, 0xe5, 0xbd, 0xd2, 0xdf, 0x34,
0xb0, 0x74, 0xaf, 0x48, 0x7c, 0x28, 0x47, 0xba, 0x0a, 0xf2, 0xb2, 0x85, 0x3a, 0xe1, 0xc7, 0x29,
0x5f, 0x0d, 0xb2, 0x68, 0xf0, 0xff, 0x90, 0x11, 0x7f, 0x95, 0xde, 0xd7, 0xc0, 0x5c, 0x8d, 0xf8,
0x2d, 0xd3, 0x20, 0x88, 0x34, 0x88, 0x4f, 0x1c, 0x83, 0xc0, 0x35, 0x30, 0xc9, 0x7f, 0xa7, 0xf3,
0xb0, 0x11, 0x0d, 0xb1, 0xe7, 0xa5, 0xcb, 0x27, 0x77, 0x22, 0x06, 0x8a, 0x65, 0xd4, 0xc0, 0x3b,
0x33, 0x70, 0xe0, 0xbd, 0x04, 0xc6, 0xbc, 0x78, 0x1c, 0x98, 0x67, 0x5c, 0x3e, 0x01, 0xe4, 0xd4,
0xd2, 0xdf, 0x35, 0xd0, 0xef, 0xbf, 0x55, 0x60, 0x0b, 0x4c, 0x50, 0x61, 0x9c, 0x74, 0xde, 0xee,
0x03, 0x3a, 0x2f, 0xbd, 0x55, 0x71, 0x4d, 0x44, 0xd4, 0x08, 0x8c, 0xf9, 0xcf, 0xc0, 0x95, 0xd0,
0xa9, 0xcb, 0x01, 0xde, 0xb4, 0xf0, 0x5f, 0x75, 0x5d, 0xd0, 0x90, 0xe2, 0xc2, 0x4b, 0x62, 0xd4,
0x94, 0x98, 0xdf, 0x44, 0x63, 0xa6, 0xca, 0x95, 0x3b, 0x77, 0x0b, 0xe7, 0x3e, 0xbe, 0x5b, 0x38,
0xf7, 0xc9, 0xdd, 0xc2, 0xb9, 0xef, 0x76, 0x0a, 0xda, 0x9d, 0x4e, 0x41, 0xfb, 0xb8, 0x53, 0xd0,
0x3e, 0xe9, 0x14, 0xb4, 0x7f, 0x75, 0x0a, 0xda, 0xcf, 0x3e, 0x2d, 0x9c, 0xfb, 0xe6, 0x84, 0x34,
0xed, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x16, 0xda, 0x75, 0x14, 0x43, 0x2a, 0x00, 0x00,
}

View File

@ -113,6 +113,16 @@ message CustomResourceConversion {
// alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
optional WebhookClientConfig webhookClientConfig = 2;
// ConversionReviewVersions is an ordered list of preferred `ConversionReview`
// 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, conversion will fail for this object.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
// Default to `['v1beta1']`.
// +optional
repeated string conversionReviewVersions = 3;
}
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format

View File

@ -91,6 +91,16 @@ type CustomResourceConversion struct {
// alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
WebhookClientConfig *WebhookClientConfig `json:"webhookClientConfig,omitempty" protobuf:"bytes,2,name=webhookClientConfig"`
// ConversionReviewVersions is an ordered list of preferred `ConversionReview`
// 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, conversion will fail for this object.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
// Default to `['v1beta1']`.
// +optional
ConversionReviewVersions []string `json:"conversionReviewVersions,omitempty" protobuf:"bytes,3,rep,name=conversionReviewVersions"`
}
// WebhookClientConfig contains the information to make a TLS

View File

@ -296,6 +296,7 @@ func Convert_apiextensions_CustomResourceColumnDefinition_To_v1beta1_CustomResou
func autoConvert_v1beta1_CustomResourceConversion_To_apiextensions_CustomResourceConversion(in *CustomResourceConversion, out *apiextensions.CustomResourceConversion, s conversion.Scope) error {
out.Strategy = apiextensions.ConversionStrategyType(in.Strategy)
out.WebhookClientConfig = (*apiextensions.WebhookClientConfig)(unsafe.Pointer(in.WebhookClientConfig))
out.ConversionReviewVersions = *(*[]string)(unsafe.Pointer(&in.ConversionReviewVersions))
return nil
}
@ -307,6 +308,7 @@ func Convert_v1beta1_CustomResourceConversion_To_apiextensions_CustomResourceCon
func autoConvert_apiextensions_CustomResourceConversion_To_v1beta1_CustomResourceConversion(in *apiextensions.CustomResourceConversion, out *CustomResourceConversion, s conversion.Scope) error {
out.Strategy = ConversionStrategyType(in.Strategy)
out.WebhookClientConfig = (*WebhookClientConfig)(unsafe.Pointer(in.WebhookClientConfig))
out.ConversionReviewVersions = *(*[]string)(unsafe.Pointer(&in.ConversionReviewVersions))
return nil
}

View File

@ -130,6 +130,11 @@ func (in *CustomResourceConversion) DeepCopyInto(out *CustomResourceConversion)
*out = new(WebhookClientConfig)
(*in).DeepCopyInto(*out)
}
if in.ConversionReviewVersions != nil {
in, out := &in.ConversionReviewVersions, &out.ConversionReviewVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -13,6 +13,7 @@ go_library(
importpath = "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation",
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",

View File

@ -24,12 +24,14 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality"
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/sets"
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
validationutil "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
)
@ -113,6 +115,10 @@ func ValidateCustomResourceDefinitionVersion(version *apiextensions.CustomResour
// ValidateCustomResourceDefinitionSpec statically validates
func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefinitionSpec, fldPath *field.Path) field.ErrorList {
return validateCustomResourceDefinitionSpec(spec, true, fldPath)
}
func validateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefinitionSpec, requireRecognizedVersion bool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(spec.Group) == 0 {
@ -205,7 +211,7 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
}
}
allErrs = append(allErrs, ValidateCustomResourceConversion(spec.Conversion, fldPath.Child("conversion"))...)
allErrs = append(allErrs, validateCustomResourceConversion(spec.Conversion, requireRecognizedVersion, fldPath.Child("conversion"))...)
return allErrs
}
@ -225,8 +231,66 @@ func validateEnumStrings(fldPath *field.Path, value string, accepted []string, r
return field.ErrorList{field.NotSupported(fldPath, value, accepted)}
}
var acceptedConversionReviewVersion = []string{v1beta1.SchemeGroupVersion.Version}
func isAcceptedConversionReviewVersion(v string) bool {
for _, version := range acceptedConversionReviewVersion {
if v == version {
return true
}
}
return false
}
func validateConversionReviewVersions(versions []string, requireRecognizedVersion bool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(versions) < 1 {
allErrs = append(allErrs, field.Required(fldPath, ""))
} else {
seen := map[string]bool{}
hasAcceptedVersion := false
for i, v := range versions {
if seen[v] {
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), v, "duplicate version"))
continue
}
seen[v] = true
for _, errString := range utilvalidation.IsDNS1035Label(v) {
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), v, errString))
}
if isAcceptedConversionReviewVersion(v) {
hasAcceptedVersion = true
}
}
if requireRecognizedVersion && !hasAcceptedVersion {
allErrs = append(allErrs, field.Invalid(
fldPath, versions,
fmt.Sprintf("none of the versions accepted by this server. accepted version(s) are %v",
strings.Join(acceptedConversionReviewVersion, ", "))))
}
}
return allErrs
}
// hasValidConversionReviewVersion return true if there is a valid version or if the list is empty.
func hasValidConversionReviewVersionOrEmpty(versions []string) bool {
if len(versions) < 1 {
return true
}
for _, v := range versions {
if isAcceptedConversionReviewVersion(v) {
return true
}
}
return false
}
// ValidateCustomResourceConversion statically validates
func ValidateCustomResourceConversion(conversion *apiextensions.CustomResourceConversion, fldPath *field.Path) field.ErrorList {
return validateCustomResourceConversion(conversion, true, fldPath)
}
func validateCustomResourceConversion(conversion *apiextensions.CustomResourceConversion, requireRecognizedVersion bool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if conversion == nil {
return allErrs
@ -250,15 +314,22 @@ func ValidateCustomResourceConversion(conversion *apiextensions.CustomResourceCo
allErrs = append(allErrs, webhook.ValidateWebhookService(fldPath.Child("webhookClientConfig").Child("service"), cc.Service.Name, cc.Service.Namespace, cc.Service.Path)...)
}
}
} else if conversion.WebhookClientConfig != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("webhookClientConfig"), "should not be set when strategy is not set to Webhook"))
allErrs = append(allErrs, validateConversionReviewVersions(conversion.ConversionReviewVersions, requireRecognizedVersion, fldPath.Child("conversionReviewVersions"))...)
} else {
if conversion.WebhookClientConfig != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("webhookClientConfig"), "should not be set when strategy is not set to Webhook"))
}
if len(conversion.ConversionReviewVersions) > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("conversionReviewVersions"), "should not be set when strategy is not set to Webhook"))
}
}
return allErrs
}
// ValidateCustomResourceDefinitionSpecUpdate statically validates
func ValidateCustomResourceDefinitionSpecUpdate(spec, oldSpec *apiextensions.CustomResourceDefinitionSpec, established bool, fldPath *field.Path) field.ErrorList {
allErrs := ValidateCustomResourceDefinitionSpec(spec, fldPath)
requireRecognizedVersion := oldSpec.Conversion == nil || hasValidConversionReviewVersionOrEmpty(oldSpec.Conversion.ConversionReviewVersions)
allErrs := validateCustomResourceDefinitionSpec(spec, requireRecognizedVersion, fldPath)
if established {
// these effect the storage and cannot be changed therefore

View File

@ -35,6 +35,9 @@ func required(path ...string) validationMatch {
func invalid(path ...string) validationMatch {
return validationMatch{path: field.NewPath(path[0], path[1:]...), errorType: field.ErrorTypeInvalid}
}
func invalidIndex(index int, path ...string) validationMatch {
return validationMatch{path: field.NewPath(path[0], path[1:]...).Index(index), errorType: field.ErrorTypeInvalid}
}
func unsupported(path ...string) validationMatch {
return validationMatch{path: field.NewPath(path[0], path[1:]...), errorType: field.ErrorTypeNotSupported}
}
@ -65,7 +68,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
errors []validationMatch
}{
{
name: "webhookconfig: blank URL",
name: "webhookconfig: both service and URL provided",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
@ -109,7 +112,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
},
},
{
name: "webhookconfig: both service and URL provided",
name: "webhookconfig: blank URL",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
@ -189,6 +192,207 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
forbidden("spec", "conversion", "webhookClientConfig"),
},
},
{
name: "ConversionReviewVersions_should_not_be_set",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("None"),
ConversionReviewVersions: []string{"v1beta1"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
forbidden("spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "webhookconfig: invalid ConversionReviewVersion",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalid("spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "webhookconfig: invalid ConversionReviewVersion version string",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"0v"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalidIndex(0, "spec", "conversion", "conversionReviewVersions"),
invalid("spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "webhookconfig: at least one valid ConversionReviewVersion",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version", "v1beta1"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{},
},
{
name: "webhookconfig: duplicate ConversionReviewVersion",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"v1beta1", "v1beta1"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalidIndex(1, "spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "missing_webhookconfig",
resource: &apiextensions.CustomResourceDefinition{
@ -646,6 +850,10 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
}
for _, tc := range tests {
// duplicate defaulting behaviour
if tc.resource.Spec.Conversion != nil && tc.resource.Spec.Conversion.Strategy == apiextensions.WebhookConverter && len(tc.resource.Spec.Conversion.ConversionReviewVersions) == 0 {
tc.resource.Spec.Conversion.ConversionReviewVersions = []string{"v1beta1"}
}
errs := ValidateCustomResourceDefinition(tc.resource)
seenErrs := make([]bool, len(errs))
@ -679,6 +887,231 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
resource *apiextensions.CustomResourceDefinition
errors []validationMatch
}{
{
name: "webhookconfig: should pass on invalid ConversionReviewVersion with old invalid versions",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
old: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version_0, invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{},
},
{
name: "webhookconfig: should fail on invalid ConversionReviewVersion with old valid versions",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
old: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"v1beta1", "invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalid("spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "webhookconfig: should fail on invalid ConversionReviewVersion with missing old versions",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
ConversionReviewVersions: []string{"invalid-version"},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
old: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com", ResourceVersion: "42"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Scope: apiextensions.ResourceScope("Cluster"),
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Conversion: &apiextensions.CustomResourceConversion{
Strategy: apiextensions.ConversionStrategyType("Webhook"),
WebhookClientConfig: &apiextensions.WebhookClientConfig{
URL: strPtr("https://example.com/webhook"),
},
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalid("spec", "conversion", "conversionReviewVersions"),
},
},
{
name: "unchanged",
old: &apiextensions.CustomResourceDefinition{

View File

@ -48,6 +48,11 @@ func (in *CustomResourceConversion) DeepCopyInto(out *CustomResourceConversion)
*out = new(WebhookClientConfig)
(*in).DeepCopyInto(*out)
}
if in.ConversionReviewVersions != nil {
in, out := &in.ConversionReviewVersions, &out.ConversionReviewVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -60,6 +60,8 @@ type webhookConverter struct {
restClient *rest.RESTClient
name string
nopConverter nopConverter
conversionReviewVersions []string
}
func webhookClientConfigForCRD(crd *internal.CustomResourceDefinition) *webhook.ClientConfig {
@ -96,6 +98,8 @@ func (f *webhookConverterFactory) NewWebhookConverter(validVersions map[schema.G
restClient: restClient,
name: crd.Name,
nopConverter: nopConverter{validVersions: validVersions},
conversionReviewVersions: crd.Spec.Conversion.ConversionReviewVersions,
}, nil
}
@ -136,6 +140,16 @@ func (c *webhookConverter) Convert(in, out, context interface{}) error {
return nil
}
// hasConversionReviewVersion check whether a version is accepted by a given webhook.
func (c *webhookConverter) hasConversionReviewVersion(v string) bool {
for _, b := range c.conversionReviewVersions {
if b == v {
return true
}
}
return false
}
func createConversionReview(obj runtime.Object, apiVersion string) *v1beta1.ConversionReview {
listObj, isList := obj.(*unstructured.UnstructuredList)
var objects []runtime.RawExtension
@ -216,6 +230,12 @@ func (c *webhookConverter) ConvertToVersion(in runtime.Object, target runtime.Gr
}
}
// Currently converter only supports `v1beta1` ConversionReview
// TODO: Make CRD webhooks caller capable of sending/receiving multiple ConversionReview versions
if !c.hasConversionReviewVersion(v1beta1.SchemeGroupVersion.Version) {
return nil, fmt.Errorf("webhook does not accept v1beta1 ConversionReview")
}
request := createConversionReview(in, toGV.String())
if len(request.Request.Objects) == 0 {
if !isList {

View File

@ -94,6 +94,12 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
}
}
// Currently dispatcher only supports `v1beta1` AdmissionReview
// TODO: Make the dispatcher capable of sending multiple AdmissionReview versions
if !util.HasAdmissionReviewVersion(v1beta1.SchemeGroupVersion.Version, h) {
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("webhook does not accept v1beta1 AdmissionReview")}
}
// Make the webhook request
request := request.CreateAdmissionReview(attr)
client, err := a.cm.HookClient(util.HookClientConfigForWebhook(h))

View File

@ -211,17 +211,19 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
Rules: []registrationv1beta1.RuleWithOperations{{
Operations: []registrationv1beta1.OperationType{registrationv1beta1.Create},
}},
NamespaceSelector: &metav1.LabelSelector{},
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
},
{
Name: "match & allow",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow.example.com",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "allow.example.com",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"},
@ -229,20 +231,22 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match & disallow",
Webhooks: []registrationv1beta1.Webhook{{
Name: "disallow",
ClientConfig: ccfgSVC("disallow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "disallow",
ClientConfig: ccfgSVC("disallow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ErrorContains: "without explanation",
},
{
Name: "match & disallow ii",
Webhooks: []registrationv1beta1.Webhook{{
Name: "disallowReason",
ClientConfig: ccfgSVC("disallowReason"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "disallowReason",
ClientConfig: ccfgSVC("disallowReason"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ErrorContains: "you shall not pass",
@ -260,6 +264,7 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
Operator: metav1.LabelSelectorOpIn,
}},
},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
@ -277,29 +282,33 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
Operator: metav1.LabelSelectorOpNotIn,
}},
},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
},
{
Name: "match & fail (but allow because fail open)",
Webhooks: []registrationv1beta1.Webhook{{
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
@ -307,53 +316,60 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match & fail (but disallow because fail close on nil FailurePolicy)",
Webhooks: []registrationv1beta1.Webhook{{
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
NamespaceSelector: &metav1.LabelSelector{},
Rules: matchEverythingRules,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: false,
},
{
Name: "match & fail (but fail because fail closed)",
Webhooks: []registrationv1beta1.Webhook{{
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
Name: "internalErr A",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
Name: "internalErr B",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
AdmissionReviewVersions: []string{"v1beta1"},
}, {
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
Name: "internalErr C",
ClientConfig: ccfgSVC("internalErr"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyFail,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: false,
},
{
Name: "match & allow (url)",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow.example.com",
ClientConfig: ccfgURL("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "allow.example.com",
ClientConfig: ccfgURL("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"},
@ -361,31 +377,34 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match & disallow (url)",
Webhooks: []registrationv1beta1.Webhook{{
Name: "disallow",
ClientConfig: ccfgURL("disallow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "disallow",
ClientConfig: ccfgURL("disallow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ErrorContains: "without explanation",
}, {
Name: "absent response and fail open",
Webhooks: []registrationv1beta1.Webhook{{
Name: "nilResponse",
ClientConfig: ccfgURL("nilResponse"),
FailurePolicy: &policyIgnore,
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "nilResponse",
ClientConfig: ccfgURL("nilResponse"),
FailurePolicy: &policyIgnore,
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
},
{
Name: "absent response and fail closed",
Webhooks: []registrationv1beta1.Webhook{{
Name: "nilResponse",
ClientConfig: ccfgURL("nilResponse"),
FailurePolicy: &policyFail,
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "nilResponse",
ClientConfig: ccfgURL("nilResponse"),
FailurePolicy: &policyFail,
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ErrorContains: "Webhook response was absent",
},
@ -397,8 +416,9 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
Rules: []registrationv1beta1.RuleWithOperations{{
Operations: []registrationv1beta1.OperationType{registrationv1beta1.Create},
}},
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsSome,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsSome,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ExpectAllow: true,
@ -406,11 +426,12 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match dry run side effects Unknown",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsUnknown,
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsUnknown,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ErrorContains: "does not support dry run",
@ -418,11 +439,12 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match dry run side effects None",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsNone,
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsNone,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ExpectAllow: true,
@ -431,11 +453,12 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match dry run side effects Some",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsSome,
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsSome,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ErrorContains: "does not support dry run",
@ -443,11 +466,12 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "match dry run side effects NoneOnDryRun",
Webhooks: []registrationv1beta1.Webhook{{
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsNoneOnDryRun,
Name: "allow",
ClientConfig: ccfgSVC("allow"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsNoneOnDryRun,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ExpectAllow: true,
@ -456,10 +480,11 @@ func NewNonMutatingTestCases(url *url.URL) []Test {
{
Name: "illegal annotation format",
Webhooks: []registrationv1beta1.Webhook{{
Name: "invalidAnnotation",
ClientConfig: ccfgURL("invalidAnnotation"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "invalidAnnotation",
ClientConfig: ccfgURL("invalidAnnotation"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
},
@ -476,10 +501,11 @@ func NewMutatingTestCases(url *url.URL) []Test {
{
Name: "match & remove label",
Webhooks: []registrationv1beta1.Webhook{{
Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
AdditionalLabels: map[string]string{"remove": "me"},
@ -489,10 +515,11 @@ func NewMutatingTestCases(url *url.URL) []Test {
{
Name: "match & add label",
Webhooks: []registrationv1beta1.Webhook{{
Name: "addLabel",
ClientConfig: ccfgSVC("addLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "addLabel",
ClientConfig: ccfgSVC("addLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectLabels: map[string]string{"pod.name": "my-pod", "added": "test"},
@ -500,10 +527,11 @@ func NewMutatingTestCases(url *url.URL) []Test {
{
Name: "match CRD & add label",
Webhooks: []registrationv1beta1.Webhook{{
Name: "addLabel",
ClientConfig: ccfgSVC("addLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "addLabel",
ClientConfig: ccfgSVC("addLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsCRD: true,
ExpectAllow: true,
@ -512,10 +540,11 @@ func NewMutatingTestCases(url *url.URL) []Test {
{
Name: "match CRD & remove label",
Webhooks: []registrationv1beta1.Webhook{{
Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "removelabel.example.com",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsCRD: true,
ExpectAllow: true,
@ -526,21 +555,23 @@ func NewMutatingTestCases(url *url.URL) []Test {
{
Name: "match & invalid mutation",
Webhooks: []registrationv1beta1.Webhook{{
Name: "invalidMutation",
ClientConfig: ccfgSVC("invalidMutation"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
Name: "invalidMutation",
ClientConfig: ccfgSVC("invalidMutation"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
AdmissionReviewVersions: []string{"v1beta1"},
}},
ErrorContains: "invalid character",
},
{
Name: "match & remove label dry run unsupported",
Webhooks: []registrationv1beta1.Webhook{{
Name: "removeLabel",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsUnknown,
Name: "removeLabel",
ClientConfig: ccfgSVC("removeLabel"),
Rules: matchEverythingRules,
NamespaceSelector: &metav1.LabelSelector{},
SideEffects: &sideEffectsUnknown,
AdmissionReviewVersions: []string{"v1beta1"},
}},
IsDryRun: true,
ErrorContains: "does not support dry run",
@ -567,11 +598,12 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest {
{
Name: "uncached: service webhook, path 'allow'",
Webhooks: []registrationv1beta1.Webhook{{
Name: "cache1",
ClientConfig: ccfgSVC("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "cache1",
ClientConfig: ccfgSVC("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectCacheMiss: true,
@ -579,11 +611,12 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest {
{
Name: "uncached: service webhook, path 'internalErr'",
Webhooks: []registrationv1beta1.Webhook{{
Name: "cache2",
ClientConfig: ccfgSVC("internalErr"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "cache2",
ClientConfig: ccfgSVC("internalErr"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectCacheMiss: true,
@ -591,11 +624,12 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest {
{
Name: "cached: service webhook, path 'allow'",
Webhooks: []registrationv1beta1.Webhook{{
Name: "cache3",
ClientConfig: ccfgSVC("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "cache3",
ClientConfig: ccfgSVC("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectCacheMiss: false,
@ -603,11 +637,12 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest {
{
Name: "uncached: url webhook, path 'allow'",
Webhooks: []registrationv1beta1.Webhook{{
Name: "cache4",
ClientConfig: ccfgURL("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "cache4",
ClientConfig: ccfgURL("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectCacheMiss: true,
@ -615,11 +650,12 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest {
{
Name: "cached: service webhook, path 'allow'",
Webhooks: []registrationv1beta1.Webhook{{
Name: "cache5",
ClientConfig: ccfgURL("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
Name: "cache5",
ClientConfig: ccfgURL("allow"),
Rules: newMatchEverythingRules(),
NamespaceSelector: &metav1.LabelSelector{},
FailurePolicy: &policyIgnore,
AdmissionReviewVersions: []string{"v1beta1"},
}},
ExpectAllow: true,
ExpectCacheMiss: false,

View File

@ -40,3 +40,13 @@ func HookClientConfigForWebhook(w *v1beta1.Webhook) webhook.ClientConfig {
}
return ret
}
// HasAdmissionReviewVersion check whether a version is accepted by a given webhook.
func HasAdmissionReviewVersion(a string, w *v1beta1.Webhook) bool {
for _, b := range w.AdmissionReviewVersions {
if b == a {
return true
}
}
return false
}

View File

@ -108,6 +108,12 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook,
}
}
// Currently dispatcher only supports `v1beta1` AdmissionReview
// TODO: Make the dispatcher capable of sending multiple AdmissionReview versions
if !util.HasAdmissionReviewVersion(v1beta1.SchemeGroupVersion.Version, h) {
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("webhook does not accept v1beta1 AdmissionReviewRequest")}
}
// Make the webhook request
request := request.CreateAdmissionReview(attr)
client, err := d.cm.HookClient(util.HookClientConfigForWebhook(h))