mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #103162 from rmoriar1/rmoriar1-add-http-code-to-webhook-metric
Add a new webhook request total metric and add a 1.0s bucket boundary to the webhook latency metric
This commit is contained in:
commit
d7a06ede70
@ -46,7 +46,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// Use buckets ranging from 5 ms to 2.5 seconds (admission webhooks timeout at 30 seconds by default).
|
// Use buckets ranging from 5 ms to 2.5 seconds (admission webhooks timeout at 30 seconds by default).
|
||||||
latencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 2.5}
|
latencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 1.0, 2.5}
|
||||||
latencySummaryMaxAge = 5 * time.Hour
|
latencySummaryMaxAge = 5 * time.Hour
|
||||||
|
|
||||||
// Metrics provides access to all admission metrics.
|
// Metrics provides access to all admission metrics.
|
||||||
@ -119,6 +119,7 @@ type AdmissionMetrics struct {
|
|||||||
controller *metricSet
|
controller *metricSet
|
||||||
webhook *metricSet
|
webhook *metricSet
|
||||||
webhookRejection *metrics.CounterVec
|
webhookRejection *metrics.CounterVec
|
||||||
|
webhookRequest *metrics.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
// newAdmissionMetrics create a new AdmissionMetrics, configured with default metric names.
|
// newAdmissionMetrics create a new AdmissionMetrics, configured with default metric names.
|
||||||
@ -149,11 +150,22 @@ func newAdmissionMetrics() *AdmissionMetrics {
|
|||||||
},
|
},
|
||||||
[]string{"name", "type", "operation", "error_type", "rejection_code"})
|
[]string{"name", "type", "operation", "error_type", "rejection_code"})
|
||||||
|
|
||||||
|
webhookRequest := metrics.NewCounterVec(
|
||||||
|
&metrics.CounterOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "webhook_request_total",
|
||||||
|
Help: "Admission webhook request total, identified by name and broken out for each admission type (validating or mutating) and operation. Additional labels specify whether the request was rejected or not and an HTTP status code. Codes greater than 600 are truncated to 600, to keep the metrics cardinality bounded.",
|
||||||
|
StabilityLevel: metrics.ALPHA,
|
||||||
|
},
|
||||||
|
[]string{"name", "type", "operation", "code", "rejected"})
|
||||||
|
|
||||||
step.mustRegister()
|
step.mustRegister()
|
||||||
controller.mustRegister()
|
controller.mustRegister()
|
||||||
webhook.mustRegister()
|
webhook.mustRegister()
|
||||||
legacyregistry.MustRegister(webhookRejection)
|
legacyregistry.MustRegister(webhookRejection)
|
||||||
return &AdmissionMetrics{step: step, controller: controller, webhook: webhook, webhookRejection: webhookRejection}
|
legacyregistry.MustRegister(webhookRequest)
|
||||||
|
return &AdmissionMetrics{step: step, controller: controller, webhook: webhook, webhookRejection: webhookRejection, webhookRequest: webhookRequest}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AdmissionMetrics) reset() {
|
func (m *AdmissionMetrics) reset() {
|
||||||
@ -173,8 +185,13 @@ func (m *AdmissionMetrics) ObserveAdmissionController(ctx context.Context, elaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ObserveWebhook records admission related metrics for a admission webhook.
|
// ObserveWebhook records admission related metrics for a admission webhook.
|
||||||
func (m *AdmissionMetrics) ObserveWebhook(ctx context.Context, elapsed time.Duration, rejected bool, attr admission.Attributes, stepType string, extraLabels ...string) {
|
func (m *AdmissionMetrics) ObserveWebhook(ctx context.Context, name string, elapsed time.Duration, rejected bool, attr admission.Attributes, stepType string, code int) {
|
||||||
m.webhook.observe(ctx, elapsed, append(extraLabels, stepType, string(attr.GetOperation()), strconv.FormatBool(rejected))...)
|
// We truncate codes greater than 600 to keep the cardinality bounded.
|
||||||
|
if code > 600 {
|
||||||
|
code = 600
|
||||||
|
}
|
||||||
|
m.webhookRequest.WithContext(ctx).WithLabelValues(name, stepType, string(attr.GetOperation()), strconv.Itoa(code), strconv.FormatBool(rejected)).Inc()
|
||||||
|
m.webhook.observe(ctx, elapsed, name, stepType, string(attr.GetOperation()), strconv.FormatBool(rejected))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObserveWebhookRejection records admission related metrics for an admission webhook rejection.
|
// ObserveWebhookRejection records admission related metrics for an admission webhook rejection.
|
||||||
|
@ -83,21 +83,48 @@ func TestObserveAdmissionController(t *testing.T) {
|
|||||||
func TestObserveWebhook(t *testing.T) {
|
func TestObserveWebhook(t *testing.T) {
|
||||||
defer Metrics.reset()
|
defer Metrics.reset()
|
||||||
defer legacyregistry.Reset()
|
defer legacyregistry.Reset()
|
||||||
Metrics.ObserveWebhook(context.TODO(), 2*time.Second, false, attr, stepAdmit, "x")
|
Metrics.ObserveWebhook(context.TODO(), "x", 2*time.Second, false, attr, stepAdmit, 200)
|
||||||
wantLabels := map[string]string{
|
Metrics.ObserveWebhook(context.TODO(), "x", 2*time.Second, true, attr, stepValidate, 654)
|
||||||
|
wantLabelsCounterAdmit := map[string]string{
|
||||||
|
"name": "x",
|
||||||
|
"operation": string(admission.Create),
|
||||||
|
"type": "admit",
|
||||||
|
"code": "200",
|
||||||
|
"rejected": "false",
|
||||||
|
}
|
||||||
|
wantLabelsCounterValidate := map[string]string{
|
||||||
|
"name": "x",
|
||||||
|
"operation": string(admission.Create),
|
||||||
|
"type": "validate",
|
||||||
|
"code": "600",
|
||||||
|
"rejected": "true",
|
||||||
|
}
|
||||||
|
wantLabelsHistogramAdmit := map[string]string{
|
||||||
"name": "x",
|
"name": "x",
|
||||||
"operation": string(admission.Create),
|
"operation": string(admission.Create),
|
||||||
"type": "admit",
|
"type": "admit",
|
||||||
"rejected": "false",
|
"rejected": "false",
|
||||||
}
|
}
|
||||||
expectHistogramCountTotal(t, "apiserver_admission_webhook_admission_duration_seconds", wantLabels, 1)
|
wantLabelsHistogramValidate := map[string]string{
|
||||||
|
"name": "x",
|
||||||
|
"operation": string(admission.Create),
|
||||||
|
"type": "validate",
|
||||||
|
"rejected": "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
expectCounterValue(t, "apiserver_admission_webhook_request_total", wantLabelsCounterAdmit, 1)
|
||||||
|
expectCounterValue(t, "apiserver_admission_webhook_request_total", wantLabelsCounterValidate, 1)
|
||||||
|
|
||||||
|
expectHistogramCountTotal(t, "apiserver_admission_webhook_admission_duration_seconds", wantLabelsHistogramAdmit, 1)
|
||||||
|
expectHistogramCountTotal(t, "apiserver_admission_webhook_admission_duration_seconds", wantLabelsHistogramValidate, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestObserveWebhookRejection(t *testing.T) {
|
func TestObserveWebhookRejection(t *testing.T) {
|
||||||
Metrics.reset()
|
Metrics.reset()
|
||||||
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 500)
|
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 500)
|
||||||
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 654)
|
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 654)
|
||||||
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepValidate, string(admission.Update), WebhookRejectionCallingWebhookError, 0)
|
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepValidate, string(admission.Update), WebhookRejectionCallingWebhookError, 501)
|
||||||
|
Metrics.ObserveWebhookRejection(context.TODO(), "x", stepValidate, string(admission.Update), WebhookRejectionAPIServerInternalError, 0)
|
||||||
wantLabels := map[string]string{
|
wantLabels := map[string]string{
|
||||||
"name": "x",
|
"name": "x",
|
||||||
"operation": string(admission.Create),
|
"operation": string(admission.Create),
|
||||||
@ -117,11 +144,19 @@ func TestObserveWebhookRejection(t *testing.T) {
|
|||||||
"operation": string(admission.Update),
|
"operation": string(admission.Update),
|
||||||
"type": "validate",
|
"type": "validate",
|
||||||
"error_type": "calling_webhook_error",
|
"error_type": "calling_webhook_error",
|
||||||
|
"rejection_code": "501",
|
||||||
|
}
|
||||||
|
wantLabelsAPIServerInternalError := map[string]string{
|
||||||
|
"name": "x",
|
||||||
|
"operation": string(admission.Update),
|
||||||
|
"type": "validate",
|
||||||
|
"error_type": "apiserver_internal_error",
|
||||||
"rejection_code": "0",
|
"rejection_code": "0",
|
||||||
}
|
}
|
||||||
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels, 1)
|
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels, 1)
|
||||||
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels600, 1)
|
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels600, 1)
|
||||||
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabelsCallingWebhookError, 1)
|
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabelsCallingWebhookError, 1)
|
||||||
|
expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabelsAPIServerInternalError, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithMetrics(t *testing.T) {
|
func TestWithMetrics(t *testing.T) {
|
||||||
|
@ -148,17 +148,21 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
|
|||||||
case *webhookutil.ErrCallingWebhook:
|
case *webhookutil.ErrCallingWebhook:
|
||||||
if !ignoreClientCallFailures {
|
if !ignoreClientCallFailures {
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0)
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, int(err.Status.ErrStatus.Code))
|
||||||
}
|
}
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "admit", int(err.Status.ErrStatus.Code))
|
||||||
case *webhookutil.ErrWebhookRejection:
|
case *webhookutil.ErrWebhookRejection:
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "admit", int(err.Status.ErrStatus.Code))
|
||||||
default:
|
default:
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "admit", 0)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "admit", 200)
|
||||||
}
|
}
|
||||||
admissionmetrics.Metrics.ObserveWebhook(ctx, time.Since(t), rejected, versionedAttr.Attributes, "admit", hook.Name)
|
|
||||||
if changed {
|
if changed {
|
||||||
// Patch had changed the object. Prepare to reinvoke all previous webhooks that are eligible for re-invocation.
|
// Patch had changed the object. Prepare to reinvoke all previous webhooks that are eligible for re-invocation.
|
||||||
webhookReinvokeCtx.RequireReinvokingPreviouslyInvokedPlugins()
|
webhookReinvokeCtx.RequireReinvokingPreviouslyInvokedPlugins()
|
||||||
@ -213,7 +217,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
|
|||||||
defer func() { annotator.addMutationAnnotation(changed) }()
|
defer func() { annotator.addMutationAnnotation(changed) }()
|
||||||
if attr.Attributes.IsDryRun() {
|
if attr.Attributes.IsDryRun() {
|
||||||
if h.SideEffects == nil {
|
if h.SideEffects == nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil"), Status: apierrors.NewBadRequest("Webhook SideEffects is nil")}
|
||||||
}
|
}
|
||||||
if !(*h.SideEffects == admissionregistrationv1.SideEffectClassNone || *h.SideEffects == admissionregistrationv1.SideEffectClassNoneOnDryRun) {
|
if !(*h.SideEffects == admissionregistrationv1.SideEffectClassNone || *h.SideEffects == admissionregistrationv1.SideEffectClassNoneOnDryRun) {
|
||||||
return false, webhookerrors.NewDryRunUnsupportedErr(h.Name)
|
return false, webhookerrors.NewDryRunUnsupportedErr(h.Name)
|
||||||
@ -222,12 +226,12 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
|
|||||||
|
|
||||||
uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation)
|
uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not create admission objects: %w", err)}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not create admission objects: %w", err), Status: apierrors.NewBadRequest("error creating admission objects")}
|
||||||
}
|
}
|
||||||
// Make the webhook request
|
// Make the webhook request
|
||||||
client, err := invocation.Webhook.GetRESTClient(a.cm)
|
client, err := invocation.Webhook.GetRESTClient(a.cm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not get REST client: %w", err)}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not get REST client: %w", err), Status: apierrors.NewBadRequest("error getting REST client")}
|
||||||
}
|
}
|
||||||
trace := utiltrace.New("Call mutating webhook",
|
trace := utiltrace.New("Call mutating webhook",
|
||||||
utiltrace.Field{"configuration", configurationName},
|
utiltrace.Field{"configuration", configurationName},
|
||||||
@ -261,13 +265,19 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := r.Do(ctx).Into(response); err != nil {
|
if err := r.Do(ctx).Into(response); err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("failed to call webhook: %w", err)}
|
var status *apierrors.StatusError
|
||||||
|
if se, ok := err.(*apierrors.StatusError); ok {
|
||||||
|
status = se
|
||||||
|
} else {
|
||||||
|
status = apierrors.NewBadRequest("error calling webhook")
|
||||||
|
}
|
||||||
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("failed to call webhook: %w", err), Status: status}
|
||||||
}
|
}
|
||||||
trace.Step("Request completed")
|
trace.Step("Request completed")
|
||||||
|
|
||||||
result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response)
|
result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("received invalid webhook response: %w", err)}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("received invalid webhook response: %w", err), Status: apierrors.NewServiceUnavailable("error validating webhook response")}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range result.AuditAnnotations {
|
for k, v := range result.AuditAnnotations {
|
||||||
@ -315,7 +325,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
|
|||||||
return false, apierrors.NewInternalError(err)
|
return false, apierrors.NewInternalError(err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("unsupported patch type %q", result.PatchType)}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("unsupported patch type %q", result.PatchType), Status: webhookerrors.ToStatusErr(h.Name, result.Result)}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newVersionedObject runtime.Object
|
var newVersionedObject runtime.Object
|
||||||
|
@ -119,18 +119,20 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
|
|||||||
case *webhookutil.ErrCallingWebhook:
|
case *webhookutil.ErrCallingWebhook:
|
||||||
if !ignoreClientCallFailures {
|
if !ignoreClientCallFailures {
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0)
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, int(err.Status.ErrStatus.Code))
|
||||||
}
|
}
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "validating", int(err.Status.ErrStatus.Code))
|
||||||
case *webhookutil.ErrWebhookRejection:
|
case *webhookutil.ErrWebhookRejection:
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code))
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "validating", int(err.Status.ErrStatus.Code))
|
||||||
default:
|
default:
|
||||||
rejected = true
|
rejected = true
|
||||||
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
|
admissionmetrics.Metrics.ObserveWebhookRejection(ctx, hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0)
|
||||||
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "validating", 0)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
admissionmetrics.Metrics.ObserveWebhook(ctx, time.Since(t), rejected, versionedAttr.Attributes, "validating", hook.Name)
|
admissionmetrics.Metrics.ObserveWebhook(ctx, hook.Name, time.Since(t), rejected, versionedAttr.Attributes, "validating", 200)
|
||||||
if err == nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +183,7 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
|
|||||||
func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes) error {
|
func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes) error {
|
||||||
if attr.Attributes.IsDryRun() {
|
if attr.Attributes.IsDryRun() {
|
||||||
if h.SideEffects == nil {
|
if h.SideEffects == nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil"), Status: apierrors.NewBadRequest("Webhook SideEffects is nil")}
|
||||||
}
|
}
|
||||||
if !(*h.SideEffects == v1.SideEffectClassNone || *h.SideEffects == v1.SideEffectClassNoneOnDryRun) {
|
if !(*h.SideEffects == v1.SideEffectClassNone || *h.SideEffects == v1.SideEffectClassNoneOnDryRun) {
|
||||||
return webhookerrors.NewDryRunUnsupportedErr(h.Name)
|
return webhookerrors.NewDryRunUnsupportedErr(h.Name)
|
||||||
@ -190,12 +192,12 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWeb
|
|||||||
|
|
||||||
uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation)
|
uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not create admission objects: %w", err), Status: apierrors.NewBadRequest("error creating admission objects")}
|
||||||
}
|
}
|
||||||
// Make the webhook request
|
// Make the webhook request
|
||||||
client, err := invocation.Webhook.GetRESTClient(d.cm)
|
client, err := invocation.Webhook.GetRESTClient(d.cm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not get REST client: %w", err), Status: apierrors.NewBadRequest("error getting REST client")}
|
||||||
}
|
}
|
||||||
trace := utiltrace.New("Call validating webhook",
|
trace := utiltrace.New("Call validating webhook",
|
||||||
utiltrace.Field{"configuration", invocation.Webhook.GetConfigurationName()},
|
utiltrace.Field{"configuration", invocation.Webhook.GetConfigurationName()},
|
||||||
@ -229,13 +231,19 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWeb
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := r.Do(ctx).Into(response); err != nil {
|
if err := r.Do(ctx).Into(response); err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
var status *apierrors.StatusError
|
||||||
|
if se, ok := err.(*apierrors.StatusError); ok {
|
||||||
|
status = se
|
||||||
|
} else {
|
||||||
|
status = apierrors.NewBadRequest("error calling webhook")
|
||||||
|
}
|
||||||
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("failed to call webhook: %w", err), Status: status}
|
||||||
}
|
}
|
||||||
trace.Step("Request completed")
|
trace.Step("Request completed")
|
||||||
|
|
||||||
result, err := webhookrequest.VerifyAdmissionResponse(uid, false, response)
|
result, err := webhookrequest.VerifyAdmissionResponse(uid, false, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("received invalid webhook response: %w", err), Status: apierrors.NewServiceUnavailable("error validating webhook response")}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range result.AuditAnnotations {
|
for k, v := range result.AuditAnnotations {
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
type ErrCallingWebhook struct {
|
type ErrCallingWebhook struct {
|
||||||
WebhookName string
|
WebhookName string
|
||||||
Reason error
|
Reason error
|
||||||
|
Status *apierrors.StatusError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrCallingWebhook) Error() string {
|
func (e *ErrCallingWebhook) Error() string {
|
||||||
|
Loading…
Reference in New Issue
Block a user