diff --git a/go.mod b/go.mod index ff9b5259e..ba742b435 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/component-base v0.37.0 k8s.io/klog/v2 v2.140.0 k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 - sigs.k8s.io/controller-runtime v0.25.1 + sigs.k8s.io/controller-runtime v0.25.2 ) require ( diff --git a/go.sum b/go.sum index baafc8f0a..1860da034 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,8 @@ k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0x k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 h1:/YpDJ4vReG7ZmzSpBGxduXgywWkJU9zHubgJG03MT+Y= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0/go.mod h1:tJo1aepTXyR+8Xs3sUsGBDk4Ub2AM5dPAPKJx0mpm5c= -sigs.k8s.io/controller-runtime v0.25.1 h1:BKgU9OeE8xv8EbbM8cY0NVzTQs35rokkdq1jh12fMb4= -sigs.k8s.io/controller-runtime v0.25.1/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc= +sigs.k8s.io/controller-runtime v0.25.2 h1:bEkK3PVOIVK9X8QWLGVhJgmFc++47vfT6wakSzAOLsQ= +sigs.k8s.io/controller-runtime v0.25.2/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc= sigs.k8s.io/json v0.0.0-20260909141634-11ed52e25bc5 h1:k9jo7ED/fsfOcz3L1P20P5tjTNtsdQNwMOG2aKzHrl8= sigs.k8s.io/json v0.0.0-20260909141634-11ed52e25bc5/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= diff --git a/vendor/modules.txt b/vendor/modules.txt index 5ead63ac8..3e054c76e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1426,7 +1426,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client -# sigs.k8s.io/controller-runtime v0.25.1 +# sigs.k8s.io/controller-runtime v0.25.2 ## explicit; go 1.26.0 sigs.k8s.io/controller-runtime sigs.k8s.io/controller-runtime/pkg/builder diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go index 23d6103f6..4fd3e92f1 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go @@ -108,6 +108,9 @@ type CacheOptions struct { // This is an experimental feature, a form of this will be kept but both the details of // how exactly it works and how exactly it is configured may change. // + // This feature does not work correctly when a resource has more than one Namespace + // configured. + // // Defaults to false. EnableReadYourWritesConsistency *bool } @@ -601,7 +604,7 @@ func (co *SubResourceCreateOptions) ApplyOptions(opts []SubResourceCreateOption) // ApplyToSubResourceCreate applies the the configuration on the given create options. func (co *SubResourceCreateOptions) ApplyToSubResourceCreate(o *SubResourceCreateOptions) { - co.CreateOptions.ApplyToCreate(&co.CreateOptions) + co.CreateOptions.ApplyToCreate(&o.CreateOptions) } // SubResourcePatchOptions holds all possible configurations for a subresource patch diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/consistency.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/consistency.go index 7cc311521..70d28a7f5 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/consistency.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/consistency.go @@ -24,8 +24,10 @@ import ( "strconv" "strings" "sync" + "time" "github.com/go-logr/logr" + "github.com/prometheus/client_golang/prometheus" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -37,8 +39,29 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/client/internal/consistencyhandler" "sigs.k8s.io/controller-runtime/pkg/client/internal/writebarrier" + crmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" ) +var ( + consistencyClientWaitDuration = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "controller_runtime_client_consistency_wait_duration_seconds", + Help: "Length of time waiting for the cache to observe writes before serving reads.", + Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2, 4, 6, 8, 10}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, + }, + []string{"operation", "result"}, + ) +) + +func init() { + crmetrics.Registry.MustRegister( + consistencyClientWaitDuration, + ) +} + type consistentClientUpstream interface { Client @@ -119,11 +142,39 @@ func (c *consistentClient) getConsistencyHandler( return h, nil } -func (c *consistentClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error { +const consistencyClientWaitDurationResultSuccess = "success" + +func consistencyClientWaitDurationResult(err error) string { + switch { + case errors.Is(err, context.DeadlineExceeded): + return "timeout" + case err != nil: + return "error" + default: + return consistencyClientWaitDurationResultSuccess + } +} + +func (c *consistentClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) (err error) { if (&GetOptions{}).ApplyOptions(opts).DisableReadYourWritesConsistency { return c.upstream.Get(ctx, key, obj, opts...) } + start := time.Now() + var waitDuration time.Duration + var result string + defer func() { + if waitDuration == 0 { + waitDuration = time.Since(start) + } + if result == "" { + result = consistencyClientWaitDurationResult(err) + } + consistencyClientWaitDuration. + WithLabelValues("get", result). + Observe(waitDuration.Seconds()) + }() + gvk, err := apiutil.GVKForObject(obj, c.upstream.Scheme()) if err != nil { return fmt.Errorf("failed to get GVK for object %T: %w", obj, err) @@ -144,14 +195,31 @@ func (c *consistentClient) Get(ctx context.Context, key ObjectKey, obj Object, o return fmt.Errorf("failed to wait for cache to catch up: %w", err) } + waitDuration = time.Since(start) + result = consistencyClientWaitDurationResultSuccess return c.upstream.Get(ctx, key, obj, opts...) } -func (c *consistentClient) List(ctx context.Context, list ObjectList, opts ...ListOption) error { +func (c *consistentClient) List(ctx context.Context, list ObjectList, opts ...ListOption) (err error) { if (&ListOptions{}).ApplyOptions(opts).DisableReadYourWritesConsistency { return c.upstream.List(ctx, list, opts...) } + start := time.Now() + var waitDuration time.Duration + var result string + defer func() { + if waitDuration == 0 { + waitDuration = time.Since(start) + } + if result == "" { + result = consistencyClientWaitDurationResult(err) + } + consistencyClientWaitDuration. + WithLabelValues("list", result). + Observe(waitDuration.Seconds()) + }() + gvk, err := apiutil.GVKForObject(list, c.upstream.Scheme()) if err != nil { return fmt.Errorf("failed to get GVK for list %T: %w", list, err) @@ -197,6 +265,8 @@ func (c *consistentClient) List(ctx context.Context, list ObjectList, opts ...Li return fmt.Errorf("failed to wait for cache to catch up: %w", err) } + waitDuration = time.Since(start) + result = consistencyClientWaitDurationResultSuccess return c.upstream.List(ctx, list, opts...) } diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go index 146757b1f..f3f6cbb1b 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go @@ -105,6 +105,10 @@ type Options struct { // This also allows providing a certificate via GetCertificate. TLSOpts []func(*tls.Config) + // HandlerOpts is used to allow configuring the promhttp handler used to serve metrics. + // These options are applied after the default handler options are set and can override them. + HandlerOpts []func(*promhttp.HandlerOpts) + // ListenConfig contains options for listening to an address on the metric server. ListenConfig net.ListenConfig } @@ -218,9 +222,7 @@ func (s *defaultServer) Start(ctx context.Context) error { mux := http.NewServeMux() - handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{ - ErrorHandling: promhttp.HTTPErrorOnError, - }) + handler := promhttp.HandlerFor(metrics.Registry, s.handlerOpts()) if s.metricsFilter != nil { log := log.WithValues("path", defaultMetricsEndpoint) var err error @@ -270,6 +272,16 @@ func (s *defaultServer) Start(ctx context.Context) error { return nil } +func (s *defaultServer) handlerOpts() promhttp.HandlerOpts { + handlerOpts := promhttp.HandlerOpts{ + ErrorHandling: promhttp.HTTPErrorOnError, + } + for _, op := range s.options.HandlerOpts { + op(&handlerOpts) + } + return handlerOpts +} + func (s *defaultServer) createListener(ctx context.Context, log logr.Logger) (net.Listener, error) { if !s.options.SecureServing { return s.options.ListenConfig.Listen(ctx, "tcp", s.options.BindAddress)