Merge pull request #74562 from roycaihw/feat/admission-webhook-timeout

admission webhook: timeout configuration
pull/564/head
Kubernetes Prow Robot 2019-02-26 23:40:44 -08:00 committed by GitHub
commit 218642e84e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 349 additions and 62 deletions

View File

@ -223,6 +223,11 @@
"sideEffects": {
"description": "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.",
"type": "string"
},
"timeoutSeconds": {
"description": "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.",
"format": "int32",
"type": "integer"
}
},
"required": [

View File

@ -32,6 +32,10 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
obj.FailurePolicy = &p
s := admissionregistration.SideEffectClassUnknown
obj.SideEffects = &s
if obj.TimeoutSeconds == nil {
i := int32(30)
obj.TimeoutSeconds = &i
}
},
}
}

View File

@ -208,6 +208,13 @@ type Webhook struct {
// sideEffects == Unknown or Some. Defaults to Unknown.
// +optional
SideEffects *SideEffectClass
// 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.
// +optional
TimeoutSeconds *int32
}
// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make

View File

@ -40,4 +40,8 @@ func SetDefaults_Webhook(obj *admissionregistrationv1beta1.Webhook) {
unknown := admissionregistrationv1beta1.SideEffectClassUnknown
obj.SideEffects = &unknown
}
if obj.TimeoutSeconds == nil {
obj.TimeoutSeconds = new(int32)
*obj.TimeoutSeconds = 30
}
}

View File

@ -301,6 +301,7 @@ func autoConvert_v1beta1_Webhook_To_admissionregistration_Webhook(in *v1beta1.We
out.FailurePolicy = (*admissionregistration.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy))
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
out.SideEffects = (*admissionregistration.SideEffectClass)(unsafe.Pointer(in.SideEffects))
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
return nil
}
@ -318,6 +319,7 @@ func autoConvert_admissionregistration_Webhook_To_v1beta1_Webhook(in *admissionr
out.FailurePolicy = (*v1beta1.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy))
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
out.SideEffects = (*v1beta1.SideEffectClass)(unsafe.Pointer(in.SideEffects))
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
return nil
}

View File

@ -171,6 +171,9 @@ func validateWebhook(hook *admissionregistration.Webhook, fldPath *field.Path) f
if hook.SideEffects != nil && !supportedSideEffectClasses.Has(string(*hook.SideEffects)) {
allErrors = append(allErrors, field.NotSupported(fldPath.Child("sideEffects"), *hook.SideEffects, supportedSideEffectClasses.List()))
}
if hook.TimeoutSeconds != nil && (*hook.TimeoutSeconds > 30 || *hook.TimeoutSeconds < 1) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("timeoutSeconds"), *hook.TimeoutSeconds, "the timeout value must be between 1 and 30 seconds"))
}
if hook.NamespaceSelector != nil {
allErrors = append(allErrors, metav1validation.ValidateLabelSelector(hook.NamespaceSelector, fldPath.Child("namespaceSelector"))...)

View File

@ -26,6 +26,8 @@ import (
func strPtr(s string) *string { return &s }
func int32Ptr(i int32) *int32 { return &i }
func newValidatingWebhookConfiguration(hooks []admissionregistration.Webhook) *admissionregistration.ValidatingWebhookConfiguration {
return &admissionregistration.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
@ -544,6 +546,63 @@ func TestValidateValidatingWebhookConfiguration(t *testing.T) {
}),
expectedError: `clientConfig.service.path: Invalid value: "/apis/foo.bar/v1alpha1/--bad": segment[3]: a DNS-1123 subdomain`,
},
{
name: "timeout seconds cannot be greater than 30",
config: newValidatingWebhookConfiguration(
[]admissionregistration.Webhook{
{
Name: "webhook.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(31),
},
}),
expectedError: `webhooks[0].timeoutSeconds: Invalid value: 31: the timeout value must be between 1 and 30 seconds`,
},
{
name: "timeout seconds cannot be smaller than 1",
config: newValidatingWebhookConfiguration(
[]admissionregistration.Webhook{
{
Name: "webhook.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(0),
},
}),
expectedError: `webhooks[0].timeoutSeconds: Invalid value: 0: the timeout value must be between 1 and 30 seconds`,
},
{
name: "timeout seconds must be positive",
config: newValidatingWebhookConfiguration(
[]admissionregistration.Webhook{
{
Name: "webhook.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(-1),
},
}),
expectedError: `webhooks[0].timeoutSeconds: Invalid value: -1: the timeout value must be between 1 and 30 seconds`,
},
{
name: "valid timeout seconds",
config: newValidatingWebhookConfiguration(
[]admissionregistration.Webhook{
{
Name: "webhook.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(1),
},
{
Name: "webhook2.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(15),
},
{
Name: "webhook3.k8s.io",
ClientConfig: validClientConfig,
TimeoutSeconds: int32Ptr(30),
},
}),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

View File

@ -257,6 +257,11 @@ func (in *Webhook) DeepCopyInto(out *Webhook) {
*out = new(SideEffectClass)
**out = **in
}
if in.TimeoutSeconds != nil {
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
*out = new(int32)
**out = **in
}
return
}

View File

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

View File

@ -217,6 +217,14 @@ message Webhook {
// sideEffects == Unknown or Some. Defaults to Unknown.
// +optional
optional string sideEffects = 6;
// 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.
// +optional
optional int32 timeoutSeconds = 7;
}
// WebhookClientConfig contains the information to make a TLS

View File

@ -216,6 +216,14 @@ type Webhook struct {
// sideEffects == Unknown or Some. Defaults to Unknown.
// +optional
SideEffects *SideEffectClass `json:"sideEffects,omitempty" protobuf:"bytes,6,opt,name=sideEffects,casttype=SideEffectClass"`
// 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.
// +optional
TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty" protobuf:"varint,7,opt,name=timeoutSeconds"`
}
// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make

View File

@ -106,6 +106,7 @@ var map_Webhook = map[string]string{
"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.",
}
func (Webhook) SwaggerDoc() map[string]string {

View File

@ -257,6 +257,11 @@ func (in *Webhook) DeepCopyInto(out *Webhook) {
*out = new(SideEffectClass)
**out = **in
}
if in.TimeoutSeconds != nil {
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
*out = new(int32)
**out = **in
}
return
}

View File

@ -101,7 +101,11 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
}
response := &admissionv1beta1.AdmissionReview{}
if err := client.Post().Context(ctx).Body(&request).Do().Into(response); err != nil {
r := client.Post().Context(ctx).Body(&request)
if h.TimeoutSeconds != nil {
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
}
if err := r.Do().Into(response); err != nil {
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
}

View File

@ -115,7 +115,11 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook,
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
}
response := &admissionv1beta1.AdmissionReview{}
if err := client.Post().Context(ctx).Body(&request).Do().Into(response); err != nil {
r := client.Post().Context(ctx).Body(&request)
if h.TimeoutSeconds != nil {
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
}
if err := r.Do().Into(response); err != nil {
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
}

View File

@ -64,6 +64,7 @@ const (
dummyValidatingWebhookConfigName = "e2e-test-dummy-validating-webhook-config"
dummyMutatingWebhookConfigName = "e2e-test-dummy-mutating-webhook-config"
crdWebhookConfigName = "e2e-test-webhook-config-crd"
slowWebhookConfigName = "e2e-test-webhook-config-slow"
skipNamespaceLabelKey = "skip-webhook-admission"
skipNamespaceLabelValue = "yes"
@ -201,6 +202,31 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
testCRDDenyWebhook(f)
})
It("Should honor timeout", func() {
policyFail := v1beta1.Fail
policyIgnore := v1beta1.Ignore
By("Setting timeout (1s) shorter than webhook latency (5s)")
slowWebhookCleanup := registerSlowWebhook(f, context, &policyFail, int32Ptr(1))
testSlowWebhookTimeoutFailEarly(f)
slowWebhookCleanup()
By("Having no error when timeout is shorter than webhook latency and failure policy is ignore")
slowWebhookCleanup = registerSlowWebhook(f, context, &policyIgnore, int32Ptr(1))
testSlowWebhookTimeoutNoError(f)
slowWebhookCleanup()
By("Having no error when timeout is longer than webhook latency")
slowWebhookCleanup = registerSlowWebhook(f, context, &policyFail, int32Ptr(10))
testSlowWebhookTimeoutNoError(f)
slowWebhookCleanup()
By("Having no error when timeout is empty (defaulted to 10s in v1beta1)")
slowWebhookCleanup = registerSlowWebhook(f, context, &policyFail, nil)
testSlowWebhookTimeoutNoError(f)
slowWebhookCleanup()
})
// TODO: add more e2e tests for mutating webhooks
// 1. mutating webhook that mutates pod
// 2. mutating webhook that sends empty patch
@ -357,6 +383,8 @@ func deployWebhookAndService(f *framework.Framework, image string, context *cert
func strPtr(s string) *string { return &s }
func int32Ptr(i int32) *int32 { return &i }
func registerWebhook(f *framework.Framework, context *certContext) func() {
client := f.ClientSet
By("Registering the webhook via the AdmissionRegistration API")
@ -1445,3 +1473,69 @@ func testCRDDenyWebhook(f *framework.Framework) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
}
func registerSlowWebhook(f *framework.Framework, context *certContext, policy *v1beta1.FailurePolicyType, timeout *int32) func() {
client := f.ClientSet
By("Registering slow webhook via the AdmissionRegistration API")
namespace := f.Namespace.Name
configName := slowWebhookConfigName
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&v1beta1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: configName,
},
Webhooks: []v1beta1.Webhook{
{
Name: "allow-configmap-with-delay-webhook.k8s.io",
Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create},
Rule: v1beta1.Rule{
APIGroups: []string{""},
APIVersions: []string{"v1"},
Resources: []string{"configmaps"},
},
}},
ClientConfig: v1beta1.WebhookClientConfig{
Service: &v1beta1.ServiceReference{
Namespace: namespace,
Name: serviceName,
Path: strPtr("/always-allow-delay-5s"),
},
CABundle: context.signingCert,
},
FailurePolicy: policy,
TimeoutSeconds: timeout,
},
},
})
framework.ExpectNoError(err, "registering slow webhook config %s with namespace %s", configName, namespace)
// The webhook configuration is honored in 10s.
time.Sleep(10 * time.Second)
return func() {
client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(configName, nil)
}
}
func testSlowWebhookTimeoutFailEarly(f *framework.Framework) {
By("Request fails when timeout (1s) is shorter than slow webhook latency (5s)")
client := f.ClientSet
name := "e2e-test-slow-webhook-configmap"
_, err := client.CoreV1().ConfigMaps(f.Namespace.Name).Create(&v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: name}})
Expect(err).To(HaveOccurred(), "create configmap in namespace %s should have timed-out reaching slow webhook", f.Namespace.Name)
expectedErrMsg := `/always-allow-delay-5s?timeout=1s: context deadline exceeded`
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
}
func testSlowWebhookTimeoutNoError(f *framework.Framework) {
client := f.ClientSet
name := "e2e-test-slow-webhook-configmap"
_, err := client.CoreV1().ConfigMaps(f.Namespace.Name).Create(&v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: name}})
Expect(err).To(BeNil())
err = client.CoreV1().ConfigMaps(f.Namespace.Name).Delete(name, &metav1.DeleteOptions{})
Expect(err).To(BeNil())
}

View File

@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"addlabel.go",
"alwaysallow.go",
"alwaysdeny.go",
"config.go",
"configmap.go",

View File

@ -1 +1 @@
1.13v1
1.14v1

View File

@ -0,0 +1,36 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"time"
"k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
)
// alwaysAllowDelayFiveSeconds sleeps for five seconds and allows all requests made to this function.
func alwaysAllowDelayFiveSeconds(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
klog.V(2).Info("always-allow-with-delay sleeping for 5 seconds")
time.Sleep(5 * time.Second)
klog.V(2).Info("calling always-allow")
reviewResponse := v1beta1.AdmissionResponse{}
reviewResponse.Allowed = true
reviewResponse.Result = &metav1.Status{Message: "this webhook allows all requests"}
return &reviewResponse
}

View File

@ -91,6 +91,10 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
}
}
func serveAlwaysAllowDelayFiveSeconds(w http.ResponseWriter, r *http.Request) {
serve(w, r, alwaysAllowDelayFiveSeconds)
}
func serveAlwaysDeny(w http.ResponseWriter, r *http.Request) {
serve(w, r, alwaysDeny)
}
@ -132,10 +136,12 @@ func serveCRD(w http.ResponseWriter, r *http.Request) {
}
func main() {
klog.InitFlags(nil)
var config Config
config.addFlags()
flag.Parse()
http.HandleFunc("/always-allow-delay-5s", serveAlwaysAllowDelayFiveSeconds)
http.HandleFunc("/always-deny", serveAlwaysDeny)
http.HandleFunc("/add-label", serveAddLabel)
http.HandleFunc("/pods", servePods)

View File

@ -93,7 +93,7 @@ var (
// Preconfigured image configs
var (
CRDConversionWebhook = Config{e2eRegistry, "crd-conversion-webhook", "1.13rev2"}
AdmissionWebhook = Config{e2eRegistry, "webhook", "1.13v1"}
AdmissionWebhook = Config{e2eRegistry, "webhook", "1.14v1"}
APIServer = Config{e2eRegistry, "sample-apiserver", "1.10"}
AppArmorLoader = Config{e2eRegistry, "apparmor-loader", "1.0"}
BusyBox = Config{dockerLibraryRegistry, "busybox", "1.29"}