mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
Add trace to webhook invocations
This commit is contained in:
parent
4824f823ad
commit
31799ebe88
@ -29,6 +29,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ package conversion
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
apivalidation "k8s.io/apimachinery/pkg/api/validation"
|
apivalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -33,6 +34,7 @@ import (
|
|||||||
|
|
||||||
internal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
internal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
|
utiltrace "k8s.io/utils/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type webhookConverterFactory struct {
|
type webhookConverterFactory struct {
|
||||||
@ -170,7 +172,8 @@ func (c *webhookConverter) Convert(in runtime.Object, toGV schema.GroupVersion)
|
|||||||
}
|
}
|
||||||
|
|
||||||
request := createConversionReview(in, toGV.String())
|
request := createConversionReview(in, toGV.String())
|
||||||
if len(request.Request.Objects) == 0 {
|
objCount := len(request.Request.Objects)
|
||||||
|
if objCount == 0 {
|
||||||
if !isList {
|
if !isList {
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
@ -178,6 +181,15 @@ func (c *webhookConverter) Convert(in runtime.Object, toGV schema.GroupVersion)
|
|||||||
out.SetAPIVersion(toGV.String())
|
out.SetAPIVersion(toGV.String())
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace := utiltrace.New(fmt.Sprintf(
|
||||||
|
"Call conversion webhook: custom resource definition: %s, desired API version: %s, object count: %d, UID: %v",
|
||||||
|
c.name, request.Request.DesiredAPIVersion, objCount, request.Request.UID))
|
||||||
|
// Only log conversion webhook traces that exceed a 8ms per object limit plus a 50ms request overhead allowance.
|
||||||
|
// The per object limit uses the SLO for conversion webhooks (~4ms per object) plus time to serialize/deserialize
|
||||||
|
// the conversion request on the apiserver side (~4ms per object).
|
||||||
|
defer trace.LogIfLong(time.Duration(50+8*objCount) * time.Millisecond)
|
||||||
|
|
||||||
response := &v1beta1.ConversionReview{}
|
response := &v1beta1.ConversionReview{}
|
||||||
// TODO: Figure out if adding one second timeout make sense here.
|
// TODO: Figure out if adding one second timeout make sense here.
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
@ -186,6 +198,7 @@ func (c *webhookConverter) Convert(in runtime.Object, toGV schema.GroupVersion)
|
|||||||
// TODO: Return a webhook specific error to be able to convert it to meta.Status
|
// TODO: Return a webhook specific error to be able to convert it to meta.Status
|
||||||
return nil, fmt.Errorf("conversion webhook for %v failed: %v", in.GetObjectKind(), err)
|
return nil, fmt.Errorf("conversion webhook for %v failed: %v", in.GetObjectKind(), err)
|
||||||
}
|
}
|
||||||
|
trace.Step("Request completed")
|
||||||
|
|
||||||
if response.Response == nil {
|
if response.Response == nil {
|
||||||
// TODO: Return a webhook specific error to be able to convert it to meta.Status
|
// TODO: Return a webhook specific error to be able to convert it to meta.Status
|
||||||
|
@ -93,7 +93,7 @@ func mergeMutatingWebhookConfigurations(configurations []*v1beta1.MutatingWebhoo
|
|||||||
n := c.Webhooks[i].Name
|
n := c.Webhooks[i].Name
|
||||||
uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n])
|
uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n])
|
||||||
names[n]++
|
names[n]++
|
||||||
accessors = append(accessors, webhook.NewMutatingWebhookAccessor(uid, &c.Webhooks[i]))
|
accessors = append(accessors, webhook.NewMutatingWebhookAccessor(uid, c.Name, &c.Webhooks[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return accessors
|
return accessors
|
||||||
|
@ -91,7 +91,7 @@ func mergeValidatingWebhookConfigurations(configurations []*v1beta1.ValidatingWe
|
|||||||
n := c.Webhooks[i].Name
|
n := c.Webhooks[i].Name
|
||||||
uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n])
|
uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n])
|
||||||
names[n]++
|
names[n]++
|
||||||
accessors = append(accessors, webhook.NewValidatingWebhookAccessor(uid, &c.Webhooks[i]))
|
accessors = append(accessors, webhook.NewValidatingWebhookAccessor(uid, c.Name, &c.Webhooks[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return accessors
|
return accessors
|
||||||
|
@ -26,6 +26,9 @@ type WebhookAccessor interface {
|
|||||||
// GetUID gets a string that uniquely identifies the webhook.
|
// GetUID gets a string that uniquely identifies the webhook.
|
||||||
GetUID() string
|
GetUID() string
|
||||||
|
|
||||||
|
// GetConfigurationName gets the name of the webhook configuration that owns this webhook.
|
||||||
|
GetConfigurationName() string
|
||||||
|
|
||||||
// GetName gets the webhook Name field. Note that the name is scoped to the webhook
|
// GetName gets the webhook Name field. Note that the name is scoped to the webhook
|
||||||
// configuration and does not provide a globally unique identity, if a unique identity is
|
// configuration and does not provide a globally unique identity, if a unique identity is
|
||||||
// needed, use GetUID.
|
// needed, use GetUID.
|
||||||
@ -56,45 +59,60 @@ type WebhookAccessor interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook.
|
// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook.
|
||||||
func NewMutatingWebhookAccessor(uid string, h *v1beta1.MutatingWebhook) WebhookAccessor {
|
func NewMutatingWebhookAccessor(uid, configurationName string, h *v1beta1.MutatingWebhook) WebhookAccessor {
|
||||||
return mutatingWebhookAccessor{uid: uid, MutatingWebhook: h}
|
return mutatingWebhookAccessor{uid: uid, configurationName: configurationName, MutatingWebhook: h}
|
||||||
}
|
}
|
||||||
|
|
||||||
type mutatingWebhookAccessor struct {
|
type mutatingWebhookAccessor struct {
|
||||||
*v1beta1.MutatingWebhook
|
*v1beta1.MutatingWebhook
|
||||||
uid string
|
uid string
|
||||||
|
configurationName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetUID() string {
|
func (m mutatingWebhookAccessor) GetUID() string {
|
||||||
return m.uid
|
return m.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mutatingWebhookAccessor) GetConfigurationName() string {
|
||||||
|
return m.configurationName
|
||||||
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetName() string {
|
func (m mutatingWebhookAccessor) GetName() string {
|
||||||
return m.Name
|
return m.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetClientConfig() v1beta1.WebhookClientConfig {
|
func (m mutatingWebhookAccessor) GetClientConfig() v1beta1.WebhookClientConfig {
|
||||||
return m.ClientConfig
|
return m.ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetRules() []v1beta1.RuleWithOperations {
|
func (m mutatingWebhookAccessor) GetRules() []v1beta1.RuleWithOperations {
|
||||||
return m.Rules
|
return m.Rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetFailurePolicy() *v1beta1.FailurePolicyType {
|
func (m mutatingWebhookAccessor) GetFailurePolicy() *v1beta1.FailurePolicyType {
|
||||||
return m.FailurePolicy
|
return m.FailurePolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetMatchPolicy() *v1beta1.MatchPolicyType {
|
func (m mutatingWebhookAccessor) GetMatchPolicy() *v1beta1.MatchPolicyType {
|
||||||
return m.MatchPolicy
|
return m.MatchPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector {
|
func (m mutatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector {
|
||||||
return m.NamespaceSelector
|
return m.NamespaceSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector {
|
func (m mutatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector {
|
||||||
return m.ObjectSelector
|
return m.ObjectSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetSideEffects() *v1beta1.SideEffectClass {
|
func (m mutatingWebhookAccessor) GetSideEffects() *v1beta1.SideEffectClass {
|
||||||
return m.SideEffects
|
return m.SideEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetTimeoutSeconds() *int32 {
|
func (m mutatingWebhookAccessor) GetTimeoutSeconds() *int32 {
|
||||||
return m.TimeoutSeconds
|
return m.TimeoutSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetAdmissionReviewVersions() []string {
|
func (m mutatingWebhookAccessor) GetAdmissionReviewVersions() []string {
|
||||||
return m.AdmissionReviewVersions
|
return m.AdmissionReviewVersions
|
||||||
}
|
}
|
||||||
@ -108,45 +126,60 @@ func (m mutatingWebhookAccessor) GetValidatingWebhook() (*v1beta1.ValidatingWebh
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook.
|
// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook.
|
||||||
func NewValidatingWebhookAccessor(uid string, h *v1beta1.ValidatingWebhook) WebhookAccessor {
|
func NewValidatingWebhookAccessor(uid, configurationName string, h *v1beta1.ValidatingWebhook) WebhookAccessor {
|
||||||
return validatingWebhookAccessor{uid: uid, ValidatingWebhook: h}
|
return validatingWebhookAccessor{uid: uid, configurationName: configurationName, ValidatingWebhook: h}
|
||||||
}
|
}
|
||||||
|
|
||||||
type validatingWebhookAccessor struct {
|
type validatingWebhookAccessor struct {
|
||||||
*v1beta1.ValidatingWebhook
|
*v1beta1.ValidatingWebhook
|
||||||
uid string
|
uid string
|
||||||
|
configurationName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetUID() string {
|
func (v validatingWebhookAccessor) GetUID() string {
|
||||||
return v.uid
|
return v.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v validatingWebhookAccessor) GetConfigurationName() string {
|
||||||
|
return v.configurationName
|
||||||
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetName() string {
|
func (v validatingWebhookAccessor) GetName() string {
|
||||||
return v.Name
|
return v.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetClientConfig() v1beta1.WebhookClientConfig {
|
func (v validatingWebhookAccessor) GetClientConfig() v1beta1.WebhookClientConfig {
|
||||||
return v.ClientConfig
|
return v.ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetRules() []v1beta1.RuleWithOperations {
|
func (v validatingWebhookAccessor) GetRules() []v1beta1.RuleWithOperations {
|
||||||
return v.Rules
|
return v.Rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetFailurePolicy() *v1beta1.FailurePolicyType {
|
func (v validatingWebhookAccessor) GetFailurePolicy() *v1beta1.FailurePolicyType {
|
||||||
return v.FailurePolicy
|
return v.FailurePolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetMatchPolicy() *v1beta1.MatchPolicyType {
|
func (v validatingWebhookAccessor) GetMatchPolicy() *v1beta1.MatchPolicyType {
|
||||||
return v.MatchPolicy
|
return v.MatchPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector {
|
func (v validatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector {
|
||||||
return v.NamespaceSelector
|
return v.NamespaceSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector {
|
func (v validatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector {
|
||||||
return v.ObjectSelector
|
return v.ObjectSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetSideEffects() *v1beta1.SideEffectClass {
|
func (v validatingWebhookAccessor) GetSideEffects() *v1beta1.SideEffectClass {
|
||||||
return v.SideEffects
|
return v.SideEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetTimeoutSeconds() *int32 {
|
func (v validatingWebhookAccessor) GetTimeoutSeconds() *int32 {
|
||||||
return v.TimeoutSeconds
|
return v.TimeoutSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetAdmissionReviewVersions() []string {
|
func (v validatingWebhookAccessor) GetAdmissionReviewVersions() []string {
|
||||||
return v.AdmissionReviewVersions
|
return v.AdmissionReviewVersions
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func TestMutatingWebhookAccessor(t *testing.T) {
|
|||||||
orig.ReinvocationPolicy = nil
|
orig.ReinvocationPolicy = nil
|
||||||
|
|
||||||
uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name)
|
uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name)
|
||||||
accessor := NewMutatingWebhookAccessor(uid, orig)
|
accessor := NewMutatingWebhookAccessor(uid, "test.configuration.admission", orig)
|
||||||
if uid != accessor.GetUID() {
|
if uid != accessor.GetUID() {
|
||||||
t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid)
|
t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid)
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ func TestValidatingWebhookAccessor(t *testing.T) {
|
|||||||
orig := &v1beta1.ValidatingWebhook{}
|
orig := &v1beta1.ValidatingWebhook{}
|
||||||
f.Fuzz(orig)
|
f.Fuzz(orig)
|
||||||
uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name)
|
uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name)
|
||||||
accessor := NewValidatingWebhookAccessor(uid, orig)
|
accessor := NewValidatingWebhookAccessor(uid, "test.configuration.admission", orig)
|
||||||
if uid != accessor.GetUID() {
|
if uid != accessor.GetUID() {
|
||||||
t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid)
|
t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid)
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ func TestShouldCallHook(t *testing.T) {
|
|||||||
|
|
||||||
for i, testcase := range testcases {
|
for i, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
invocation, err := a.ShouldCallHook(webhook.NewValidatingWebhookAccessor(fmt.Sprintf("webhook-%d", i), testcase.webhook), testcase.attrs, interfaces)
|
invocation, err := a.ShouldCallHook(webhook.NewValidatingWebhookAccessor(fmt.Sprintf("webhook-%d", i), fmt.Sprintf("webhook-cfg-%d", i), testcase.webhook), testcase.attrs, interfaces)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(testcase.expectErr) == 0 {
|
if len(testcase.expectErr) == 0 {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -32,6 +32,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
||||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ import (
|
|||||||
webhookrequest "k8s.io/apiserver/pkg/admission/plugin/webhook/request"
|
webhookrequest "k8s.io/apiserver/pkg/admission/plugin/webhook/request"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
|
utiltrace "k8s.io/utils/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mutatingDispatcher struct {
|
type mutatingDispatcher struct {
|
||||||
@ -172,6 +173,10 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
|
trace := utiltrace.New(fmt.Sprintf("Call mutating webhook: configuration: %s, webhook: %s, resource: %v, subResource: %s, operation: %v, UID: %v",
|
||||||
|
invocation.Webhook.GetConfigurationName(), h.Name, request.Request.Resource, request.Request.SubResource, request.Request.Operation, request.Request.UID))
|
||||||
|
defer trace.LogIfLong(500 * time.Millisecond)
|
||||||
|
response := &admissionv1beta1.AdmissionReview{}
|
||||||
r := client.Post().Context(ctx).Body(request)
|
r := client.Post().Context(ctx).Body(request)
|
||||||
if h.TimeoutSeconds != nil {
|
if h.TimeoutSeconds != nil {
|
||||||
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
|
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
|
||||||
@ -179,6 +184,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
|
|||||||
if err := r.Do().Into(response); err != nil {
|
if err := r.Do().Into(response); err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
|
trace.Step("Request completed")
|
||||||
|
|
||||||
result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response)
|
result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -248,7 +254,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
|
|||||||
}
|
}
|
||||||
|
|
||||||
changed := !apiequality.Semantic.DeepEqual(attr.VersionedObject, newVersionedObject)
|
changed := !apiequality.Semantic.DeepEqual(attr.VersionedObject, newVersionedObject)
|
||||||
|
trace.Step("Patch applied")
|
||||||
attr.Dirty = true
|
attr.Dirty = true
|
||||||
attr.VersionedObject = newVersionedObject
|
attr.VersionedObject = newVersionedObject
|
||||||
o.GetObjectDefaulter().Default(attr.VersionedObject)
|
o.GetObjectDefaulter().Default(attr.VersionedObject)
|
||||||
|
@ -120,7 +120,7 @@ func TestNotExemptClusterScopedResource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, &metav1.CreateOptions{}, false, nil)
|
attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, &metav1.CreateOptions{}, false, nil)
|
||||||
matcher := Matcher{}
|
matcher := Matcher{}
|
||||||
matches, err := matcher.MatchNamespaceSelector(webhook.NewValidatingWebhookAccessor("mock-hook", hook), attr)
|
matches, err := matcher.MatchNamespaceSelector(webhook.NewValidatingWebhookAccessor("mock-hook", "mock-cfg", hook), attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ func TestObjectSelector(t *testing.T) {
|
|||||||
}}}
|
}}}
|
||||||
|
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
match, err := matcher.MatchObjectSelector(webhook.NewValidatingWebhookAccessor("mock-hook", hook), testcase.attrs)
|
match, err := matcher.MatchObjectSelector(webhook.NewValidatingWebhookAccessor("mock-hook", "mock-cfg", hook), testcase.attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -486,14 +486,14 @@ func TestCreateAdmissionObjects(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no supported versions",
|
name: "no supported versions",
|
||||||
invocation: &generic.WebhookInvocation{
|
invocation: &generic.WebhookInvocation{
|
||||||
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", &admissionregistrationv1beta1.MutatingWebhook{}),
|
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1beta1.MutatingWebhook{}),
|
||||||
},
|
},
|
||||||
expectErr: "webhook does not accept known AdmissionReview versions",
|
expectErr: "webhook does not accept known AdmissionReview versions",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no known supported versions",
|
name: "no known supported versions",
|
||||||
invocation: &generic.WebhookInvocation{
|
invocation: &generic.WebhookInvocation{
|
||||||
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", &admissionregistrationv1beta1.MutatingWebhook{
|
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1beta1.MutatingWebhook{
|
||||||
AdmissionReviewVersions: []string{"vX"},
|
AdmissionReviewVersions: []string{"vX"},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -510,7 +510,7 @@ func TestCreateAdmissionObjects(t *testing.T) {
|
|||||||
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
|
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
|
||||||
Subresource: "",
|
Subresource: "",
|
||||||
Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"},
|
Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"},
|
||||||
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", &admissionregistrationv1beta1.MutatingWebhook{
|
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1beta1.MutatingWebhook{
|
||||||
AdmissionReviewVersions: []string{"v1", "v1beta1"},
|
AdmissionReviewVersions: []string{"v1", "v1beta1"},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -553,7 +553,7 @@ func TestCreateAdmissionObjects(t *testing.T) {
|
|||||||
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
|
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
|
||||||
Subresource: "",
|
Subresource: "",
|
||||||
Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"},
|
Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"},
|
||||||
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", &admissionregistrationv1beta1.MutatingWebhook{
|
Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1beta1.MutatingWebhook{
|
||||||
AdmissionReviewVersions: []string{"v1beta1", "v1"},
|
AdmissionReviewVersions: []string{"v1beta1", "v1"},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -25,6 +25,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
utiltrace "k8s.io/utils/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type validatingDispatcher struct {
|
type validatingDispatcher struct {
|
||||||
@ -153,6 +154,10 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Validati
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
|
trace := utiltrace.New(fmt.Sprintf("Call validating webhook: configuration: %s, webhook: %s, resource: %v, subResource: %s, operation: %v, UID: %v",
|
||||||
|
invocation.Webhook.GetConfigurationName(), h.Name, request.Request.Resource, request.Request.SubResource, request.Request.Operation, request.Request.UID))
|
||||||
|
defer trace.LogIfLong(500 * time.Millisecond)
|
||||||
|
response := &admissionv1beta1.AdmissionReview{}
|
||||||
r := client.Post().Context(ctx).Body(request)
|
r := client.Post().Context(ctx).Body(request)
|
||||||
if h.TimeoutSeconds != nil {
|
if h.TimeoutSeconds != nil {
|
||||||
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
|
r = r.Timeout(time.Duration(*h.TimeoutSeconds) * time.Second)
|
||||||
@ -160,6 +165,7 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Validati
|
|||||||
if err := r.Do().Into(response); err != nil {
|
if err := r.Do().Into(response); err != nil {
|
||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
|
trace.Step("Request completed")
|
||||||
|
|
||||||
result, err := webhookrequest.VerifyAdmissionResponse(uid, false, response)
|
result, err := webhookrequest.VerifyAdmissionResponse(uid, false, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,6 +36,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/audit:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/audit"
|
"k8s.io/apiserver/pkg/audit"
|
||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
|
utiltrace "k8s.io/utils/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -95,6 +96,12 @@ func (b *backend) processEvents(ev ...*auditinternal.Event) error {
|
|||||||
list.Items = append(list.Items, *e)
|
list.Items = append(list.Items, *e)
|
||||||
}
|
}
|
||||||
return b.w.WithExponentialBackoff(func() rest.Result {
|
return b.w.WithExponentialBackoff(func() rest.Result {
|
||||||
|
trace := utiltrace.New(fmt.Sprintf("Audit events webhook request for %s, event list count: %d", b.name, len(list.Items)))
|
||||||
|
// Only log audit webhook traces that exceed a 25ms per object limit plus a 50ms
|
||||||
|
// request overhead allowance. The high per object limit used here is primarily to
|
||||||
|
// allow enough time for the serialization/deserialization of audit events, which
|
||||||
|
// contain nested request and response objects plus additional event fields.
|
||||||
|
defer trace.LogIfLong(time.Duration(50+25*len(list.Items)) * time.Millisecond)
|
||||||
return b.w.RestClient.Post().Body(&list).Do()
|
return b.w.RestClient.Post().Body(&list).Do()
|
||||||
}).Error()
|
}).Error()
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,11 @@ package apiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"k8s.io/klog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"k8s.io/klog"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||||
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
|
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
|
||||||
|
Loading…
Reference in New Issue
Block a user