refactor: rename webhook duration tracker

Kubernetes-commit: 4a9b9028153c6984b9cf69067cc0a1aa12a00e73
This commit is contained in:
Abu Kashem 2022-02-01 15:44:59 -05:00 committed by Kubernetes Publisher
parent 0b7780f8b1
commit 72aa2c42fc
9 changed files with 67 additions and 61 deletions

View File

@ -265,9 +265,9 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
}
do := func() { err = r.Do(ctx).Into(response) }
if wd, ok := endpointsrequest.WebhookDurationFrom(ctx); ok {
if wd, ok := endpointsrequest.LatencyTrackersFrom(ctx); ok {
tmp := do
do = func() { wd.AdmitTracker.Track(tmp) }
do = func() { wd.MutatingWebhookTracker.Track(tmp) }
}
do()
if err != nil {

View File

@ -274,7 +274,7 @@ func TestWebhookDuration(ts *testing.T) {
ts.Run(test.Name, func(t *testing.T) {
ctx := context.TODO()
if test.InitContext {
ctx = request.WithWebhookDurationAndCustomClock(ctx, &clk)
ctx = request.WithLatencyTrackersAndCustomClock(ctx, &clk)
}
wh, err := NewMutatingWebhook(nil)
if err != nil {
@ -299,7 +299,7 @@ func TestWebhookDuration(ts *testing.T) {
}
_ = wh.Admit(ctx, webhooktesting.NewAttribute(ns, nil, test.IsDryRun), objectInterfaces)
wd, ok := request.WebhookDurationFrom(ctx)
wd, ok := request.LatencyTrackersFrom(ctx)
if !ok {
if test.InitContext {
t.Errorf("expected webhook duration to be initialized")
@ -310,11 +310,11 @@ func TestWebhookDuration(ts *testing.T) {
t.Errorf("expected webhook duration to not be initialized")
return
}
if wd.AdmitTracker.GetLatency() != test.ExpectedDurationSum {
t.Errorf("expected admit duration %q got %q", test.ExpectedDurationSum, wd.AdmitTracker.GetLatency())
if wd.MutatingWebhookTracker.GetLatency() != test.ExpectedDurationSum {
t.Errorf("expected admit duration %q got %q", test.ExpectedDurationSum, wd.MutatingWebhookTracker.GetLatency())
}
if wd.ValidateTracker.GetLatency() != 0 {
t.Errorf("expected validate duraion to be equal to 0 got %q", wd.ValidateTracker.GetLatency())
if wd.ValidatingWebhookTracker.GetLatency() != 0 {
t.Errorf("expected validate duraion to be equal to 0 got %q", wd.ValidatingWebhookTracker.GetLatency())
}
})
}

View File

@ -232,9 +232,9 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWeb
}
do := func() { err = r.Do(ctx).Into(response) }
if wd, ok := endpointsrequest.WebhookDurationFrom(ctx); ok {
if wd, ok := endpointsrequest.LatencyTrackersFrom(ctx); ok {
tmp := do
do = func() { wd.ValidateTracker.Track(tmp) }
do = func() { wd.ValidatingWebhookTracker.Track(tmp) }
}
do()
if err != nil {

View File

@ -236,7 +236,7 @@ func TestValidateWebhookDuration(ts *testing.T) {
ts.Run(test.Name, func(t *testing.T) {
ctx := context.TODO()
if test.InitContext {
ctx = request.WithWebhookDurationAndCustomClock(ctx, &clk)
ctx = request.WithLatencyTrackersAndCustomClock(ctx, &clk)
}
wh, err := NewValidatingAdmissionWebhook(nil)
if err != nil {
@ -261,7 +261,7 @@ func TestValidateWebhookDuration(ts *testing.T) {
}
_ = wh.Validate(ctx, webhooktesting.NewAttribute(ns, nil, test.IsDryRun), objectInterfaces)
wd, ok := request.WebhookDurationFrom(ctx)
wd, ok := request.LatencyTrackersFrom(ctx)
if !ok {
if test.InitContext {
t.Errorf("expected webhook duration to be initialized")
@ -272,11 +272,11 @@ func TestValidateWebhookDuration(ts *testing.T) {
t.Errorf("expected webhook duration to not be initialized")
return
}
if wd.AdmitTracker.GetLatency() != 0 {
t.Errorf("expected admit duration to be equal to 0 got %q", wd.AdmitTracker.GetLatency())
if wd.MutatingWebhookTracker.GetLatency() != 0 {
t.Errorf("expected admit duration to be equal to 0 got %q", wd.MutatingWebhookTracker.GetLatency())
}
if wd.ValidateTracker.GetLatency() < test.ExpectedDurationMax {
t.Errorf("expected validate duraion to be greater or equal to %q got %q", test.ExpectedDurationMax, wd.ValidateTracker.GetLatency())
if wd.ValidatingWebhookTracker.GetLatency() < test.ExpectedDurationMax {
t.Errorf("expected validate duraion to be greater or equal to %q got %q", test.ExpectedDurationMax, wd.ValidatingWebhookTracker.GetLatency())
}
})
}

View File

@ -22,12 +22,13 @@ import (
"k8s.io/apiserver/pkg/endpoints/request"
)
// WithWebhookDuration adds WebhookDuration trackers to the
// context associated with a request.
func WithWebhookDuration(handler http.Handler) http.Handler {
// WithLatencyTrackers adds a LatencyTrackers instance to the
// context associated with a request so that we can measure latency
// incurred in various components within the apiserver.
func WithLatencyTrackers(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
req = req.WithContext(request.WithWebhookDuration(ctx))
req = req.WithContext(request.WithLatencyTrackers(ctx))
handler.ServeHTTP(w, req)
})
}

View File

@ -482,8 +482,8 @@ func MonitorRequest(req *http.Request, verb, group, version, resource, subresour
}
}
requestLatencies.WithContext(req.Context()).WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component).Observe(elapsedSeconds)
if wd, ok := request.WebhookDurationFrom(req.Context()); ok {
sloLatency := elapsedSeconds - (wd.AdmitTracker.GetLatency() + wd.ValidateTracker.GetLatency()).Seconds()
if wd, ok := request.LatencyTrackersFrom(req.Context()); ok {
sloLatency := elapsedSeconds - (wd.MutatingWebhookTracker.GetLatency() + wd.ValidatingWebhookTracker.GetLatency()).Seconds()
requestSloLatencies.WithContext(req.Context()).WithLabelValues(reportedVerb, group, version, resource, subresource, scope, component).Observe(sloLatency)
}
// We are only interested in response sizes of read requests.

View File

@ -85,38 +85,43 @@ func newMaxLatencyTracker(c clock.Clock) DurationTracker {
}
}
// WebhookDuration stores trackers used to measure webhook request durations.
// Since admit webhooks are done sequentially duration is aggregated using
// sum function. Validate webhooks are done in parallel so max function
// is used.
type WebhookDuration struct {
AdmitTracker DurationTracker
ValidateTracker DurationTracker
// LatencyTrackers stores trackers used to measure latecny incurred in
// components within the apiserver.
type LatencyTrackers struct {
// MutatingWebhookTracker tracks the latency incurred in mutating webhook(s).
// Since mutating webhooks are done sequentially, latency
// is aggregated using sum function.
MutatingWebhookTracker DurationTracker
// ValidatingWebhookTracker tracks the latency incurred in validating webhook(s).
// Validate webhooks are done in parallel, so max function is used.
ValidatingWebhookTracker DurationTracker
}
type webhookDurationKeyType int
type latencyTrackersKeyType int
// webhookDurationKey is the WebhookDuration (the time the request spent waiting
// for the webhooks to finish) key for the context.
const webhookDurationKey webhookDurationKeyType = iota
// latencyTrackersKey is the key that associates a LatencyTrackers
// instance with the request context.
const latencyTrackersKey latencyTrackersKeyType = iota
// WithWebhookDuration returns a copy of parent context to which the
// WebhookDuration trackers are added.
func WithWebhookDuration(parent context.Context) context.Context {
return WithWebhookDurationAndCustomClock(parent, clock.RealClock{})
// WithLatencyTrackers returns a copy of parent context to which an
// instance of LatencyTrackers is added.
func WithLatencyTrackers(parent context.Context) context.Context {
return WithLatencyTrackersAndCustomClock(parent, clock.RealClock{})
}
// WithWebhookDurationAndCustomClock returns a copy of parent context to which
// the WebhookDuration trackers are added. Tracers use given clock.
func WithWebhookDurationAndCustomClock(parent context.Context, c clock.Clock) context.Context {
return WithValue(parent, webhookDurationKey, &WebhookDuration{
AdmitTracker: newSumLatencyTracker(c),
ValidateTracker: newMaxLatencyTracker(c),
// WithLatencyTrackersAndCustomClock returns a copy of parent context to which
// an instance of LatencyTrackers is added. Tracers use given clock.
func WithLatencyTrackersAndCustomClock(parent context.Context, c clock.Clock) context.Context {
return WithValue(parent, latencyTrackersKey, &LatencyTrackers{
MutatingWebhookTracker: newSumLatencyTracker(c),
ValidatingWebhookTracker: newMaxLatencyTracker(c),
})
}
// WebhookDurationFrom returns the value of the WebhookDuration key from the specified context.
func WebhookDurationFrom(ctx context.Context) (*WebhookDuration, bool) {
wd, ok := ctx.Value(webhookDurationKey).(*WebhookDuration)
// LatencyTrackersFrom returns the associated LatencyTrackers instance
// from the specified context.
func LatencyTrackersFrom(ctx context.Context) (*LatencyTrackers, bool) {
wd, ok := ctx.Value(latencyTrackersKey).(*LatencyTrackers)
return wd, ok && wd != nil
}

View File

@ -24,7 +24,7 @@ import (
clocktesting "k8s.io/utils/clock/testing"
)
func TestWebhookDurationFrom(t *testing.T) {
func TestLatencyTrackersFrom(t *testing.T) {
type testCase struct {
Durations []time.Duration
SumDurations time.Duration
@ -37,37 +37,37 @@ func TestWebhookDurationFrom(t *testing.T) {
}
t.Run("TestWebhookDurationFrom", func(t *testing.T) {
parent := context.TODO()
_, ok := WebhookDurationFrom(parent)
_, ok := LatencyTrackersFrom(parent)
if ok {
t.Error("expected WebhookDurationFrom to not be initialized")
t.Error("expected LatencyTrackersFrom to not be initialized")
}
clk := clocktesting.FakeClock{}
ctx := WithWebhookDurationAndCustomClock(parent, &clk)
wd, ok := WebhookDurationFrom(ctx)
ctx := WithLatencyTrackersAndCustomClock(parent, &clk)
wd, ok := LatencyTrackersFrom(ctx)
if !ok {
t.Error("expected webhook duration to be initialized")
t.Error("expected LatencyTrackersFrom to be initialized")
}
if wd.AdmitTracker.GetLatency() != 0 || wd.ValidateTracker.GetLatency() != 0 {
if wd.MutatingWebhookTracker.GetLatency() != 0 || wd.ValidatingWebhookTracker.GetLatency() != 0 {
t.Error("expected values to be initialized to 0")
}
for _, d := range tc.Durations {
wd.AdmitTracker.Track(func() { clk.Step(d) })
wd.ValidateTracker.Track(func() { clk.Step(d) })
wd.MutatingWebhookTracker.Track(func() { clk.Step(d) })
wd.ValidatingWebhookTracker.Track(func() { clk.Step(d) })
}
wd, ok = WebhookDurationFrom(ctx)
wd, ok = LatencyTrackersFrom(ctx)
if !ok {
t.Errorf("expected webhook duration to be initialized")
}
if wd.AdmitTracker.GetLatency() != tc.SumDurations {
t.Errorf("expected admit duration: %q, but got: %q", tc.SumDurations, wd.AdmitTracker.GetLatency())
if wd.MutatingWebhookTracker.GetLatency() != tc.SumDurations {
t.Errorf("expected admit duration: %q, but got: %q", tc.SumDurations, wd.MutatingWebhookTracker.GetLatency())
}
if wd.ValidateTracker.GetLatency() != tc.MaxDuration {
t.Errorf("expected validate duration: %q, but got: %q", tc.MaxDuration, wd.ValidateTracker.GetLatency())
if wd.ValidatingWebhookTracker.GetLatency() != tc.MaxDuration {
t.Errorf("expected validate duration: %q, but got: %q", tc.MaxDuration, wd.ValidatingWebhookTracker.GetLatency())
}
})
}

View File

@ -762,7 +762,7 @@ func BuildHandlerChainWithStorageVersionPrecondition(apiHandler http.Handler, c
}
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
handler := genericapifilters.WithWebhookDuration(apiHandler)
handler := genericapifilters.WithLatencyTrackers(apiHandler)
handler = filterlatency.TrackCompleted(handler)
handler = genericapifilters.WithAuthorization(handler, c.Authorization.Authorizer, c.Serializer)
handler = filterlatency.TrackStarted(handler, "authorization")