wire up the webhook rejection metrics in webhook handlers

Kubernetes-commit: 620f5f2c587971be50cb27bb2a2d35209b3dc058
This commit is contained in:
Haowei Cai 2019-08-28 17:32:07 -07:00 committed by Kubernetes Publisher
parent 466e192e26
commit 8d86fef522
3 changed files with 44 additions and 9 deletions

View File

@ -136,10 +136,18 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore
rejected := false rejected := false
if err != nil { if err != nil {
// ErrCallingWebhook is ignored if the webhook is configured to failopen. switch err := err.(type) {
// Otherwise the request is rejected. case *webhookutil.ErrCallingWebhook:
if _, ok := err.(*webhookutil.ErrCallingWebhook); !ok || !ignoreClientCallFailures { if !ignoreClientCallFailures {
rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0)
}
case *webhookutil.ErrWebhookRejection:
rejected = true rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
default:
rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
} }
} }
admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "admit", hook.Name) admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "admit", hook.Name)
@ -172,6 +180,9 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
klog.Warningf("Failed calling webhook, failing closed %v: %v", hook.Name, err) klog.Warningf("Failed calling webhook, failing closed %v: %v", hook.Name, err)
return apierrors.NewInternalError(err) return apierrors.NewInternalError(err)
} }
if rejectionErr, ok := err.(*webhookutil.ErrWebhookRejection); ok {
return rejectionErr.Status
}
return err return err
} }
@ -257,7 +268,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
} }
if !result.Allowed { if !result.Allowed {
return false, webhookerrors.ToStatusErr(h.Name, result.Result) return false, &webhookutil.ErrWebhookRejection{Status: webhookerrors.ToStatusErr(h.Name, result.Result)}
} }
if len(result.Patch) == 0 { if len(result.Patch) == 0 {

View File

@ -104,10 +104,18 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore
rejected := false rejected := false
if err != nil { if err != nil {
// ErrCallingWebhook is ignored if the webhook is configured to failopen. switch err := err.(type) {
// Otherwise the request is rejected. case *webhookutil.ErrCallingWebhook:
if _, ok := err.(*webhookutil.ErrCallingWebhook); !ok || !ignoreClientCallFailures { if !ignoreClientCallFailures {
rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0)
}
case *webhookutil.ErrWebhookRejection:
rejected = true rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
default:
rejected = true
admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
} }
} }
admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "validating", hook.Name) admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "validating", hook.Name)
@ -127,6 +135,9 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
return return
} }
if rejectionErr, ok := err.(*webhookutil.ErrWebhookRejection); ok {
err = rejectionErr.Status
}
klog.Warningf("rejected by webhook %q: %#v", hook.Name, err) klog.Warningf("rejected by webhook %q: %#v", hook.Name, err)
errCh <- err errCh <- err
}(relevantHooks[i]) }(relevantHooks[i])
@ -219,5 +230,5 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Validati
if result.Allowed { if result.Allowed {
return nil return nil
} }
return webhookerrors.ToStatusErr(h.Name, result.Result) return &webhookutil.ErrWebhookRejection{Status: webhookerrors.ToStatusErr(h.Name, result.Result)}
} }

View File

@ -16,7 +16,11 @@ limitations under the License.
package webhook package webhook
import "fmt" import (
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
// ErrCallingWebhook is returned for transport-layer errors calling webhooks. It // ErrCallingWebhook is returned for transport-layer errors calling webhooks. It
// represents a failure to talk to the webhook, not the webhook rejecting a // represents a failure to talk to the webhook, not the webhook rejecting a
@ -32,3 +36,12 @@ func (e *ErrCallingWebhook) Error() string {
} }
return fmt.Sprintf("failed calling webhook %q; no further details available", e.WebhookName) return fmt.Sprintf("failed calling webhook %q; no further details available", e.WebhookName)
} }
// ErrWebhookRejection represents a webhook properly rejecting a request.
type ErrWebhookRejection struct {
Status *apierrors.StatusError
}
func (e *ErrWebhookRejection) Error() string {
return e.Status.Error()
}