From 6c273020d3a5d1f74e6f948f4ed7938ce78bd34b Mon Sep 17 00:00:00 2001 From: Tim Allclair Date: Tue, 26 Oct 2021 18:49:13 -0700 Subject: [PATCH] [PodSecurity] Avoid the LegcayRegistry for metrics serving --- .../security/podsecurity/admission.go | 18 +++++++++++++-- .../cmd/webhook/server/server.go | 13 +++++++---- .../pod-security-admission/metrics/metrics.go | 23 +++---------------- test/integration/auth/podsecurity_test.go | 4 ++++ 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/plugin/pkg/admission/security/podsecurity/admission.go b/plugin/pkg/admission/security/podsecurity/admission.go index 3407c42038e..f4b4859e34f 100644 --- a/plugin/pkg/admission/security/podsecurity/admission.go +++ b/plugin/pkg/admission/security/podsecurity/admission.go @@ -43,6 +43,7 @@ import ( "k8s.io/client-go/kubernetes" corev1listers "k8s.io/client-go/listers/core/v1" "k8s.io/component-base/featuregate" + "k8s.io/component-base/metrics/legacyregistry" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/batch" @@ -83,6 +84,20 @@ var _ admission.ValidationInterface = &Plugin{} var _ genericadmissioninit.WantsExternalKubeInformerFactory = &Plugin{} var _ genericadmissioninit.WantsExternalKubeClientSet = &Plugin{} +var ( + defaultRecorder *metrics.PrometheusRecorder + defaultRecorderInit sync.Once +) + +func getDefaultRecorder() metrics.Recorder { + // initialize and register to legacy metrics once + defaultRecorderInit.Do(func() { + defaultRecorder = metrics.NewPrometheusRecorder(podsecurityadmissionapi.GetAPIVersion()) + defaultRecorder.MustRegister(legacyregistry.MustRegister) + }) + return defaultRecorder +} + // newPlugin creates a new admission plugin. func newPlugin(reader io.Reader) (*Plugin, error) { config, err := podsecurityconfigloader.LoadFromReader(reader) @@ -94,14 +109,13 @@ func newPlugin(reader io.Reader) (*Plugin, error) { if err != nil { return nil, fmt.Errorf("could not create PodSecurityRegistry: %w", err) } - metrics.LegacyMustRegister() return &Plugin{ Handler: admission.NewHandler(admission.Create, admission.Update), delegate: &podsecurityadmission.Admission{ Configuration: config, Evaluator: evaluator, - Metrics: metrics.DefaultRecorder(), + Metrics: getDefaultRecorder(), PodSpecExtractor: podsecurityadmission.DefaultPodSpecExtractor{}, }, }, nil diff --git a/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go b/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go index 21b50b0db7a..8ea6d5cf202 100644 --- a/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go +++ b/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go @@ -41,7 +41,6 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" compbasemetrics "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" "k8s.io/component-base/version/verflag" "k8s.io/klog/v2" "k8s.io/pod-security-admission/admission" @@ -107,6 +106,8 @@ type Server struct { informerFactory kubeinformers.SharedInformerFactory delegate *admission.Admission + + metricsRegistry compbasemetrics.KubeRegistry } func (s *Server) Start(ctx context.Context) error { @@ -119,10 +120,9 @@ func (s *Server) Start(ctx context.Context) error { // debugging or proxy purposes. The API server will not connect to an http webhook. mux.HandleFunc("/", s.HandleValidate) - // Serve the global metrics registry. - metrics.LegacyMustRegister() + // Serve the metrics. mux.Handle("/metrics", - compbasemetrics.HandlerFor(legacyregistry.DefaultGatherer, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError})) + compbasemetrics.HandlerFor(s.metricsRegistry, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError})) if s.insecureServing != nil { if err := s.insecureServing.Serve(mux, 0, ctx.Done()); err != nil { @@ -279,11 +279,14 @@ func Setup(c *Config) (*Server, error) { if err != nil { return nil, fmt.Errorf("could not create PodSecurityRegistry: %w", err) } + metrics := metrics.NewPrometheusRecorder(api.GetAPIVersion()) + s.metricsRegistry = compbasemetrics.NewKubeRegistry() + metrics.MustRegister(s.metricsRegistry.MustRegister) s.delegate = &admission.Admission{ Configuration: c.PodSecurityConfig, Evaluator: evaluator, - Metrics: metrics.DefaultRecorder(), + Metrics: metrics, PodSpecExtractor: admission.DefaultPodSpecExtractor{}, PodLister: admission.PodListerFromClient(client), NamespaceGetter: admission.NamespaceGetterFromListerAndClient(namespaceLister, client), diff --git a/staging/src/k8s.io/pod-security-admission/metrics/metrics.go b/staging/src/k8s.io/pod-security-admission/metrics/metrics.go index f84388a736b..d6ab481f098 100644 --- a/staging/src/k8s.io/pod-security-admission/metrics/metrics.go +++ b/staging/src/k8s.io/pod-security-admission/metrics/metrics.go @@ -19,13 +19,11 @@ package metrics import ( "strconv" "strings" - "sync" admissionv1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" "k8s.io/pod-security-admission/api" ) @@ -46,25 +44,12 @@ type Recorder interface { RecordError(fatal bool, attrs api.Attributes) } -var defaultRecorder = NewPrometheusRecorder(api.GetAPIVersion()) - -func DefaultRecorder() Recorder { - return defaultRecorder -} - -// MustRegister registers the global DefaultMetrics against the legacy registry. -func LegacyMustRegister() { - defaultRecorder.MustRegister(legacyregistry.MustRegister) -} - type PrometheusRecorder struct { apiVersion api.Version evaluationsCounter *metrics.CounterVec exemptionsCounter *metrics.CounterVec errorsCounter *metrics.CounterVec - - registerOnce sync.Once } var _ Recorder = &PrometheusRecorder{} @@ -104,11 +89,9 @@ func NewPrometheusRecorder(version api.Version) *PrometheusRecorder { } func (r *PrometheusRecorder) MustRegister(registerFunc func(...metrics.Registerable)) { - r.registerOnce.Do(func() { - registerFunc(r.evaluationsCounter) - registerFunc(r.exemptionsCounter) - registerFunc(r.errorsCounter) - }) + registerFunc(r.evaluationsCounter) + registerFunc(r.exemptionsCounter) + registerFunc(r.errorsCounter) } func (r *PrometheusRecorder) Reset() { diff --git a/test/integration/auth/podsecurity_test.go b/test/integration/auth/podsecurity_test.go index 4acdcde7d3e..ad7c8e215ca 100644 --- a/test/integration/auth/podsecurity_test.go +++ b/test/integration/auth/podsecurity_test.go @@ -342,4 +342,8 @@ func validateMetrics(t *testing.T, rawMetrics []byte) { "decision", "policy_level", "policy_version", "mode", "request_operation", "resource", "subresource"); err != nil { t.Errorf("Metric validation failed: %v", err) } + if err := testutil.ValidateMetrics(metrics, "pod_security_exemptions_total", + "request_operation", "resource", "subresource"); err != nil { + t.Errorf("Metric validation failed: %v", err) + } }