From 39011961f4ffc16639547d3bf23f4ba7dc9c4081 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Tue, 16 Jun 2026 17:47:08 -0700 Subject: [PATCH 1/5] feat(storage): registry dispatch via --storage-backend (KPEP-0001 phase 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires the apiserver to KPEP-0001's pluggable storage backend registry. The apiserver has zero Spanner-specific code — it imports the aggregator package kplane-dev/storage/backends, constructs a *registry.Backends in NewServerRunOptions(), and dispatches via --storage-backend at startup. What this does: - cmd/apiserver/app/options/options.go: - Imports kplane-dev/storage/backends + .../registry. - Adds Extra.StorageBackend (default 'etcd3') and Extra.Backends. - NewServerRunOptions() calls storagebackends.RegisterBuiltin(b) so every in-tree backend's Options is registered before flag parse. - Flags() binds --storage-backend and fans out s.Backends.AddFlags(fs) so every backend's per-flag block appears in --help. - cmd/apiserver/app/config.go: after building mcOpts, looks up the selected backend by name, calls Validate + Build, and installs the resulting registry.Factory on mcOpts.BackendFactory. --storage-backend values of 'etcd3' or empty short-circuit (legacy etcd3 path; no factory installed). Non-etcd backends also flip storagefeature.SetFeatureSupported(RequestWatchProgress, true) so the cacher allows SendInitialEvents watches. - pkg/multicluster/options.go: adds Options.BackendFactory (set by config.go) plumbing the dispatch result down to storage.go. - pkg/multicluster/storage.go: passes mcOpts.BackendFactory through to extstorage.DecoratorConfig.BackendFactory. nil keeps the etcd3 path; non-nil swaps in the registry's chosen Factory. go.mod bumps: - kplane-dev/storage pinned to PR #2 head (registry + DecoratorConfig hook + backends/spanner/ migration + aggregator). - k8s.io/* and k8s.io/kubernetes pinned to feat/per-cluster-allocators (32f5e9075db5) which has the prerequisite storage.WithDecodeCallback move. KPEP conformance check (vs. design doc): - Apiserver source contains no string 'spanner' / 'Spanner' / 'spanner-*': grep -rn 'spanner\|Spanner' cmd/ pkg/ → empty. - The apiserver imports the aggregator, not a specific backend. Adding postgres / kine etc. requires zero apiserver changes — only an additional Register() call in kplane-dev/storage/backends/register.go. - Each backend's ---* flags come from its own AddFlags via the fan-out, matching the upstream pattern (--etcd-* belong to etcd, etc.). Tested: - bin/kplane-apiserver --help shows --storage-backend + every backend's flag block (currently just --spanner-*). E2E test loop (kubectl against a real apiserver) documented in docs/design-kpep-0001-test-loop.md (next commit). --- cmd/apiserver/app/config.go | 31 ++++ cmd/apiserver/app/options/options.go | 34 ++++ go.mod | 80 ++++++--- go.sum | 243 ++++++++++++++++++++------- pkg/multicluster/options.go | 6 + pkg/multicluster/storage.go | 5 +- 6 files changed, 309 insertions(+), 90 deletions(-) diff --git a/cmd/apiserver/app/config.go b/cmd/apiserver/app/config.go index fdeb4c1..98b35b7 100644 --- a/cmd/apiserver/app/config.go +++ b/cmd/apiserver/app/config.go @@ -18,6 +18,7 @@ package app import ( "context" + "fmt" "net/http" "reflect" "strings" @@ -32,6 +33,8 @@ import ( genericfilters "k8s.io/apiserver/pkg/endpoints/filters" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/storage" + storagefeature "k8s.io/apiserver/pkg/storage/feature" serverfilters "k8s.io/apiserver/pkg/server/filters" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/pkg/util/webhook" @@ -129,6 +132,34 @@ func NewConfig(opts options.CompletedOptions) (*Config, error) { clientPool := mc.NewClientPool(genericConfig.LoopbackClientConfig, mcOpts.PathPrefix, mcOpts.ControlPlaneSegment) informerRegistry := mc.NewInformerRegistry(wait.ContextForChannel(genericConfig.DrainedNotify())) mcOpts.InformerRegistry = informerRegistry + + // KPEP-0001 storage backend dispatch. Resolve the registered backend + // named by --storage-backend, validate, build, and install the + // resulting Factory on mcOpts so the storage decorator uses it + // instead of the upstream etcd3 path. "etcd3" (or empty) keeps + // mcOpts.BackendFactory nil and falls through to etcd3 transparently. + if opts.StorageBackend != "" && opts.StorageBackend != "etcd3" { + backend, ok := opts.Backends.Get(opts.StorageBackend) + if !ok { + return nil, fmt.Errorf( + "unknown --storage-backend=%q (registered: %v)", + opts.StorageBackend, opts.Backends.Names(), + ) + } + if errs := backend.Validate(); len(errs) > 0 { + return nil, fmt.Errorf("validating --storage-backend=%q: %v", opts.StorageBackend, errs) + } + factory, err := backend.Build() + if err != nil { + return nil, fmt.Errorf("building --storage-backend=%q: %w", opts.StorageBackend, err) + } + mcOpts.BackendFactory = factory + // Non-etcd backends typically implement RequestWatchProgress + // natively (Spanner via its broadcaster). Tell the feature + // checker so the cacher allows SendInitialEvents watches. + storagefeature.SetFeatureSupported(storage.RequestWatchProgress, true) + } + var crdRuntimeMgr *mcbootstrap.CRDRuntimeManager systemNamespaceBootstrapper := mcbootstrap.NewSystemNamespaceBootstrapper(mcbootstrap.SystemNamespaceOptions{ ClientForCluster: clientPool.KubeClientForCluster, diff --git a/cmd/apiserver/app/options/options.go b/cmd/apiserver/app/options/options.go index 85a438a..375c22d 100644 --- a/cmd/apiserver/app/options/options.go +++ b/cmd/apiserver/app/options/options.go @@ -23,6 +23,8 @@ import ( "time" mc "github.com/kplane-dev/apiserver/pkg/multicluster" + storagebackends "github.com/kplane-dev/storage/backends" + "github.com/kplane-dev/storage/registry" v1 "k8s.io/api/core/v1" utilnet "k8s.io/apimachinery/pkg/util/net" cliflag "k8s.io/component-base/cli/flag" @@ -64,6 +66,25 @@ type Extra struct { EndpointReconcilerType string MasterCount int + + // StorageBackend selects which registered storage backend serves the + // multicluster data plane. Defaults to "etcd3" (the legacy path); + // other valid values are whatever backends are registered into + // Backends via storagebackends.RegisterBuiltin (or by an out-of-tree + // custom apiserver that registers more before Validate runs). + // + // KPEP-0001: this is the single dispatch knob. Per-backend flags + // (--spanner-project, future --postgres-dsn, etc.) come from the + // backend's own AddFlags, fanned out by Backends.AddFlags. The + // apiserver options layer never names a specific backend. + StorageBackend string + + // Backends is the instance-scoped registry of available storage + // backends. The default set is populated in NewServerRunOptions via + // storagebackends.RegisterBuiltin. Custom apiservers can call + // Backends.Register(.NewOptions()) on the returned value + // before Flags() is invoked. + Backends *registry.Backends } const ( @@ -75,10 +96,15 @@ const ( // NewServerRunOptions creates and returns ServerRunOptions according to the given featureGate and effectiveVersion of the server binary to run. func NewServerRunOptions() *ServerRunOptions { + backends := registry.New() + storagebackends.RegisterBuiltin(backends) + s := ServerRunOptions{ Options: controlplaneapiserver.NewOptions(), Extra: Extra{ + StorageBackend: "etcd3", + Backends: backends, EndpointReconcilerType: string(reconcilers.LeaseEndpointReconcilerType), KubeletConfig: kubeletclient.KubeletClientConfig{ Port: ports.KubeletPort, @@ -124,6 +150,14 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) { mcfs.StringVar(&s.ServiceCIDRSharingMode, "service-cidr-sharing-mode", s.ServiceCIDRSharingMode, "Service CIDR strategy across control planes: 'shared' keeps root-managed defaults only; 'per-cluster' bootstraps default ServiceCIDR in each virtual control plane.") + // KPEP-0001 storage backend dispatch. Picks which registered backend + // services multicluster storage; backend-specific flags (e.g. + // --spanner-project) are bound by each backend's AddFlags below. + storagefs := fss.FlagSet("storage backend") + storagefs.StringVar(&s.StorageBackend, "storage-backend", s.StorageBackend, + "Storage backend for multicluster data. One of: "+strings.Join(s.Backends.Names(), ", ")+". Defaults to 'etcd3'.") + s.Backends.AddFlags(storagefs) + fs := fss.FlagSet("misc") fs.BoolVar(&s.AllowPrivileged, "allow-privileged", s.AllowPrivileged, diff --git a/go.mod b/go.mod index 24c66d8..c506d25 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,14 @@ module github.com/kplane-dev/apiserver -go 1.25.0 +go 1.25.8 require ( github.com/kplane-dev/informer v0.0.0-00010101000000-000000000000 github.com/kplane-dev/storage v0.0.0 github.com/spf13/cobra v1.10.1 go.etcd.io/etcd/client/v3 v3.6.7 - go.opentelemetry.io/otel v1.40.0 - golang.org/x/sync v0.19.0 + go.opentelemetry.io/otel v1.44.0 + golang.org/x/sync v0.21.0 gopkg.in/evanphx/json-patch.v4 v4.13.0 k8s.io/api v0.34.1 k8s.io/apiextensions-apiserver v0.34.1 @@ -24,17 +24,17 @@ require ( replace ( github.com/kplane-dev/informer => github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b - github.com/kplane-dev/storage => github.com/kplane-dev/storage v0.0.0-20260404055526-b175d95c9fe7 - k8s.io/api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260404055358-aac72e7d04ad + github.com/kplane-dev/storage => github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3 + k8s.io/api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5 k8s.io/apiextensions-apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad - k8s.io/apimachinery => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260404055358-aac72e7d04ad - k8s.io/apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260404055358-aac72e7d04ad + k8s.io/apimachinery => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5 + k8s.io/apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5 k8s.io/cli-runtime => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20260404055358-aac72e7d04ad - k8s.io/client-go => github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260404055358-aac72e7d04ad + k8s.io/client-go => github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5 k8s.io/cloud-provider => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad k8s.io/cluster-bootstrap => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad k8s.io/code-generator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20260404055358-aac72e7d04ad - k8s.io/component-base => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260404055358-aac72e7d04ad + k8s.io/component-base => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5 k8s.io/component-helpers => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad k8s.io/controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260404055358-aac72e7d04ad k8s.io/cri-api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260404055358-aac72e7d04ad @@ -43,14 +43,14 @@ replace ( k8s.io/dynamic-resource-allocation => github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260404055358-aac72e7d04ad k8s.io/endpointslice => github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260404055358-aac72e7d04ad k8s.io/externaljwt => github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kms => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260404055358-aac72e7d04ad + k8s.io/kms => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5 k8s.io/kube-aggregator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad k8s.io/kube-controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260404055358-aac72e7d04ad k8s.io/kube-proxy => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260404055358-aac72e7d04ad k8s.io/kube-scheduler => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260404055358-aac72e7d04ad k8s.io/kubectl => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260404055358-aac72e7d04ad k8s.io/kubelet => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kubernetes => github.com/kplane-dev/kubernetes v0.0.0-20260404055358-aac72e7d04ad + k8s.io/kubernetes => github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5 k8s.io/metrics => github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260404055358-aac72e7d04ad k8s.io/mount-utils => github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260404055358-aac72e7d04ad k8s.io/pod-security-admission => github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad @@ -60,15 +60,26 @@ replace ( ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.20.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.11.0 // indirect + cloud.google.com/go/longrunning v1.0.0 // indirect + cloud.google.com/go/monitoring v1.29.0 // indirect + cloud.google.com/go/spanner v1.88.0 // indirect cyphar.com/go-pathrs v0.2.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.6.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect github.com/coreos/go-oidc v2.5.0+incompatible // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.7.0 // indirect @@ -76,9 +87,12 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect @@ -100,7 +114,10 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.16 // indirect + github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect @@ -119,6 +136,7 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/selinux v1.13.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/cachecontrol v0.2.0 // indirect github.com/prometheus/client_golang v1.23.2 // indirect @@ -127,35 +145,41 @@ require ( github.com/prometheus/procfs v0.19.2 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/spf13/pflag v1.0.10 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/etcd/api/v3 v3.6.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.6.7 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.53.0 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect - golang.org/x/net v0.49.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.40.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/grpc v1.78.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.38.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.45.0 // indirect + google.golang.org/api v0.285.0 // indirect + google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad // indirect + google.golang.org/grpc v1.81.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 00b883f..389b1ac 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,31 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA= +cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.11.0 h1:KieQ9Pb+LLPak1O3Rv3GgCxhnmkYf7Xyh0P5HfF1jFM= +cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4= +cloud.google.com/go/longrunning v1.0.0 h1:lwzWEYD8+NkYV7dhexOz6kmlvajZA70+bW/xMhRVVdY= +cloud.google.com/go/longrunning v1.0.0/go.mod h1:8nqFBPOO1U/XkhWl0I19AMZEphrHi73VNABIpKYaTwM= +cloud.google.com/go/monitoring v1.29.0 h1:AHhDsFaSax1/4k+qlIDX/SDGe6hggnfXJ9dkgD9qBPY= +cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM= +cloud.google.com/go/spanner v1.88.0 h1:HS+5TuEYZOVOXj9K+0EtrbTw7bKBLrMe3vgGsbnehmU= +cloud.google.com/go/spanner v1.88.0/go.mod h1:MzulBwuuYwQUVdkZXBBFapmXee3N+sQrj2T/yup6uEE= cyphar.com/go-pathrs v0.2.2 h1:y9w7hxbkr3zEL78Fjzeg4HEhs2xNy+fbwHiHGJJY2Xo= cyphar.com/go-pathrs v0.2.2/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.6.0 h1:BzsL0qE7LvtTEtXG7Dt5NS1EP0CQwI21HZfj9aGghhw= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.6.0/go.mod h1:I7kE2kM3qCr9QPT4cU4cCFYkEpVyVr16YOGUHzy+nR0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -20,8 +42,13 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/coreos/go-oidc v2.5.0+incompatible h1:6W0vGJR3Tu0r0PwfmjOrRZSlfxeEln8dsejt3ZWIvwo= github.com/coreos/go-oidc v2.5.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -43,12 +70,26 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= +github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -90,6 +131,22 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -98,13 +155,26 @@ github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.16 h1:F/VPrx0YPBdksZJQdCAp0WUsqnNmZpUZszzfYt0M5Dw= +github.com/googleapis/enterprise-certificate-proxy v0.3.16/go.mod h1:9Yb0eAkH/Xqhvv3zbeKf/+wMJqCeocWc6KIhDvEAuYE= +github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= +github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= @@ -127,24 +197,24 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b h1:Z1+b+fPm/I2STcdIT3Psb3OYng2xYYILMmdgD55KEm8= github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b/go.mod h1:y+IpeQX/vAaf7h6d+fwTYQ9kqdpwJdjHCc5KuN4JcC4= -github.com/kplane-dev/kubernetes v0.0.0-20260404055358-aac72e7d04ad h1:249TYMHw60P6D58XGVjf7G2TNp708zRyNa0RbXfQAUQ= -github.com/kplane-dev/kubernetes v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:9uEdeMBkUjkGSL2ioy2pKr0+aLNIvmOan7p8F7ENHbk= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260404055358-aac72e7d04ad h1:0k/XM+mWOjNWWmc/HkYP5qYcIw72vssnGhS6i7jidBE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:KOrdwhDi3QHVXr50HAWBhO2r9uMtWbO46CiIHzRVtU8= +github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5 h1:uCHzOMe1b0TocxFY2ynt9LHaR98P8uhzjZKJTIEFGrg= +github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5/go.mod h1:9uEdeMBkUjkGSL2ioy2pKr0+aLNIvmOan7p8F7ENHbk= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5 h1:VGSKAidEijlXCza8zQ6pdFZz9QczfT98wBox+qRTaxc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5/go.mod h1:KOrdwhDi3QHVXr50HAWBhO2r9uMtWbO46CiIHzRVtU8= github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad h1:XLq9ewx7uGAHa18cYQ1juWA/2dgrp4/bct+38M2XSuQ= github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:wZyuUfbqWsRKO42GvZVHZSJ0JttMO7YrXnu/bv/GqPg= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260404055358-aac72e7d04ad h1:hR3yKcG3v2+mjQEMME/9piLycd/Ry7JKtzVGB76satk= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:7mgr/dli8ofwAbcIQXetFVX1fbOYsOYojq3AUbybVmQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260404055358-aac72e7d04ad h1:mWkFOi6/+Ttf9RzcReo+0Om1AFJDTrHzxnfIWueiTRQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:GNWcUSRqjpm4i1hrLaGA7EQrl60YdahMic4aS+WUQVI= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260404055358-aac72e7d04ad h1:OhrfiUM1g6sHUohSTgiWoTwXfl1fg2He51+X0KneB8c= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:7IM9p4c8CafSxF7ZY0F46WHylFn3o4mLVW5T1VZbaY8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5 h1:FdV1ooo4kmNti8PMOwjuzMgP+HaUjggCVW502sdMbV8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5/go.mod h1:7mgr/dli8ofwAbcIQXetFVX1fbOYsOYojq3AUbybVmQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5 h1:B32q2wQIQLDhK8jhqRgRIBUZS2WoSEYYFau0dh9pl/g= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5/go.mod h1:GNWcUSRqjpm4i1hrLaGA7EQrl60YdahMic4aS+WUQVI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5 h1:g1Cgzs09gUaCwXCtSzWJS5rFYaK1ycHKruIpwuCJJtI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5/go.mod h1:7IM9p4c8CafSxF7ZY0F46WHylFn3o4mLVW5T1VZbaY8= github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad h1:J8CwRPJ1ehjMrT0UbH2cUaXDTUfJ7W7JVRkMumWKukw= github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:bGWrOCyYWe9G/1zpB0hSLAO+BnZUNbNVWXcHAzfaF+E= github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad h1:BH4eKNGN6ep4PQzAOya7Y2tqFui5jvl95jelztrCl1s= github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:CxFNOU1/U4gfM4SU7hRkzCRhTfUweuTLRWKWh6yitcE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260404055358-aac72e7d04ad h1:msldiJV5olCNfzoFD7pMKFMa1D0DTMWbASyAS4fxMEs= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:R6vYa1XRfX3PdQEGNkCaL3pt7NvLU2ti7FPzsEsA6GQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5 h1:l4RLyYStWu+BL8uKL++4byqPwLc2cv76rnHW/7A+Cvw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5/go.mod h1:R6vYa1XRfX3PdQEGNkCaL3pt7NvLU2ti7FPzsEsA6GQ= github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad h1:y+O0nFoSa7+0Z9HAfB0ffVjTiUxETsGzmi7vS3m7HWQ= github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:axBpPWJYMZFstDUXj45ooTW3njLMa7B8Kz8o4QY5xfk= github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260404055358-aac72e7d04ad h1:5bXsA+t0Qj8s/qLCB1ZWbjZTBLNYXbW2wLG+XrSiVhI= @@ -161,8 +231,8 @@ github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-2026040 github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:fdIUBx+W5Ypy0TBvfW8qonHr4QV3iXw+N+ADcGYf8eI= github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad h1:dGtsABtyNZPtY696j/WnFHM8mTaMNw0KJgbCxO4lG6c= github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:+8tzBBizhTus+bM0JPY/4h2O26NxIQgcEBdK5Xdfehc= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260404055358-aac72e7d04ad h1:F5GG5dhOffoOm+4jG94RLGaaFdKKO0nPiJCCqTHn8h8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:rhO9JHsWibaRLx12/ViuMQdeZi43hsiXCl8KEEihjaw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5 h1:vjbNa+ypXFTpVWOqfx1ft5to/rTcIEgIo9prLbgApzE= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5/go.mod h1:rhO9JHsWibaRLx12/ViuMQdeZi43hsiXCl8KEEihjaw= github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad h1:0cEi7M+eIESF+kWiEHnL7/kirpbvEn/b2asLQSZHx3o= github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:KXJ9MlZYxlzOWKhHqfdxOTDdmfk/+ftdOwN//JGQs0g= github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260404055358-aac72e7d04ad h1:BZew8n8DewnquBgR4mEKdgvoq3EVV3/4EMyW37KAd+8= @@ -181,8 +251,8 @@ github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-202604040 github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:0tRkeDDp5zQDR/JKhcttJMwq3mTWqNm5GE2DgjfRvsY= github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad h1:d51TIux4RCxVjdYsZnyyQcwiA/h1R7hTlH5s80Ylzp8= github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:2Hv3+Ga3SCWHO9E8+Ym58CioDvWe7wW21gy3nVetVNw= -github.com/kplane-dev/storage v0.0.0-20260404055526-b175d95c9fe7 h1:mvqa9LueCYKUDY/2Hsrg4E7/UwtFcps5dAua31PgS+0= -github.com/kplane-dev/storage v0.0.0-20260404055526-b175d95c9fe7/go.mod h1:add4/uRzmN2LrWjbWvoEGfIFBD5E1gfG+FJ/V/JN8SI= +github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3 h1:3yv8oDTgHzDJcnNxIVwlX6krOMJXqxirMJ0kgwsb+aU= +github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3/go.mod h1:C7jzKCXDJNzfLiTRTK48EOmIAhme7FGzLmIc/mfIOj0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -215,6 +285,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE= github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -222,6 +294,7 @@ github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEn github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= @@ -242,6 +315,8 @@ github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4 github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -278,26 +353,32 @@ go.etcd.io/etcd/server/v3 v3.6.7 h1:8dEGQ877tj0cQJFEfD2bDoZDA76qbS2OkvCNjwAyrSo= go.etcd.io/etcd/server/v3 v3.6.7/go.mod h1:LEM328bPA2uVMhN0+Ht/vAsADW127QS1oM7EuHrOTy0= go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/contrib/detectors/gcp v1.42.0 h1:kpt2PEJuOuqYkPcktfJqWWDjTEd/FNgrxcniL7kQrXQ= +go.opentelemetry.io/contrib/detectors/gcp v1.42.0/go.mod h1:W9zQ439utxymRrXsUOzZbFX4JhLxXU4+ZnCt8GG7yA8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -313,59 +394,99 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= -google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.285.0 h1:B7eHHoKGAX/LrPkQvhQqnGwjgWxofbdGwCTQvpm8FkM= +google.golang.org/api v0.285.0/go.mod h1:NlOlUIr8MPoIhT9Bb/oUnRuHbJOLwxb6JSYJM8Yz+jQ= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad h1:45WmJvIV6C2+O/jjLkPUH+F3aOj/1miDoU2DD0+NWbg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -382,6 +503,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY= diff --git a/pkg/multicluster/options.go b/pkg/multicluster/options.go index a69259f..b44907c 100644 --- a/pkg/multicluster/options.go +++ b/pkg/multicluster/options.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/kplane-dev/apiserver/pkg/multicluster/internalcap" + extstorage "github.com/kplane-dev/storage" apirequest "k8s.io/apiserver/pkg/endpoints/request" ) @@ -34,6 +35,11 @@ type Options struct { // InformerRegistry provides MultiClusterInformer instances for resource types. // Set by config.go and used by storage.go to register clusteredStorage instances. InformerRegistry *InformerRegistry + // BackendFactory, when non-nil, installs a non-etcd storage backend + // into every per-resource storage decorator. Set by config.go after + // resolving --storage-backend through the KPEP-0001 registry; nil + // preserves the upstream etcd3 path. + BackendFactory extstorage.BackendFactory } // ResourceScope defines which keyspace view a request should use. diff --git a/pkg/multicluster/storage.go b/pkg/multicluster/storage.go index f78328d..9353a74 100644 --- a/pkg/multicluster/storage.go +++ b/pkg/multicluster/storage.go @@ -72,8 +72,9 @@ func (w RESTOptionsDecorator) GetRESTOptions(resource schema.GroupResource, exam // sets WrapDecodedObject on the etcd3 storage config so that decoded // objects carry their storage key through the watch.Event boundary. base := extstorage.StorageWithClusterIdentity(extstorage.DecoratorConfig{ - KeyLayout: extstorage.DefaultKeyLayout(), - GroupResource: resource, + KeyLayout: extstorage.DefaultKeyLayout(), + GroupResource: resource, + BackendFactory: w.Options.BackendFactory, }) base = wrapBaseDecorator(base, w.Options) opts.Decorator = func( From 8cde8ed9b951378512878235d525b9f06ceee4d8 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Mon, 29 Jun 2026 12:04:50 -0700 Subject: [PATCH 2/5] feat: register backend with fork factory so internal stores hit Spanner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KPEP-0001 Option C wiring. When --storage-backend= is passed: - Options.Complete (options/completion.go) resolves the registered backend from opts.Backends, calls Validate, builds the factory.Backend via the new BuildFactoryBackend hook, and calls factory.Register(name, backend). Registration must happen here, not in config.go, because upstream EtcdOptions.Validate runs between Complete and BuildGenericConfig and rejects unknown --storage-backend values unless factory.IsRegistered reports them. The backend name comes from s.Etcd.StorageConfig.Type — the field upstream EtcdOptions binds --storage-backend to — so kplane doesn't introduce a second pflag for the same flag name. - config.go now only handles CR storage: it calls backend.Build() and installs the resulting Factory on mcOpts.BackendFactory for the multicluster decorator. spanner.Options.Build reuses the FactoryBackend built in Complete (one shared spanner.Client per process). Also removes a non-deterministic flag-routing bug: the previous version registered a second --storage-backend pflag in kplane's Flags() pointing at a separate Extra.StorageBackend field, alongside upstream EtcdOptions's own --storage-backend flag pointing at Etcd.StorageConfig.Type. pflag's NamedFlagSets merge silently collapses duplicate registrations, but which destination pointer wins depends on the order flag-sets are added — so half the time the user's --storage-backend=spanner landed on the kplane field and left Etcd.StorageConfig.Type empty (apiserver started, but internal callers dispatched to etcd3 because Type was unset); the other half it landed on Etcd.StorageConfig.Type with kplane's field empty (Complete skipped Register, upstream Validate rejected the backend). The kplane field and flag registration are removed; the single source of truth is now Etcd.StorageConfig.Type. Test in flags_test.go pins this. After this change, master/peer endpoint leases, service IP/NodePort allocators, and CR storage all flow through the same Spanner backend. No etcd alongside. The "etcd3" / "etcd2" / empty default path is unchanged. Refs: KPEP-0001 --- cmd/apiserver/app/config.go | 32 +++++++------- cmd/apiserver/app/options/completion.go | 37 +++++++++++++++++ cmd/apiserver/app/options/flags_test.go | 55 +++++++++++++++++++++++++ cmd/apiserver/app/options/options.go | 25 ++++------- 4 files changed, 117 insertions(+), 32 deletions(-) create mode 100644 cmd/apiserver/app/options/flags_test.go diff --git a/cmd/apiserver/app/config.go b/cmd/apiserver/app/config.go index 98b35b7..1dda099 100644 --- a/cmd/apiserver/app/config.go +++ b/cmd/apiserver/app/config.go @@ -133,27 +133,31 @@ func NewConfig(opts options.CompletedOptions) (*Config, error) { informerRegistry := mc.NewInformerRegistry(wait.ContextForChannel(genericConfig.DrainedNotify())) mcOpts.InformerRegistry = informerRegistry - // KPEP-0001 storage backend dispatch. Resolve the registered backend - // named by --storage-backend, validate, build, and install the - // resulting Factory on mcOpts so the storage decorator uses it - // instead of the upstream etcd3 path. "etcd3" (or empty) keeps - // mcOpts.BackendFactory nil and falls through to etcd3 transparently. - if opts.StorageBackend != "" && opts.StorageBackend != "etcd3" { - backend, ok := opts.Backends.Get(opts.StorageBackend) + // KPEP-0001 storage backend dispatch. Options.Complete has already + // registered the selected backend with the fork's factory registry + // (so upstream EtcdOptions.Validate passed and every internal + // factory.Create callsite — master/peer endpoint leases, service IP/ + // NodePort allocators — dispatches to it at runtime). Here we install + // the same backend's CR-storage Factory on the multicluster decorator + // hook. spanner.Options.Build reuses the FactoryBackend created in + // Complete (one shared spanner.Client per process). + backendName := "" + if opts.Etcd != nil { + backendName = opts.Etcd.StorageConfig.Type + } + if backendName != "" && backendName != "etcd3" && backendName != "etcd2" { + backend, ok := opts.Backends.Get(backendName) if !ok { return nil, fmt.Errorf( "unknown --storage-backend=%q (registered: %v)", - opts.StorageBackend, opts.Backends.Names(), + backendName, opts.Backends.Names(), ) } - if errs := backend.Validate(); len(errs) > 0 { - return nil, fmt.Errorf("validating --storage-backend=%q: %v", opts.StorageBackend, errs) - } - factory, err := backend.Build() + crFactory, err := backend.Build() if err != nil { - return nil, fmt.Errorf("building --storage-backend=%q: %w", opts.StorageBackend, err) + return nil, fmt.Errorf("building --storage-backend=%q: %w", backendName, err) } - mcOpts.BackendFactory = factory + mcOpts.BackendFactory = crFactory // Non-etcd backends typically implement RequestWatchProgress // natively (Spanner via its broadcaster). Tell the feature // checker so the cacher allows SendInitialEvents watches. diff --git a/cmd/apiserver/app/options/completion.go b/cmd/apiserver/app/options/completion.go index e047639..ec52c37 100644 --- a/cmd/apiserver/app/options/completion.go +++ b/cmd/apiserver/app/options/completion.go @@ -23,6 +23,7 @@ import ( "strings" apiserveroptions "k8s.io/apiserver/pkg/server/options" + storagefactory "k8s.io/apiserver/pkg/storage/storagebackend/factory" _ "k8s.io/component-base/metrics/prometheus/workqueue" netutils "k8s.io/utils/net" @@ -49,6 +50,42 @@ func (s *ServerRunOptions) Complete(ctx context.Context) (CompletedOptions, erro return CompletedOptions{completedOptions: &completedOptions{}}, nil } + // KPEP-0001 Option C: register the selected non-etcd3 backend with the + // fork's factory registry BEFORE downstream Validate runs. EtcdOptions + // rejects --storage-backend values it doesn't recognize, but it + // consults factory.IsRegistered first — registering here means + // "--storage-backend=spanner" passes upstream validation, and every + // factory.Create callsite inside upstream (CR storage, master/peer + // endpoint leases, service IP/NodePort allocators) dispatches to the + // same Spanner backend at runtime. spanner.Options.BuildFactoryBackend + // is idempotent (one shared client per Options) so Build/the decorator + // hook in config.go reuse the same instance. + // + // The backend name comes from upstream EtcdOptions's --storage-backend + // flag (bound to s.Etcd.StorageConfig.Type). Empty / "etcd3" / "etcd2" + // keep the upstream default path. + backendName := "" + if s.Etcd != nil { + backendName = s.Etcd.StorageConfig.Type + } + if backendName != "" && backendName != "etcd3" && backendName != "etcd2" { + backend, ok := s.Backends.Get(backendName) + if !ok { + return CompletedOptions{}, fmt.Errorf( + "unknown --storage-backend=%q (registered: %v)", + backendName, s.Backends.Names(), + ) + } + if errs := backend.Validate(); len(errs) > 0 { + return CompletedOptions{}, fmt.Errorf("validating --storage-backend=%q: %v", backendName, errs) + } + fb, err := backend.BuildFactoryBackend() + if err != nil { + return CompletedOptions{}, fmt.Errorf("building factory backend for --storage-backend=%q: %w", backendName, err) + } + storagefactory.Register(backendName, fb) + } + // process s.ServiceClusterIPRange from list to Primary and Secondary // we process secondary only if provided by user apiServerServiceIP, primaryServiceIPRange, secondaryServiceIPRange, err := getServiceIPAndRanges(s.ServiceClusterIPRanges) diff --git a/cmd/apiserver/app/options/flags_test.go b/cmd/apiserver/app/options/flags_test.go new file mode 100644 index 0000000..e1e7ecf --- /dev/null +++ b/cmd/apiserver/app/options/flags_test.go @@ -0,0 +1,55 @@ +/* +Copyright 2026 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 +*/ + +package options + +import ( + "testing" + + "github.com/spf13/pflag" +) + +// TestStorageBackendFlagRoutesToEtcdConfig guards the KPEP-0001 Option C +// flag wiring. The backend selection comes from upstream EtcdOptions's +// --storage-backend flag, which binds directly to s.Etcd.StorageConfig.Type. +// Options.Complete reads that field to decide which backend to register +// with the fork factory registry. +// +// A previous version of kplane's Flags() registered a SECOND --storage-backend +// pflag pointing at a separate kplane-side field. pflag's NamedFlagSets +// merge silently collapses duplicate registrations, but which destination +// pointer "wins" depends on the order flag-sets are added — so half the +// time the upstream field stayed empty after parse, Complete skipped +// Register, and upstream Validate then rejected the backend as unknown. +// +// This test asserts that after parsing --storage-backend=, the value +// lands in s.Etcd.StorageConfig.Type (the field Complete actually reads). +// Re-introducing a duplicate registration anywhere in Flags() fails the +// test because the new flag's destination wins parsing instead. +func TestStorageBackendFlagRoutesToEtcdConfig(t *testing.T) { + s := NewServerRunOptions() + + fss := s.Flags() + merged := pflag.NewFlagSet("merged", pflag.ContinueOnError) + for _, fs := range fss.FlagSets { + merged.AddFlagSet(fs) + } + + if err := merged.Parse([]string{"--storage-backend=spanner"}); err != nil { + t.Fatalf("Parse failed: %v", err) + } + + if s.Etcd == nil { + t.Fatal("s.Etcd is nil after NewServerRunOptions") + } + if got := s.Etcd.StorageConfig.Type; got != "spanner" { + t.Fatalf("after --storage-backend=spanner, s.Etcd.StorageConfig.Type=%q; want \"spanner\"", got) + } +} diff --git a/cmd/apiserver/app/options/options.go b/cmd/apiserver/app/options/options.go index 375c22d..cb7585d 100644 --- a/cmd/apiserver/app/options/options.go +++ b/cmd/apiserver/app/options/options.go @@ -67,18 +67,6 @@ type Extra struct { MasterCount int - // StorageBackend selects which registered storage backend serves the - // multicluster data plane. Defaults to "etcd3" (the legacy path); - // other valid values are whatever backends are registered into - // Backends via storagebackends.RegisterBuiltin (or by an out-of-tree - // custom apiserver that registers more before Validate runs). - // - // KPEP-0001: this is the single dispatch knob. Per-backend flags - // (--spanner-project, future --postgres-dsn, etc.) come from the - // backend's own AddFlags, fanned out by Backends.AddFlags. The - // apiserver options layer never names a specific backend. - StorageBackend string - // Backends is the instance-scoped registry of available storage // backends. The default set is populated in NewServerRunOptions via // storagebackends.RegisterBuiltin. Custom apiservers can call @@ -103,7 +91,6 @@ func NewServerRunOptions() *ServerRunOptions { Options: controlplaneapiserver.NewOptions(), Extra: Extra{ - StorageBackend: "etcd3", Backends: backends, EndpointReconcilerType: string(reconcilers.LeaseEndpointReconcilerType), KubeletConfig: kubeletclient.KubeletClientConfig{ @@ -150,12 +137,14 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) { mcfs.StringVar(&s.ServiceCIDRSharingMode, "service-cidr-sharing-mode", s.ServiceCIDRSharingMode, "Service CIDR strategy across control planes: 'shared' keeps root-managed defaults only; 'per-cluster' bootstraps default ServiceCIDR in each virtual control plane.") - // KPEP-0001 storage backend dispatch. Picks which registered backend - // services multicluster storage; backend-specific flags (e.g. - // --spanner-project) are bound by each backend's AddFlags below. + // KPEP-0001 backend-specific flags (e.g. --spanner-project) are bound + // by each backend's AddFlags below. The selection itself reuses + // upstream EtcdOptions's --storage-backend flag (bound to + // s.Etcd.StorageConfig.Type) — Options.Complete reads that value and + // registers the chosen backend with the fork factory registry. + // Registering a second --storage-backend pflag here would collide + // non-deterministically with the upstream one. storagefs := fss.FlagSet("storage backend") - storagefs.StringVar(&s.StorageBackend, "storage-backend", s.StorageBackend, - "Storage backend for multicluster data. One of: "+strings.Join(s.Backends.Names(), ", ")+". Defaults to 'etcd3'.") s.Backends.AddFlags(storagefs) fs := fss.FlagSet("misc") From 1213f7295d3b1d96b5afe88748551bab7b461f4d Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Tue, 30 Jun 2026 15:45:23 -0700 Subject: [PATCH 3/5] chore: bump kubernetes (K0.5) + storage (PR-S) pins - kubernetes => github.com/kplane-dev/kubernetes v0.0.0-20260630223049-360a88f3ed5f (includes #4 factory.Backend registry seam and #5 DecodeCallback relocation) - storage => github.com/kplane-dev/storage v0.0.0-20260630223821-e46399bd0d8b (includes #3 KPEP-0001 Spanner backend with conformance + TTL + ordered watch) Revendors to match. --- go.mod | 68 +++++++++++++++++------------------ go.sum | 112 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/go.mod b/go.mod index c506d25..6542e3c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/kplane-dev/informer v0.0.0-00010101000000-000000000000 github.com/kplane-dev/storage v0.0.0 github.com/spf13/cobra v1.10.1 + github.com/spf13/pflag v1.0.10 go.etcd.io/etcd/client/v3 v3.6.7 go.opentelemetry.io/otel v1.44.0 golang.org/x/sync v0.21.0 @@ -24,39 +25,39 @@ require ( replace ( github.com/kplane-dev/informer => github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b - github.com/kplane-dev/storage => github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3 - k8s.io/api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5 - k8s.io/apiextensions-apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad - k8s.io/apimachinery => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5 - k8s.io/apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5 - k8s.io/cli-runtime => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20260404055358-aac72e7d04ad - k8s.io/client-go => github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5 - k8s.io/cloud-provider => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad - k8s.io/cluster-bootstrap => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad - k8s.io/code-generator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20260404055358-aac72e7d04ad - k8s.io/component-base => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5 - k8s.io/component-helpers => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad - k8s.io/controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260404055358-aac72e7d04ad - k8s.io/cri-api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260404055358-aac72e7d04ad - k8s.io/cri-client => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260404055358-aac72e7d04ad - k8s.io/csi-translation-lib => github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260404055358-aac72e7d04ad - k8s.io/dynamic-resource-allocation => github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260404055358-aac72e7d04ad - k8s.io/endpointslice => github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260404055358-aac72e7d04ad - k8s.io/externaljwt => github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kms => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5 - k8s.io/kube-aggregator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kube-controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kube-proxy => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kube-scheduler => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kubectl => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kubelet => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260404055358-aac72e7d04ad - k8s.io/kubernetes => github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5 - k8s.io/metrics => github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260404055358-aac72e7d04ad - k8s.io/mount-utils => github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260404055358-aac72e7d04ad - k8s.io/pod-security-admission => github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad - k8s.io/sample-apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20260404055358-aac72e7d04ad - k8s.io/sample-cli-plugin => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20260404055358-aac72e7d04ad - k8s.io/sample-controller => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20260404055358-aac72e7d04ad + github.com/kplane-dev/storage => github.com/kplane-dev/storage v0.0.0-20260630223821-e46399bd0d8b + k8s.io/api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260630223049-360a88f3ed5f + k8s.io/apiextensions-apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260630223049-360a88f3ed5f + k8s.io/apimachinery => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260630223049-360a88f3ed5f + k8s.io/apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260630223049-360a88f3ed5f + k8s.io/cli-runtime => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20260630223049-360a88f3ed5f + k8s.io/client-go => github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260630223049-360a88f3ed5f + k8s.io/cloud-provider => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260630223049-360a88f3ed5f + k8s.io/cluster-bootstrap => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260630223049-360a88f3ed5f + k8s.io/code-generator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20260630223049-360a88f3ed5f + k8s.io/component-base => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260630223049-360a88f3ed5f + k8s.io/component-helpers => github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260630223049-360a88f3ed5f + k8s.io/controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260630223049-360a88f3ed5f + k8s.io/cri-api => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260630223049-360a88f3ed5f + k8s.io/cri-client => github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260630223049-360a88f3ed5f + k8s.io/csi-translation-lib => github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260630223049-360a88f3ed5f + k8s.io/dynamic-resource-allocation => github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260630223049-360a88f3ed5f + k8s.io/endpointslice => github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260630223049-360a88f3ed5f + k8s.io/externaljwt => github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kms => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kube-aggregator => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kube-controller-manager => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kube-proxy => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kube-scheduler => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kubectl => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kubelet => github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260630223049-360a88f3ed5f + k8s.io/kubernetes => github.com/kplane-dev/kubernetes v0.0.0-20260630223049-360a88f3ed5f + k8s.io/metrics => github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260630223049-360a88f3ed5f + k8s.io/mount-utils => github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260630223049-360a88f3ed5f + k8s.io/pod-security-admission => github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260630223049-360a88f3ed5f + k8s.io/sample-apiserver => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20260630223049-360a88f3ed5f + k8s.io/sample-cli-plugin => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20260630223049-360a88f3ed5f + k8s.io/sample-controller => github.com/kplane-dev/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20260630223049-360a88f3ed5f ) require ( @@ -144,7 +145,6 @@ require ( github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.19.2 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/spf13/pflag v1.0.10 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index 389b1ac..42ff43a 100644 --- a/go.sum +++ b/go.sum @@ -197,62 +197,62 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b h1:Z1+b+fPm/I2STcdIT3Psb3OYng2xYYILMmdgD55KEm8= github.com/kplane-dev/informer v0.0.0-20260404055613-d9279cfd5e9b/go.mod h1:y+IpeQX/vAaf7h6d+fwTYQ9kqdpwJdjHCc5KuN4JcC4= -github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5 h1:uCHzOMe1b0TocxFY2ynt9LHaR98P8uhzjZKJTIEFGrg= -github.com/kplane-dev/kubernetes v0.0.0-20260311054814-32f5e9075db5/go.mod h1:9uEdeMBkUjkGSL2ioy2pKr0+aLNIvmOan7p8F7ENHbk= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5 h1:VGSKAidEijlXCza8zQ6pdFZz9QczfT98wBox+qRTaxc= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260311054814-32f5e9075db5/go.mod h1:KOrdwhDi3QHVXr50HAWBhO2r9uMtWbO46CiIHzRVtU8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad h1:XLq9ewx7uGAHa18cYQ1juWA/2dgrp4/bct+38M2XSuQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:wZyuUfbqWsRKO42GvZVHZSJ0JttMO7YrXnu/bv/GqPg= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5 h1:FdV1ooo4kmNti8PMOwjuzMgP+HaUjggCVW502sdMbV8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260311054814-32f5e9075db5/go.mod h1:7mgr/dli8ofwAbcIQXetFVX1fbOYsOYojq3AUbybVmQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5 h1:B32q2wQIQLDhK8jhqRgRIBUZS2WoSEYYFau0dh9pl/g= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260311054814-32f5e9075db5/go.mod h1:GNWcUSRqjpm4i1hrLaGA7EQrl60YdahMic4aS+WUQVI= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5 h1:g1Cgzs09gUaCwXCtSzWJS5rFYaK1ycHKruIpwuCJJtI= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260311054814-32f5e9075db5/go.mod h1:7IM9p4c8CafSxF7ZY0F46WHylFn3o4mLVW5T1VZbaY8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad h1:J8CwRPJ1ehjMrT0UbH2cUaXDTUfJ7W7JVRkMumWKukw= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:bGWrOCyYWe9G/1zpB0hSLAO+BnZUNbNVWXcHAzfaF+E= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad h1:BH4eKNGN6ep4PQzAOya7Y2tqFui5jvl95jelztrCl1s= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:CxFNOU1/U4gfM4SU7hRkzCRhTfUweuTLRWKWh6yitcE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5 h1:l4RLyYStWu+BL8uKL++4byqPwLc2cv76rnHW/7A+Cvw= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260311054814-32f5e9075db5/go.mod h1:R6vYa1XRfX3PdQEGNkCaL3pt7NvLU2ti7FPzsEsA6GQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad h1:y+O0nFoSa7+0Z9HAfB0ffVjTiUxETsGzmi7vS3m7HWQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:axBpPWJYMZFstDUXj45ooTW3njLMa7B8Kz8o4QY5xfk= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260404055358-aac72e7d04ad h1:5bXsA+t0Qj8s/qLCB1ZWbjZTBLNYXbW2wLG+XrSiVhI= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:gjjSpBn/ZS8VRB+BMH7Ttd2kk+Hr+IYvm4LwBwQAtaU= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260404055358-aac72e7d04ad h1:f8s2S/2J/nm4NhCjkrU5tST0B3Y3e+501NxH/dJizXc= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:sez47HjW1useDMcQeVkW7kQNjwzaLJlaJoMcWYU6WVE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260404055358-aac72e7d04ad h1:ufowm4dXMNXSHGVkjfdqkRWVdq04dAmeGhu6miLuz5E= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:rVFUCMkvRUmEXFCLoBSsAbnSarFL/9tYTe6kE+nh/a0= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260404055358-aac72e7d04ad h1:HgcSsZgjPAgPkK0nIZGTVliZx1HREu5X9GOMMLi2vyY= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:h4+rRn/HN1k7Uln9nnxykSWPI5ZBQCBJyHosyW4F7nk= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260404055358-aac72e7d04ad h1:nl9unlL2JiIKQ3FgVbVQXwibcJU0npGsKUkB7uTDOBE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:2UvGX2oAJmCnqKSEBlBMnCEWisTXl2ZXQK/quJy61Q4= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260404055358-aac72e7d04ad h1:+GjOBFoY4CtAwNsgRKUoFcL7g7sizw6QROeSnLZZRgM= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:fdIUBx+W5Ypy0TBvfW8qonHr4QV3iXw+N+ADcGYf8eI= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad h1:dGtsABtyNZPtY696j/WnFHM8mTaMNw0KJgbCxO4lG6c= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:+8tzBBizhTus+bM0JPY/4h2O26NxIQgcEBdK5Xdfehc= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5 h1:vjbNa+ypXFTpVWOqfx1ft5to/rTcIEgIo9prLbgApzE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260311054814-32f5e9075db5/go.mod h1:rhO9JHsWibaRLx12/ViuMQdeZi43hsiXCl8KEEihjaw= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad h1:0cEi7M+eIESF+kWiEHnL7/kirpbvEn/b2asLQSZHx3o= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:KXJ9MlZYxlzOWKhHqfdxOTDdmfk/+ftdOwN//JGQs0g= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260404055358-aac72e7d04ad h1:BZew8n8DewnquBgR4mEKdgvoq3EVV3/4EMyW37KAd+8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:fvSj40FltpPVU4KLda+I/WhFTwwiGuPpzpy+5UeiOaM= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260404055358-aac72e7d04ad h1:EEyuT5azRN/RkWgXDczPRDgX3598fP1iHsuVQauWGi4= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:1nDymEUiZa0nIsVZkeSAFISoJsp0Nnd40vWuipDGLv0= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260404055358-aac72e7d04ad h1:sdCFHW5DkVxoth6vaYH4Gu05ay0Vd2jOz4ag9cYBcxw= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:5ZwsfUdHnj/nEAAdk8utKGDG6c4eZTyZg/7BHPE4uaQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260404055358-aac72e7d04ad h1:GNH39+P1HigOfx5C8H0blnUhq1KU3pVzXuKeMJ5KFOE= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:ZmlXPtm3wJFF6x/7QU8q/op7GHIyBvnUjsbkud1NeNQ= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260404055358-aac72e7d04ad h1:/+N54AxY+Oacq2Ovo9HP1jNJWQhfllm6KTLLfxjtAxo= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:h59njVygVWeHIhmMqMoocQNjUyC3q8D51fZNSuMEAis= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260404055358-aac72e7d04ad h1:Y3dWxmUNbH9sYyldW7SbGzQCtUPh94yqxnNJTcW1y8c= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:5vBQ1SE0Ed1m5R6BkCKRXDboEjmKbbO17EyrF6XXiqA= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260404055358-aac72e7d04ad h1:Lz4SqxEKxB2lxmBCnaoqyx4ofqx13nmo838ZFMI+OG0= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:0tRkeDDp5zQDR/JKhcttJMwq3mTWqNm5GE2DgjfRvsY= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad h1:d51TIux4RCxVjdYsZnyyQcwiA/h1R7hTlH5s80Ylzp8= -github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260404055358-aac72e7d04ad/go.mod h1:2Hv3+Ga3SCWHO9E8+Ym58CioDvWe7wW21gy3nVetVNw= -github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3 h1:3yv8oDTgHzDJcnNxIVwlX6krOMJXqxirMJ0kgwsb+aU= -github.com/kplane-dev/storage v0.0.0-20260617004011-dccace0ff6c3/go.mod h1:C7jzKCXDJNzfLiTRTK48EOmIAhme7FGzLmIc/mfIOj0= +github.com/kplane-dev/kubernetes v0.0.0-20260630223049-360a88f3ed5f h1:Chh2AB0XED5YhP4eLdHHBn0elHErCp77eygQFwcE4hs= +github.com/kplane-dev/kubernetes v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:9uEdeMBkUjkGSL2ioy2pKr0+aLNIvmOan7p8F7ENHbk= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260630223049-360a88f3ed5f h1:1wSIVzfWHC1L9+eSvLmayDEcfRy4ZsgczNrmqCxbysc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/api v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:KOrdwhDi3QHVXr50HAWBhO2r9uMtWbO46CiIHzRVtU8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260630223049-360a88f3ed5f h1:h3UhGusy4wdTgjor8z+RZedsjWAmpanQFMpcLFX6jZI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:wZyuUfbqWsRKO42GvZVHZSJ0JttMO7YrXnu/bv/GqPg= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260630223049-360a88f3ed5f h1:KRk302u+wdAvE5GVZKw47l5gHCYnVki7JPrVPbpZ1k0= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:7mgr/dli8ofwAbcIQXetFVX1fbOYsOYojq3AUbybVmQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260630223049-360a88f3ed5f h1:+jUMirT1PvykTxHVPbekxM0wcPB6OjT7C2uvBgSqdSI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:GNWcUSRqjpm4i1hrLaGA7EQrl60YdahMic4aS+WUQVI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260630223049-360a88f3ed5f h1:OU6umzhUd0QuCLBdXLiJFbu7vrDq6G4qbR/c7CcKtLg= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/client-go v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:7IM9p4c8CafSxF7ZY0F46WHylFn3o4mLVW5T1VZbaY8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260630223049-360a88f3ed5f h1:NY29p+4xrAVfu099pJIdS/m+xRNXUl4m6LDW59W2Fiw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:bGWrOCyYWe9G/1zpB0hSLAO+BnZUNbNVWXcHAzfaF+E= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260630223049-360a88f3ed5f h1:Gj6UKywCyA3IStC25dCjAvn5sh/jnH2nE9gvaxe/SRc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:CxFNOU1/U4gfM4SU7hRkzCRhTfUweuTLRWKWh6yitcE= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260630223049-360a88f3ed5f h1:XW8sSR+XxARpXx7223DqrHnK/lEaBWIgC07zJThBU1Y= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-base v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:R6vYa1XRfX3PdQEGNkCaL3pt7NvLU2ti7FPzsEsA6GQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260630223049-360a88f3ed5f h1:YAed0CNcxUVuk23RLh2TRE5imPf2h7pAUHqYj5ZvMSM= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:axBpPWJYMZFstDUXj45ooTW3njLMa7B8Kz8o4QY5xfk= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260630223049-360a88f3ed5f h1:R8hXKiymiypBbdNJstXcBCJQmHiDOCugiJGJXvNJz/4= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:gjjSpBn/ZS8VRB+BMH7Ttd2kk+Hr+IYvm4LwBwQAtaU= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260630223049-360a88f3ed5f h1:KwxVrgUx56MzDjEJ6lFoXI41a9eNBqYoefryZYkoh7k= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:sez47HjW1useDMcQeVkW7kQNjwzaLJlaJoMcWYU6WVE= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260630223049-360a88f3ed5f h1:pevqRlcVFbmp0zH3raQ0GI8z0V5ruqznIHaXkktTyAw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:rVFUCMkvRUmEXFCLoBSsAbnSarFL/9tYTe6kE+nh/a0= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260630223049-360a88f3ed5f h1:u7e7g70gQqHG1pS/RaWd+TKDZ0cIrBX1xH9iRc53JLI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:h4+rRn/HN1k7Uln9nnxykSWPI5ZBQCBJyHosyW4F7nk= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260630223049-360a88f3ed5f h1:v6YaBoOyyBxgABIQOvcx+Me9KxB6JJDqNtSnplQ/Stk= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:2UvGX2oAJmCnqKSEBlBMnCEWisTXl2ZXQK/quJy61Q4= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260630223049-360a88f3ed5f h1:NDsEVamwHS+UbaCfNfVaiF1Tc9Sspic43VpPWUccAfM= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:fdIUBx+W5Ypy0TBvfW8qonHr4QV3iXw+N+ADcGYf8eI= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260630223049-360a88f3ed5f h1:L3shRLFf/nA9Swh1b+6lyz3yWEzPnzhHlbU2E5gHP3M= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/externaljwt v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:+8tzBBizhTus+bM0JPY/4h2O26NxIQgcEBdK5Xdfehc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260630223049-360a88f3ed5f h1:Z6Tvf9mag4rbpUWgTVzY//gzxn1WVkn8NyQrzxra4n8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kms v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:rhO9JHsWibaRLx12/ViuMQdeZi43hsiXCl8KEEihjaw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260630223049-360a88f3ed5f h1:V7ZL0XasvI9YoKRGybBrJorlEjivrOE52NG2d4+g29U= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:KXJ9MlZYxlzOWKhHqfdxOTDdmfk/+ftdOwN//JGQs0g= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260630223049-360a88f3ed5f h1:91rm6sMYXIdcZF7CH319bEzaOWmRyyGyxQo7LID2TVE= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:fvSj40FltpPVU4KLda+I/WhFTwwiGuPpzpy+5UeiOaM= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260630223049-360a88f3ed5f h1:VuQb7MP3BGrRpKePplatUBnvtEkDI1Oi8krdlbKHOIc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:1nDymEUiZa0nIsVZkeSAFISoJsp0Nnd40vWuipDGLv0= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260630223049-360a88f3ed5f h1:ykKSyWMSSmSFXWG55yfXfpS3NnDhHGKAYeG/r3/pOX8= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:5ZwsfUdHnj/nEAAdk8utKGDG6c4eZTyZg/7BHPE4uaQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260630223049-360a88f3ed5f h1:m+mtpHaey8Em8p1nBy7QtH9XUsqKM6oj5v25wtH+6DQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:ZmlXPtm3wJFF6x/7QU8q/op7GHIyBvnUjsbkud1NeNQ= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260630223049-360a88f3ed5f h1:cBEcWAX8Haaj/v7a/iGq5jjRZaGRZiQ6G7ziKpamvxw= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:h59njVygVWeHIhmMqMoocQNjUyC3q8D51fZNSuMEAis= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260630223049-360a88f3ed5f h1:tJ+lQrQVcHMG/7L5oCfV0zep9Guu4RgOEaksROf6OXE= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/metrics v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:5vBQ1SE0Ed1m5R6BkCKRXDboEjmKbbO17EyrF6XXiqA= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260630223049-360a88f3ed5f h1:lBdHGlfzNCZWKxFpU8fUXO9MiNauEUkG3fzOn3KLiUc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:0tRkeDDp5zQDR/JKhcttJMwq3mTWqNm5GE2DgjfRvsY= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260630223049-360a88f3ed5f h1:6XJs3+7WY1nAfezPXn/2DNHpTsyIVqb/oTEfvVgQkQc= +github.com/kplane-dev/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20260630223049-360a88f3ed5f/go.mod h1:2Hv3+Ga3SCWHO9E8+Ym58CioDvWe7wW21gy3nVetVNw= +github.com/kplane-dev/storage v0.0.0-20260630223821-e46399bd0d8b h1:/Fyb5CNg+nPyz1m9mH7MceobNZYtE+QjGMcXyYNyjB4= +github.com/kplane-dev/storage v0.0.0-20260630223821-e46399bd0d8b/go.mod h1:JvvSAQ7Ai72HgVL5SgjxT71Q+m4+XvcsKOdRnw2nNn8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= From 7f3ebbd8f40804a138f1453daf32a949c6a1b7d6 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Tue, 30 Jun 2026 15:45:23 -0700 Subject: [PATCH 4/5] fix(multicluster): listers return apierrors.NewNotFound, not fmt.Errorf Admission's PrepareForCreate / PrepareForUpdate / Validate paths check apierrors.IsNotFound(err) when consulting per-resource listers (e.g. the ResourceQuota validator). A typed NotFound makes those paths skip the missing object gracefully; a bare fmt.Errorf reads as a hard error and propagates as a 500 to the client. All 9 Lister.Get adapters in this package were returning fmt.Errorf " not found". This change switches each to apierrors.NewNotFound with the correct GroupResource. TestListersReturnTypedNotFound (new) asserts apierrors.IsNotFound returns true for every adapter. --- pkg/multicluster/typedinformer/adapters.go | 19 +-- .../typedinformer/adapters_test.go | 109 ++++++++++++++++++ 2 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 pkg/multicluster/typedinformer/adapters_test.go diff --git a/pkg/multicluster/typedinformer/adapters.go b/pkg/multicluster/typedinformer/adapters.go index 12629cf..137a3e2 100644 --- a/pkg/multicluster/typedinformer/adapters.go +++ b/pkg/multicluster/typedinformer/adapters.go @@ -6,6 +6,7 @@ import ( admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" discoveryv1 "k8s.io/api/discovery/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" admissionregistrationlisters "k8s.io/client-go/listers/admissionregistration/v1" @@ -63,7 +64,7 @@ func (l *namespaceLister) List(sel labels.Selector) (ret []*corev1.Namespace, er func (l *namespaceLister) Get(name string) (*corev1.Namespace, error) { obj, ok := l.mci.Get(l.cluster, "", name) if !ok { - return nil, fmt.Errorf("namespace %q not found", name) + return nil, apierrors.NewNotFound(corev1.Resource("namespaces"), name) } return convert[corev1.Namespace](obj) } @@ -139,7 +140,7 @@ func (l *secretNamespaceLister) List(sel labels.Selector) (ret []*corev1.Secret, func (l *secretNamespaceLister) Get(name string) (*corev1.Secret, error) { obj, ok := l.parent.mci.Get(l.parent.cluster, l.namespace, name) if !ok { - return nil, fmt.Errorf("secret %s/%s not found", l.namespace, name) + return nil, apierrors.NewNotFound(corev1.Resource("secrets"), name) } return convert[corev1.Secret](obj) } @@ -193,7 +194,7 @@ func (l *serviceAccountNamespaceLister) List(sel labels.Selector) (ret []*corev1 func (l *serviceAccountNamespaceLister) Get(name string) (*corev1.ServiceAccount, error) { obj, ok := l.parent.mci.Get(l.parent.cluster, l.namespace, name) if !ok { - return nil, fmt.Errorf("serviceaccount %s/%s not found", l.namespace, name) + return nil, apierrors.NewNotFound(corev1.Resource("serviceaccounts"), name) } return convert[corev1.ServiceAccount](obj) } @@ -247,7 +248,7 @@ func (l *podNamespaceLister) List(sel labels.Selector) (ret []*corev1.Pod, err e func (l *podNamespaceLister) Get(name string) (*corev1.Pod, error) { obj, ok := l.parent.mci.Get(l.parent.cluster, l.namespace, name) if !ok { - return nil, fmt.Errorf("pod %s/%s not found", l.namespace, name) + return nil, apierrors.NewNotFound(corev1.Resource("pods"), name) } return convert[corev1.Pod](obj) } @@ -282,7 +283,7 @@ func (l *nodeLister) List(sel labels.Selector) (ret []*corev1.Node, err error) { func (l *nodeLister) Get(name string) (*corev1.Node, error) { obj, ok := l.mci.Get(l.cluster, "", name) if !ok { - return nil, fmt.Errorf("node %q not found", name) + return nil, apierrors.NewNotFound(corev1.Resource("nodes"), name) } return convert[corev1.Node](obj) } @@ -336,7 +337,7 @@ func (l *serviceNamespaceLister) List(sel labels.Selector) (ret []*corev1.Servic func (l *serviceNamespaceLister) Get(name string) (*corev1.Service, error) { obj, ok := l.parent.mci.Get(l.parent.cluster, l.namespace, name) if !ok { - return nil, fmt.Errorf("service %s/%s not found", l.namespace, name) + return nil, apierrors.NewNotFound(corev1.Resource("services"), name) } return convert[corev1.Service](obj) } @@ -390,7 +391,7 @@ func (l *endpointSliceNamespaceLister) List(sel labels.Selector) (ret []*discove func (l *endpointSliceNamespaceLister) Get(name string) (*discoveryv1.EndpointSlice, error) { obj, ok := l.parent.mci.Get(l.parent.cluster, l.namespace, name) if !ok { - return nil, fmt.Errorf("endpointslice %s/%s not found", l.namespace, name) + return nil, apierrors.NewNotFound(discoveryv1.Resource("endpointslices"), name) } return convert[discoveryv1.EndpointSlice](obj) } @@ -425,7 +426,7 @@ func (l *mutatingWebhookConfigurationLister) List(sel labels.Selector) (ret []*a func (l *mutatingWebhookConfigurationLister) Get(name string) (*admissionregistrationv1.MutatingWebhookConfiguration, error) { obj, ok := l.mci.Get(l.cluster, "", name) if !ok { - return nil, fmt.Errorf("mutatingwebhookconfiguration %q not found", name) + return nil, apierrors.NewNotFound(admissionregistrationv1.Resource("mutatingwebhookconfigurations"), name) } return convert[admissionregistrationv1.MutatingWebhookConfiguration](obj) } @@ -460,7 +461,7 @@ func (l *validatingWebhookConfigurationLister) List(sel labels.Selector) (ret [] func (l *validatingWebhookConfigurationLister) Get(name string) (*admissionregistrationv1.ValidatingWebhookConfiguration, error) { obj, ok := l.mci.Get(l.cluster, "", name) if !ok { - return nil, fmt.Errorf("validatingwebhookconfiguration %q not found", name) + return nil, apierrors.NewNotFound(admissionregistrationv1.Resource("validatingwebhookconfigurations"), name) } return convert[admissionregistrationv1.ValidatingWebhookConfiguration](obj) } diff --git a/pkg/multicluster/typedinformer/adapters_test.go b/pkg/multicluster/typedinformer/adapters_test.go new file mode 100644 index 0000000..e22f4f4 --- /dev/null +++ b/pkg/multicluster/typedinformer/adapters_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2026 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 +*/ + +package typedinformer + +import ( + "testing" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + apistorage "k8s.io/apiserver/pkg/storage" + + "github.com/kplane-dev/informer" +) + +// TestListersReturnTypedNotFound asserts that every Lister.Get returns an +// apierrors.IsNotFound-compatible error when the requested object is +// absent from the cache. Upstream's NamespaceLifecycle admission plugin +// distinguishes "not in cache, fall back to live lookup" from "real +// error, return 500" via apierrors.IsNotFound(err) — if the lister +// returns plain fmt.Errorf("namespace %q not found", name) instead of a +// typed NotFound, IsNotFound returns false, admission wraps the error in +// errors.NewInternalError and returns 500 to the client without ever +// attempting the recovery path. +// +// This silently breaks bootstrap on any storage backend slower than etcd: +// etcd is fast enough that the informer cache holds kube-system by the +// time the first ConfigMap/Lease create lands, but Spanner's higher +// per-write latency means dependent writes arrive BEFORE the namespace +// reaches the lister cache. Without typed NotFound, admission returns +// 500 forever instead of falling through to the live lookup that would +// succeed. +// +// Fixing only namespaceLister would leave the others (Secret, Pod, Node, +// Service, EndpointSlice, MutatingWebhookConfiguration, +// ValidatingWebhookConfiguration, ServiceAccount) with the same bug for +// every controller that retries on IsNotFound. This test pins every +// adapter in adapters.go. +func TestListersReturnTypedNotFound(t *testing.T) { + mci := informer.New(informer.Config{ + Storage: nopStorage{}, + ResourcePrefix: "/anything/clusters/", + GroupResource: schema.GroupResource{Resource: "anything"}, + }) + + tests := []struct { + name string + get func() error + }{ + {"namespace", func() error { + _, err := NewNamespaceLister(mci, "c1").Get("kube-system") + return err + }}, + {"secret", func() error { + _, err := NewSecretLister(mci, "c1").Secrets("ns").Get("missing") + return err + }}, + {"serviceaccount", func() error { + _, err := NewServiceAccountLister(mci, "c1").ServiceAccounts("ns").Get("missing") + return err + }}, + {"pod", func() error { + _, err := NewPodLister(mci, "c1").Pods("ns").Get("missing") + return err + }}, + {"node", func() error { + _, err := NewNodeLister(mci, "c1").Get("missing") + return err + }}, + {"service", func() error { + _, err := NewServiceLister(mci, "c1").Services("ns").Get("missing") + return err + }}, + {"endpointslice", func() error { + _, err := NewEndpointSliceLister(mci, "c1").EndpointSlices("ns").Get("missing") + return err + }}, + {"mutatingwebhookconfiguration", func() error { + _, err := NewMutatingWebhookConfigurationLister(mci, "c1").Get("missing") + return err + }}, + {"validatingwebhookconfiguration", func() error { + _, err := NewValidatingWebhookConfigurationLister(mci, "c1").Get("missing") + return err + }}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.get() + if err == nil { + t.Fatalf("expected error on missing object") + } + if !apierrors.IsNotFound(err) { + t.Fatalf("expected apierrors.IsNotFound(err)==true; got err=%v (%T) — admission plugins that recover via live lookup require typed NotFound", err, err) + } + }) + } +} + +// nopStorage satisfies apistorage.Interface enough for informer.New — +// the informer's Run loop never starts in this test. +type nopStorage struct{ apistorage.Interface } From e3539ec6c817392e2d8561634ba0037280a8d412 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Tue, 30 Jun 2026 15:55:29 -0700 Subject: [PATCH 5/5] chore: drop project-codename references from in-code comments Code comments shouldn't reference internal codenames; the apiserver should read as plain functionality. Strips 5 references from comments in config.go, options/options.go, options/completion.go, options/flags_test.go, and multicluster/options.go. No behavior change. --- cmd/apiserver/app/config.go | 16 ++++++++-------- cmd/apiserver/app/options/completion.go | 8 ++++---- cmd/apiserver/app/options/flags_test.go | 2 +- cmd/apiserver/app/options/options.go | 6 +++--- pkg/multicluster/options.go | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/apiserver/app/config.go b/cmd/apiserver/app/config.go index 1dda099..7190494 100644 --- a/cmd/apiserver/app/config.go +++ b/cmd/apiserver/app/config.go @@ -133,14 +133,14 @@ func NewConfig(opts options.CompletedOptions) (*Config, error) { informerRegistry := mc.NewInformerRegistry(wait.ContextForChannel(genericConfig.DrainedNotify())) mcOpts.InformerRegistry = informerRegistry - // KPEP-0001 storage backend dispatch. Options.Complete has already - // registered the selected backend with the fork's factory registry - // (so upstream EtcdOptions.Validate passed and every internal - // factory.Create callsite — master/peer endpoint leases, service IP/ - // NodePort allocators — dispatches to it at runtime). Here we install - // the same backend's CR-storage Factory on the multicluster decorator - // hook. spanner.Options.Build reuses the FactoryBackend created in - // Complete (one shared spanner.Client per process). + // Storage backend dispatch. Options.Complete has already registered the + // selected backend with the fork's factory registry (so upstream + // EtcdOptions.Validate passed and every internal factory.Create + // callsite — master/peer endpoint leases, service IP/NodePort + // allocators — dispatches to it at runtime). Here we install the same + // backend's CR-storage Factory on the multicluster decorator hook. + // spanner.Options.Build reuses the FactoryBackend created in Complete + // (one shared spanner.Client per process). backendName := "" if opts.Etcd != nil { backendName = opts.Etcd.StorageConfig.Type diff --git a/cmd/apiserver/app/options/completion.go b/cmd/apiserver/app/options/completion.go index ec52c37..122eb76 100644 --- a/cmd/apiserver/app/options/completion.go +++ b/cmd/apiserver/app/options/completion.go @@ -50,10 +50,10 @@ func (s *ServerRunOptions) Complete(ctx context.Context) (CompletedOptions, erro return CompletedOptions{completedOptions: &completedOptions{}}, nil } - // KPEP-0001 Option C: register the selected non-etcd3 backend with the - // fork's factory registry BEFORE downstream Validate runs. EtcdOptions - // rejects --storage-backend values it doesn't recognize, but it - // consults factory.IsRegistered first — registering here means + // Register the selected non-etcd3 backend with the fork's factory + // registry BEFORE downstream Validate runs. EtcdOptions rejects + // --storage-backend values it doesn't recognize, but it consults + // factory.IsRegistered first — registering here means // "--storage-backend=spanner" passes upstream validation, and every // factory.Create callsite inside upstream (CR storage, master/peer // endpoint leases, service IP/NodePort allocators) dispatches to the diff --git a/cmd/apiserver/app/options/flags_test.go b/cmd/apiserver/app/options/flags_test.go index e1e7ecf..7bf42ad 100644 --- a/cmd/apiserver/app/options/flags_test.go +++ b/cmd/apiserver/app/options/flags_test.go @@ -16,7 +16,7 @@ import ( "github.com/spf13/pflag" ) -// TestStorageBackendFlagRoutesToEtcdConfig guards the KPEP-0001 Option C +// TestStorageBackendFlagRoutesToEtcdConfig guards the backend-selection // flag wiring. The backend selection comes from upstream EtcdOptions's // --storage-backend flag, which binds directly to s.Etcd.StorageConfig.Type. // Options.Complete reads that field to decide which backend to register diff --git a/cmd/apiserver/app/options/options.go b/cmd/apiserver/app/options/options.go index cb7585d..6850239 100644 --- a/cmd/apiserver/app/options/options.go +++ b/cmd/apiserver/app/options/options.go @@ -137,9 +137,9 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) { mcfs.StringVar(&s.ServiceCIDRSharingMode, "service-cidr-sharing-mode", s.ServiceCIDRSharingMode, "Service CIDR strategy across control planes: 'shared' keeps root-managed defaults only; 'per-cluster' bootstraps default ServiceCIDR in each virtual control plane.") - // KPEP-0001 backend-specific flags (e.g. --spanner-project) are bound - // by each backend's AddFlags below. The selection itself reuses - // upstream EtcdOptions's --storage-backend flag (bound to + // Backend-specific flags (e.g. --spanner-project) are bound by each + // backend's AddFlags below. The selection itself reuses upstream + // EtcdOptions's --storage-backend flag (bound to // s.Etcd.StorageConfig.Type) — Options.Complete reads that value and // registers the chosen backend with the fork factory registry. // Registering a second --storage-backend pflag here would collide diff --git a/pkg/multicluster/options.go b/pkg/multicluster/options.go index b44907c..b763138 100644 --- a/pkg/multicluster/options.go +++ b/pkg/multicluster/options.go @@ -37,8 +37,8 @@ type Options struct { InformerRegistry *InformerRegistry // BackendFactory, when non-nil, installs a non-etcd storage backend // into every per-resource storage decorator. Set by config.go after - // resolving --storage-backend through the KPEP-0001 registry; nil - // preserves the upstream etcd3 path. + // resolving --storage-backend through the storage backend registry; + // nil preserves the upstream etcd3 path. BackendFactory extstorage.BackendFactory }