mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #81896 from liggitt/webhook-efficiency
Compute webhook selectors and client once per webhookconfig revision
This commit is contained in:
commit
273e1a4605
@ -9,6 +9,9 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/api/admissionregistration/v1beta1:go_default_library",
|
"//staging/src/k8s.io/api/admissionregistration/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,8 +17,13 @@ limitations under the License.
|
|||||||
package webhook
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"k8s.io/api/admissionregistration/v1beta1"
|
"k8s.io/api/admissionregistration/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebhookAccessor provides a common interface to both mutating and validating webhook types.
|
// WebhookAccessor provides a common interface to both mutating and validating webhook types.
|
||||||
@ -29,6 +34,13 @@ type WebhookAccessor interface {
|
|||||||
// GetConfigurationName gets the name of the webhook configuration that owns this webhook.
|
// GetConfigurationName gets the name of the webhook configuration that owns this webhook.
|
||||||
GetConfigurationName() string
|
GetConfigurationName() string
|
||||||
|
|
||||||
|
// GetRESTClient gets the webhook client
|
||||||
|
GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error)
|
||||||
|
// GetParsedNamespaceSelector gets the webhook NamespaceSelector field.
|
||||||
|
GetParsedNamespaceSelector() (labels.Selector, error)
|
||||||
|
// GetParsedObjectSelector gets the webhook ObjectSelector field.
|
||||||
|
GetParsedObjectSelector() (labels.Selector, error)
|
||||||
|
|
||||||
// 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.
|
||||||
@ -60,134 +72,226 @@ type WebhookAccessor interface {
|
|||||||
|
|
||||||
// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook.
|
// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook.
|
||||||
func NewMutatingWebhookAccessor(uid, configurationName string, h *v1beta1.MutatingWebhook) WebhookAccessor {
|
func NewMutatingWebhookAccessor(uid, configurationName string, h *v1beta1.MutatingWebhook) WebhookAccessor {
|
||||||
return mutatingWebhookAccessor{uid: uid, configurationName: configurationName, 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
|
configurationName string
|
||||||
|
|
||||||
|
initObjectSelector sync.Once
|
||||||
|
objectSelector labels.Selector
|
||||||
|
objectSelectorErr error
|
||||||
|
|
||||||
|
initNamespaceSelector sync.Once
|
||||||
|
namespaceSelector labels.Selector
|
||||||
|
namespaceSelectorErr error
|
||||||
|
|
||||||
|
initClient sync.Once
|
||||||
|
client *rest.RESTClient
|
||||||
|
clientErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetUID() string {
|
func (m *mutatingWebhookAccessor) GetUID() string {
|
||||||
return m.uid
|
return m.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetConfigurationName() string {
|
func (m *mutatingWebhookAccessor) GetConfigurationName() string {
|
||||||
return m.configurationName
|
return m.configurationName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetName() string {
|
func (m *mutatingWebhookAccessor) GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error) {
|
||||||
|
m.initClient.Do(func() {
|
||||||
|
m.client, m.clientErr = clientManager.HookClient(hookClientConfigForWebhook(m))
|
||||||
|
})
|
||||||
|
return m.client, m.clientErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mutatingWebhookAccessor) GetParsedNamespaceSelector() (labels.Selector, error) {
|
||||||
|
m.initNamespaceSelector.Do(func() {
|
||||||
|
m.namespaceSelector, m.namespaceSelectorErr = metav1.LabelSelectorAsSelector(m.NamespaceSelector)
|
||||||
|
})
|
||||||
|
return m.namespaceSelector, m.namespaceSelectorErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mutatingWebhookAccessor) GetParsedObjectSelector() (labels.Selector, error) {
|
||||||
|
m.initObjectSelector.Do(func() {
|
||||||
|
m.objectSelector, m.objectSelectorErr = metav1.LabelSelectorAsSelector(m.ObjectSelector)
|
||||||
|
})
|
||||||
|
return m.objectSelector, m.objectSelectorErr
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetMutatingWebhook() (*v1beta1.MutatingWebhook, bool) {
|
func (m *mutatingWebhookAccessor) GetMutatingWebhook() (*v1beta1.MutatingWebhook, bool) {
|
||||||
return m.MutatingWebhook, true
|
return m.MutatingWebhook, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mutatingWebhookAccessor) GetValidatingWebhook() (*v1beta1.ValidatingWebhook, bool) {
|
func (m *mutatingWebhookAccessor) GetValidatingWebhook() (*v1beta1.ValidatingWebhook, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook.
|
// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook.
|
||||||
func NewValidatingWebhookAccessor(uid, configurationName string, h *v1beta1.ValidatingWebhook) WebhookAccessor {
|
func NewValidatingWebhookAccessor(uid, configurationName string, h *v1beta1.ValidatingWebhook) WebhookAccessor {
|
||||||
return validatingWebhookAccessor{uid: uid, configurationName: configurationName, 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
|
configurationName string
|
||||||
|
|
||||||
|
initObjectSelector sync.Once
|
||||||
|
objectSelector labels.Selector
|
||||||
|
objectSelectorErr error
|
||||||
|
|
||||||
|
initNamespaceSelector sync.Once
|
||||||
|
namespaceSelector labels.Selector
|
||||||
|
namespaceSelectorErr error
|
||||||
|
|
||||||
|
initClient sync.Once
|
||||||
|
client *rest.RESTClient
|
||||||
|
clientErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetUID() string {
|
func (v *validatingWebhookAccessor) GetUID() string {
|
||||||
return v.uid
|
return v.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetConfigurationName() string {
|
func (v *validatingWebhookAccessor) GetConfigurationName() string {
|
||||||
return v.configurationName
|
return v.configurationName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetName() string {
|
func (v *validatingWebhookAccessor) GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error) {
|
||||||
|
v.initClient.Do(func() {
|
||||||
|
v.client, v.clientErr = clientManager.HookClient(hookClientConfigForWebhook(v))
|
||||||
|
})
|
||||||
|
return v.client, v.clientErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *validatingWebhookAccessor) GetParsedNamespaceSelector() (labels.Selector, error) {
|
||||||
|
v.initNamespaceSelector.Do(func() {
|
||||||
|
v.namespaceSelector, v.namespaceSelectorErr = metav1.LabelSelectorAsSelector(v.NamespaceSelector)
|
||||||
|
})
|
||||||
|
return v.namespaceSelector, v.namespaceSelectorErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *validatingWebhookAccessor) GetParsedObjectSelector() (labels.Selector, error) {
|
||||||
|
v.initObjectSelector.Do(func() {
|
||||||
|
v.objectSelector, v.objectSelectorErr = metav1.LabelSelectorAsSelector(v.ObjectSelector)
|
||||||
|
})
|
||||||
|
return v.objectSelector, v.objectSelectorErr
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetMutatingWebhook() (*v1beta1.MutatingWebhook, bool) {
|
func (v *validatingWebhookAccessor) GetMutatingWebhook() (*v1beta1.MutatingWebhook, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v validatingWebhookAccessor) GetValidatingWebhook() (*v1beta1.ValidatingWebhook, bool) {
|
func (v *validatingWebhookAccessor) GetValidatingWebhook() (*v1beta1.ValidatingWebhook, bool) {
|
||||||
return v.ValidatingWebhook, true
|
return v.ValidatingWebhook, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hookClientConfigForWebhook construct a webhookutil.ClientConfig using a WebhookAccessor to access
|
||||||
|
// v1beta1.MutatingWebhook and v1beta1.ValidatingWebhook API objects. webhookutil.ClientConfig is used
|
||||||
|
// to create a HookClient and the purpose of the config struct is to share that with other packages
|
||||||
|
// that need to create a HookClient.
|
||||||
|
func hookClientConfigForWebhook(w WebhookAccessor) webhookutil.ClientConfig {
|
||||||
|
ret := webhookutil.ClientConfig{Name: w.GetName(), CABundle: w.GetClientConfig().CABundle}
|
||||||
|
if w.GetClientConfig().URL != nil {
|
||||||
|
ret.URL = *w.GetClientConfig().URL
|
||||||
|
}
|
||||||
|
if w.GetClientConfig().Service != nil {
|
||||||
|
ret.Service = &webhookutil.ClientConfigService{
|
||||||
|
Name: w.GetClientConfig().Service.Name,
|
||||||
|
Namespace: w.GetClientConfig().Service.Namespace,
|
||||||
|
}
|
||||||
|
if w.GetClientConfig().Service.Port != nil {
|
||||||
|
ret.Service.Port = *w.GetClientConfig().Service.Port
|
||||||
|
} else {
|
||||||
|
ret.Service.Port = 443
|
||||||
|
}
|
||||||
|
if w.GetClientConfig().Service.Path != nil {
|
||||||
|
ret.Service.Path = *w.GetClientConfig().Service.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
@ -28,7 +28,6 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/apis/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",
|
||||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||||
|
@ -40,7 +40,6 @@ import (
|
|||||||
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
|
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
|
||||||
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"
|
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
utiltrace "k8s.io/utils/trace"
|
utiltrace "k8s.io/utils/trace"
|
||||||
@ -197,7 +196,7 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
|
|||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
// Make the webhook request
|
// Make the webhook request
|
||||||
client, err := a.cm.HookClient(util.HookClientConfigForWebhook(invocation.Webhook))
|
client, err := invocation.Webhook.GetRESTClient(a.cm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -33,6 +34,75 @@ import (
|
|||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BenchmarkAdmit tests the performance cost of invoking a mutating webhook
|
||||||
|
func BenchmarkAdmit(b *testing.B) {
|
||||||
|
testServerURL := os.Getenv("WEBHOOK_TEST_SERVER_URL")
|
||||||
|
if len(testServerURL) == 0 {
|
||||||
|
b.Log("warning, WEBHOOK_TEST_SERVER_URL not set, starting in-process server, benchmarks will include webhook cost.")
|
||||||
|
b.Log("to run a standalone server, run:")
|
||||||
|
b.Log("go run ./vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main/main.go")
|
||||||
|
testServer := webhooktesting.NewTestServer(b)
|
||||||
|
testServer.StartTLS()
|
||||||
|
defer testServer.Close()
|
||||||
|
testServerURL = testServer.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
serverURL, err := url.ParseRequestURI(testServerURL)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("this should never happen? %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
|
stopCh := make(chan struct{})
|
||||||
|
defer close(stopCh)
|
||||||
|
|
||||||
|
testCases := append(webhooktesting.NewMutatingTestCases(serverURL, "test-webhooks"),
|
||||||
|
webhooktesting.ConvertToMutatingTestCases(webhooktesting.NewNonMutatingTestCases(serverURL), "test-webhooks")...)
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
// For now, skip failure cases or tests that explicitly skip benchmarking
|
||||||
|
if !tt.ExpectAllow || tt.SkipBenchmark {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b.Run(tt.Name, func(b *testing.B) {
|
||||||
|
wh, err := NewMutatingWebhook(nil)
|
||||||
|
if err != nil {
|
||||||
|
b.Errorf("failed to create mutating webhook: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ns := "webhook-test"
|
||||||
|
client, informer := webhooktesting.NewFakeMutatingDataSource(ns, tt.Webhooks, stopCh)
|
||||||
|
|
||||||
|
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
||||||
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
|
wh.SetExternalKubeClientSet(client)
|
||||||
|
wh.SetExternalKubeInformerFactory(informer)
|
||||||
|
|
||||||
|
informer.Start(stopCh)
|
||||||
|
informer.WaitForCacheSync(stopCh)
|
||||||
|
|
||||||
|
if err = wh.ValidateInitialization(); err != nil {
|
||||||
|
b.Errorf("failed to validate initialization: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var attr admission.Attributes
|
||||||
|
if tt.IsCRD {
|
||||||
|
attr = webhooktesting.NewAttributeUnstructured(ns, tt.AdditionalLabels, tt.IsDryRun)
|
||||||
|
} else {
|
||||||
|
attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
wh.Admit(context.TODO(), attr, objectInterfaces)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestAdmit tests that MutatingWebhook#Admit works as expected
|
// TestAdmit tests that MutatingWebhook#Admit works as expected
|
||||||
func TestAdmit(t *testing.T) {
|
func TestAdmit(t *testing.T) {
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
|
@ -95,8 +95,7 @@ func (m *Matcher) MatchNamespaceSelector(h webhook.WebhookAccessor, attr admissi
|
|||||||
// Also update the comment in types.go
|
// Also update the comment in types.go
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
// TODO: adding an LRU cache to cache the translation
|
selector, err := h.GetParsedNamespaceSelector()
|
||||||
selector, err := metav1.LabelSelectorAsSelector(h.GetNamespaceSelector())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, apierrors.NewInternalError(err)
|
return false, apierrors.NewInternalError(err)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||||
|
@ -19,7 +19,6 @@ package object
|
|||||||
import (
|
import (
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
@ -47,8 +46,7 @@ func matchObject(obj runtime.Object, selector labels.Selector) bool {
|
|||||||
// MatchObjectSelector decideds whether the request matches the ObjectSelector
|
// MatchObjectSelector decideds whether the request matches the ObjectSelector
|
||||||
// of the webhook. Only when they match, the webhook is called.
|
// of the webhook. Only when they match, the webhook is called.
|
||||||
func (m *Matcher) MatchObjectSelector(h webhook.WebhookAccessor, attr admission.Attributes) (bool, *apierrors.StatusError) {
|
func (m *Matcher) MatchObjectSelector(h webhook.WebhookAccessor, attr admission.Attributes) (bool, *apierrors.StatusError) {
|
||||||
// TODO: adding an LRU cache to cache the translation
|
selector, err := h.GetParsedObjectSelector()
|
||||||
selector, err := metav1.LabelSelectorAsSelector(h.GetObjectSelector())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, apierrors.NewInternalError(err)
|
return false, apierrors.NewInternalError(err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,10 @@ filegroup(
|
|||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [":package-srcs"],
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main:all-srcs",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["main.go"],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main",
|
||||||
|
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main",
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
deps = ["//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:go_default_library"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_binary(
|
||||||
|
name = "main",
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
server := webhooktesting.NewTestServer(nil)
|
||||||
|
server.StartTLS()
|
||||||
|
fmt.Println("serving on", server.URL)
|
||||||
|
select {}
|
||||||
|
}
|
@ -217,6 +217,7 @@ type ValidatingTest struct {
|
|||||||
IsCRD bool
|
IsCRD bool
|
||||||
IsDryRun bool
|
IsDryRun bool
|
||||||
AdditionalLabels map[string]string
|
AdditionalLabels map[string]string
|
||||||
|
SkipBenchmark bool
|
||||||
ExpectLabels map[string]string
|
ExpectLabels map[string]string
|
||||||
ExpectAllow bool
|
ExpectAllow bool
|
||||||
ErrorContains string
|
ErrorContains string
|
||||||
@ -233,6 +234,7 @@ type MutatingTest struct {
|
|||||||
IsCRD bool
|
IsCRD bool
|
||||||
IsDryRun bool
|
IsDryRun bool
|
||||||
AdditionalLabels map[string]string
|
AdditionalLabels map[string]string
|
||||||
|
SkipBenchmark bool
|
||||||
ExpectLabels map[string]string
|
ExpectLabels map[string]string
|
||||||
ExpectAllow bool
|
ExpectAllow bool
|
||||||
ErrorContains string
|
ErrorContains string
|
||||||
@ -262,7 +264,7 @@ func ConvertToMutatingTestCases(tests []ValidatingTest, configurationName string
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r[i] = MutatingTest{t.Name, ConvertToMutatingWebhooks(t.Webhooks), t.Path, t.IsCRD, t.IsDryRun, t.AdditionalLabels, t.ExpectLabels, t.ExpectAllow, t.ErrorContains, t.ExpectAnnotations, t.ExpectStatusCode, t.ExpectReinvokeWebhooks}
|
r[i] = MutatingTest{t.Name, ConvertToMutatingWebhooks(t.Webhooks), t.Path, t.IsCRD, t.IsDryRun, t.AdditionalLabels, t.SkipBenchmark, t.ExpectLabels, t.ExpectAllow, t.ErrorContains, t.ExpectAnnotations, t.ExpectStatusCode, t.ExpectReinvokeWebhooks}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@ -404,7 +406,8 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest {
|
|||||||
AdmissionReviewVersions: []string{"v1beta1"},
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
}},
|
}},
|
||||||
|
|
||||||
ExpectAllow: true,
|
SkipBenchmark: true,
|
||||||
|
ExpectAllow: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "match & fail (but disallow because fail close on nil FailurePolicy)",
|
Name: "match & fail (but disallow because fail close on nil FailurePolicy)",
|
||||||
@ -499,7 +502,8 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest {
|
|||||||
ObjectSelector: &metav1.LabelSelector{},
|
ObjectSelector: &metav1.LabelSelector{},
|
||||||
AdmissionReviewVersions: []string{"v1beta1"},
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
}},
|
}},
|
||||||
ExpectAllow: true,
|
SkipBenchmark: true,
|
||||||
|
ExpectAllow: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "absent response and fail closed",
|
Name: "absent response and fail closed",
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@ -31,11 +30,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewTestServer returns a webhook test HTTPS server with fixed webhook test certs.
|
// NewTestServer returns a webhook test HTTPS server with fixed webhook test certs.
|
||||||
func NewTestServer(t *testing.T) *httptest.Server {
|
func NewTestServer(t testing.TB) *httptest.Server {
|
||||||
// Create the test webhook server
|
// Create the test webhook server
|
||||||
sCert, err := tls.X509KeyPair(testcerts.ServerCert, testcerts.ServerKey)
|
sCert, err := tls.X509KeyPair(testcerts.ServerCert, testcerts.ServerKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Error(err)
|
||||||
|
t.FailNow()
|
||||||
}
|
}
|
||||||
rootCAs := x509.NewCertPool()
|
rootCAs := x509.NewCertPool()
|
||||||
rootCAs.AppendCertsFromPEM(testcerts.CACert)
|
rootCAs.AppendCertsFromPEM(testcerts.CACert)
|
||||||
@ -49,7 +49,7 @@ func NewTestServer(t *testing.T) *httptest.Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func webhookHandler(w http.ResponseWriter, r *http.Request) {
|
func webhookHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Printf("got req: %v\n", r.URL.Path)
|
// fmt.Printf("got req: %v\n", r.URL.Path)
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/internalErr":
|
case "/internalErr":
|
||||||
http.Error(w, "webhook internal server error", http.StatusInternalServerError)
|
http.Error(w, "webhook internal server error", http.StatusInternalServerError)
|
||||||
|
@ -6,10 +6,7 @@ go_library(
|
|||||||
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util",
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util",
|
||||||
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook/util",
|
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook/util",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = ["//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library"],
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
@ -18,35 +18,8 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HookClientConfigForWebhook construct a webhookutil.ClientConfig using a WebhookAccessor to access
|
|
||||||
// v1beta1.MutatingWebhook and v1beta1.ValidatingWebhook API objects. webhookutil.ClientConfig is used
|
|
||||||
// to create a HookClient and the purpose of the config struct is to share that with other packages
|
|
||||||
// that need to create a HookClient.
|
|
||||||
func HookClientConfigForWebhook(w webhook.WebhookAccessor) webhookutil.ClientConfig {
|
|
||||||
ret := webhookutil.ClientConfig{Name: w.GetName(), CABundle: w.GetClientConfig().CABundle}
|
|
||||||
if w.GetClientConfig().URL != nil {
|
|
||||||
ret.URL = *w.GetClientConfig().URL
|
|
||||||
}
|
|
||||||
if w.GetClientConfig().Service != nil {
|
|
||||||
ret.Service = &webhookutil.ClientConfigService{
|
|
||||||
Name: w.GetClientConfig().Service.Name,
|
|
||||||
Namespace: w.GetClientConfig().Service.Namespace,
|
|
||||||
}
|
|
||||||
if w.GetClientConfig().Service.Port != nil {
|
|
||||||
ret.Service.Port = *w.GetClientConfig().Service.Port
|
|
||||||
} else {
|
|
||||||
ret.Service.Port = 443
|
|
||||||
}
|
|
||||||
if w.GetClientConfig().Service.Path != nil {
|
|
||||||
ret.Service.Path = *w.GetClientConfig().Service.Path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasAdmissionReviewVersion check whether a version is accepted by a given webhook.
|
// HasAdmissionReviewVersion check whether a version is accepted by a given webhook.
|
||||||
func HasAdmissionReviewVersion(a string, w webhook.WebhookAccessor) bool {
|
func HasAdmissionReviewVersion(a string, w webhook.WebhookAccessor) bool {
|
||||||
for _, b := range w.GetAdmissionReviewVersions() {
|
for _, b := range w.GetAdmissionReviewVersions() {
|
||||||
|
@ -22,7 +22,6 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request: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",
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
|
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
|
||||||
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"
|
|
||||||
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"
|
utiltrace "k8s.io/utils/trace"
|
||||||
@ -158,7 +157,7 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Validati
|
|||||||
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
|
||||||
}
|
}
|
||||||
// Make the webhook request
|
// Make the webhook request
|
||||||
client, err := d.cm.HookClient(util.HookClientConfigForWebhook(invocation.Webhook))
|
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: err}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package validating
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -29,6 +30,68 @@ import (
|
|||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BenchmarkValidate tests that ValidatingWebhook#Validate works as expected
|
||||||
|
func BenchmarkValidate(b *testing.B) {
|
||||||
|
testServerURL := os.Getenv("WEBHOOK_TEST_SERVER_URL")
|
||||||
|
if len(testServerURL) == 0 {
|
||||||
|
b.Log("warning, WEBHOOK_TEST_SERVER_URL not set, starting in-process server, benchmarks will include webhook cost.")
|
||||||
|
b.Log("to run a standalone server, run:")
|
||||||
|
b.Log("go run ./vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main/main.go")
|
||||||
|
testServer := webhooktesting.NewTestServer(b)
|
||||||
|
testServer.StartTLS()
|
||||||
|
defer testServer.Close()
|
||||||
|
testServerURL = testServer.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
|
||||||
|
|
||||||
|
serverURL, err := url.ParseRequestURI(testServerURL)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("this should never happen? %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stopCh := make(chan struct{})
|
||||||
|
defer close(stopCh)
|
||||||
|
|
||||||
|
for _, tt := range webhooktesting.NewNonMutatingTestCases(serverURL) {
|
||||||
|
// For now, skip failure cases or tests that explicitly skip benchmarking
|
||||||
|
if !tt.ExpectAllow || tt.SkipBenchmark {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run(tt.Name, func(b *testing.B) {
|
||||||
|
wh, err := NewValidatingAdmissionWebhook(nil)
|
||||||
|
if err != nil {
|
||||||
|
b.Errorf("%s: failed to create validating webhook: %v", tt.Name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ns := "webhook-test"
|
||||||
|
client, informer := webhooktesting.NewFakeValidatingDataSource(ns, tt.Webhooks, stopCh)
|
||||||
|
|
||||||
|
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
|
||||||
|
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
|
||||||
|
wh.SetExternalKubeClientSet(client)
|
||||||
|
wh.SetExternalKubeInformerFactory(informer)
|
||||||
|
|
||||||
|
informer.Start(stopCh)
|
||||||
|
informer.WaitForCacheSync(stopCh)
|
||||||
|
|
||||||
|
if err = wh.ValidateInitialization(); err != nil {
|
||||||
|
b.Errorf("%s: failed to validate initialization: %v", tt.Name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
wh.Validate(context.TODO(), attr, objectInterfaces)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestValidate tests that ValidatingWebhook#Validate works as expected
|
// TestValidate tests that ValidatingWebhook#Validate works as expected
|
||||||
func TestValidate(t *testing.T) {
|
func TestValidate(t *testing.T) {
|
||||||
testServer := webhooktesting.NewTestServer(t)
|
testServer := webhooktesting.NewTestServer(t)
|
||||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1282,7 +1282,6 @@ k8s.io/apiserver/pkg/admission/plugin/webhook/namespace
|
|||||||
k8s.io/apiserver/pkg/admission/plugin/webhook/object
|
k8s.io/apiserver/pkg/admission/plugin/webhook/object
|
||||||
k8s.io/apiserver/pkg/admission/plugin/webhook/request
|
k8s.io/apiserver/pkg/admission/plugin/webhook/request
|
||||||
k8s.io/apiserver/pkg/admission/plugin/webhook/rules
|
k8s.io/apiserver/pkg/admission/plugin/webhook/rules
|
||||||
k8s.io/apiserver/pkg/admission/plugin/webhook/util
|
|
||||||
k8s.io/apiserver/pkg/admission/plugin/webhook/validating
|
k8s.io/apiserver/pkg/admission/plugin/webhook/validating
|
||||||
k8s.io/apiserver/pkg/admission/testing
|
k8s.io/apiserver/pkg/admission/testing
|
||||||
k8s.io/apiserver/pkg/apis/apiserver
|
k8s.io/apiserver/pkg/apis/apiserver
|
||||||
|
Loading…
Reference in New Issue
Block a user