diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19a76e99e..4b0bbdf5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,75 +13,75 @@ permissions: contents: read env: - GO_VERSION: "1.23" + GO_VERSION: "1.24" jobs: lint: name: Lint - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + uses: actions/checkout@v5 + - uses: actions/setup-go@v6 with: go-version: ${{ env.GO_VERSION }} cache: false - - uses: actions/checkout@v4 - - uses: golangci/golangci-lint-action@v6 + - uses: actions/checkout@v5 + - uses: golangci/golangci-lint-action@v8 with: - version: v1.63.4 + version: v2.4 args: --timeout=15m --config=.golangci.yml skip-cache: true unit-tests: name: Unit Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + uses: actions/checkout@v5 + - uses: actions/setup-go@v6 with: go-version: ${{ env.GO_VERSION }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run Tests run: make test env-tests: name: Envtest Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout repository - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + uses: actions/checkout@v5 + - uses: actions/setup-go@v6 with: go-version: ${{ env.GO_VERSION }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run Tests run: make envtest e2e: name: E2E - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest timeout-minutes: 20 env: CHANGE_MINIKUBE_NONE_USER: true - KUBERNETES_VERSION: v1.31 + KUBERNETES_VERSION: v1.33 MINIKUBE_HOME: /home/runner - MINIKUBE_VERSION: v1.34.0 + MINIKUBE_VERSION: v1.36.0 MINIKUBE_WANTUPDATENOTIFICATION: false MINIKUBE_WANTREPORTERRORPROMPT: false SKAFFOLD_VERSION: v2.13.2 GO111MODULE: "on" steps: - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version: ${{ env.GO_VERSION }} - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Skaffold run: | curl -sLo skaffold https://storage.googleapis.com/skaffold/releases/${SKAFFOLD_VERSION}/skaffold-linux-amd64 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2092f8580..2e0a03ee0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.gitignore b/.gitignore index c16e93d6b..840db838d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ credentials.json # Test loganalytics file loganalytics.json +# Envtest +.envtest/ + # VS Code files .vscode/ diff --git a/.golangci.bck.yml b/.golangci.bck.yml new file mode 100644 index 000000000..0199dc0a2 --- /dev/null +++ b/.golangci.bck.yml @@ -0,0 +1,34 @@ +issues: + exclude-use-default: false + exclude: + # EXC0001 errcheck: Almost all programs ignore errors on these functions and in most cases it's ok + - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). (is not checked|Errors unhandled) + + exclude-dirs: + # This directory contains copy code from upstream kubernetes/kubernetes, skip it. + - internal/kubernetes + # This is mostly copied from upstream, rather than fixing that code here just ignore the errors. + - internal/podutils + +linters: + enable: + - errcheck + - staticcheck + - unconvert + - gofmt + - goimports + - ineffassign + - govet + - unused + - misspell + - gosec + - copyloopvar # Checks for pointers to enclosing loop variables + - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17 + - lll + +linters-settings: + gosec: + excludes: + - G304 # Potential file inclusion via variable + lll: + line-length: 200 diff --git a/.golangci.yml b/.golangci.yml index 4393501e0..0383bb8c7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,37 +1,51 @@ -linter-settings: - lll: - line-length: 200 - -timeout: 10m - -issues: - exclude-use-default: false - exclude: - # EXC0001 errcheck: Almost all programs ignore errors on these functions and in most cases it's ok - - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). (is not checked|Errors unhandled) - - exclude-dirs: - # This directory contains copy code from upstream kubernetes/kubernetes, skip it. - - internal/kubernetes - # This is mostly copied from upstream, rather than fixing that code here just ignore the errors. - - internal/podutils - +version: "2" linters: enable: - - errcheck - - staticcheck + - copyloopvar + - gosec + - lll + - misspell - unconvert + settings: + gosec: + excludes: + - G304 + lll: + line-length: 200 + exclusions: + generated: lax + rules: + - path: (.+)\.go$ + text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). (is not checked|Errors unhandled) + paths: + - internal/kubernetes + - internal/podutils + - third_party$ + - builtin$ + - examples$ +formatters: + enable: - gofmt - goimports - - ineffassign - - govet - - unused - - misspell - - gosec - - copyloopvar # Checks for pointers to enclosing loop variables - - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17 + exclusions: + generated: lax + paths: + - internal/kubernetes + - internal/podutils + - third_party$ + - builtin$ + - examples$ +issues: + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + max-issues-per-linter: 0 + + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 -linters-settings: - gosec: - excludes: - - G304 # Potential file inclusion via variable + # Make issues output unique by line. + # Default: true + uniq-by-line: false diff --git a/Dockerfile b/Dockerfile index 3f11e9cce..aa7da91ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG GOLANG_CI_LINT_VERSION -FROM golang:1.23 as builder +FROM golang:1.24 as builder ENV PATH /go/bin:/usr/local/go/bin:$PATH ENV GOPATH /go COPY . /go/src/github.com/virtual-kubelet/virtual-kubelet diff --git a/Makefile b/Makefile index d1daee5ce..a46ede1eb 100644 --- a/Makefile +++ b/Makefile @@ -165,19 +165,18 @@ authors: rm -f NEWAUTHORS rm -f GITAUTHORS -checksums_2.3.1.txt: - curl -o checksums_2.3.1.txt -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.1/checksums.txt -kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}.tar.gz: - curl -C - -O -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.1/kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}.tar.gz -kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}: kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}.tar.gz checksums_2.3.1.txt - sha256sum -c --ignore-missing checksums_2.3.1.txt - tar -xvf kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}.tar.gz +SETUP_ENVTEST_VERSION ?= v0.0.0-20250604165838-d6126d850224 +ENVTEST_K8S_VERSION := 1.31.x + +ENVTEST ?= go run sigs.k8s.io/controller-runtime/tools/setup-envtest@$(SETUP_ENVTEST_VERSION) +ENVTEST_DIR ?= $(shell pwd)/.envtest +export KUBEBUILDER_ASSETS ?= $(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(ENVTEST_DIR) -p path) .PHONY: envtest -envtest: kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH} +envtest: # You can add klog flags for debugging, like: -klog.v=10 -klog.logtostderr # klogv2 flags just wraps our existing logrus. - KUBEBUILDER_ASSETS=$(PWD)/kubebuilder_2.3.1_${TEST_OS}_${TEST_ARCH}/bin $(GOTEST) -run=TestEnvtest ./node -envtest=true + $(GOTEST) -run=TestEnvtest ./node -envtest=true .PHONY: fmt fmt: diff --git a/cmd/virtual-kubelet/internal/provider/mock/mock.go b/cmd/virtual-kubelet/internal/provider/mock/mock.go index 45eee89e2..77eeb930f 100644 --- a/cmd/virtual-kubelet/internal/provider/mock/mock.go +++ b/cmd/virtual-kubelet/internal/provider/mock/mock.go @@ -43,7 +43,7 @@ var ( */ // MockProvider implements the virtual-kubelet provider interface and stores pods in memory. -type MockProvider struct { //nolint:golint +type MockProvider struct { nodeName string operatingSystem string internalIP string @@ -55,7 +55,7 @@ type MockProvider struct { //nolint:golint } // MockConfig contains a mock virtual-kubelet's configurable parameters. -type MockConfig struct { //nolint:golint +type MockConfig struct { CPU string `json:"cpu,omitempty"` Memory string `json:"memory,omitempty"` Pods string `json:"pods,omitempty"` @@ -123,17 +123,17 @@ func loadConfig(providerConfig, nodeName string) (config MockConfig, err error) } if _, err = resource.ParseQuantity(config.CPU); err != nil { - return config, fmt.Errorf("Invalid CPU value %v", config.CPU) + return config, fmt.Errorf("invalid CPU value %v", config.CPU) } if _, err = resource.ParseQuantity(config.Memory); err != nil { - return config, fmt.Errorf("Invalid memory value %v", config.Memory) + return config, fmt.Errorf("invalid memory value %v", config.Memory) } if _, err = resource.ParseQuantity(config.Pods); err != nil { - return config, fmt.Errorf("Invalid pods value %v", config.Pods) + return config, fmt.Errorf("invalid pods value %v", config.Pods) } for _, v := range config.Others { if _, err = resource.ParseQuantity(v); err != nil { - return config, fmt.Errorf("Invalid other value %v", v) + return config, fmt.Errorf("invalid other value %v", v) } } return config, nil @@ -349,7 +349,7 @@ func (p *MockProvider) GetPods(ctx context.Context) ([]*v1.Pod, error) { return pods, nil } -func (p *MockProvider) ConfigureNode(ctx context.Context, n *v1.Node) { //nolint:golint +func (p *MockProvider) ConfigureNode(ctx context.Context, n *v1.Node) { ctx, span := trace.StartSpan(ctx, "mock.ConfigureNode") //nolint:staticcheck,ineffassign defer span.End() @@ -367,8 +367,8 @@ func (p *MockProvider) ConfigureNode(ctx context.Context, n *v1.Node) { //nolint } n.Status.NodeInfo.OperatingSystem = os n.Status.NodeInfo.Architecture = "amd64" - n.ObjectMeta.Labels["alpha.service-controller.kubernetes.io/exclude-balancer"] = "true" - n.ObjectMeta.Labels["node.kubernetes.io/exclude-from-external-load-balancers"] = "true" + n.Labels["alpha.service-controller.kubernetes.io/exclude-balancer"] = "true" + n.Labels["node.kubernetes.io/exclude-from-external-load-balancers"] = "true" } // Capacity returns a resource list containing the capacity limits. @@ -671,15 +671,15 @@ func buildKeyFromNames(namespace string, name string) (string, error) { // buildKey is a helper for building the "key" for the providers pod store. func buildKey(pod *v1.Pod) (string, error) { - if pod.ObjectMeta.Namespace == "" { + if pod.Namespace == "" { return "", fmt.Errorf("pod namespace not found") } - if pod.ObjectMeta.Name == "" { + if pod.Name == "" { return "", fmt.Errorf("pod name not found") } - return buildKeyFromNames(pod.ObjectMeta.Namespace, pod.ObjectMeta.Name) + return buildKeyFromNames(pod.Namespace, pod.Name) } // addAttributes adds the specified attributes to the provided span. diff --git a/cmd/virtual-kubelet/internal/provider/store.go b/cmd/virtual-kubelet/internal/provider/store.go index e5a74f9a1..f711513f1 100644 --- a/cmd/virtual-kubelet/internal/provider/store.go +++ b/cmd/virtual-kubelet/internal/provider/store.go @@ -13,7 +13,7 @@ type Store struct { ls map[string]InitFunc } -func NewStore() *Store { //nolint:golint +func NewStore() *Store { return &Store{ ls: make(map[string]InitFunc), } @@ -71,4 +71,4 @@ type InitConfig struct { ResourceManager *manager.ResourceManager } -type InitFunc func(InitConfig) (Provider, error) //nolint:golint +type InitFunc func(InitConfig) (Provider, error) diff --git a/cmd/virtual-kubelet/internal/provider/types.go b/cmd/virtual-kubelet/internal/provider/types.go index 7ef9eb07b..da2d42ca9 100644 --- a/cmd/virtual-kubelet/internal/provider/types.go +++ b/cmd/virtual-kubelet/internal/provider/types.go @@ -7,7 +7,7 @@ const ( OperatingSystemWindows = "windows" ) -type OperatingSystems map[string]bool //nolint:golint +type OperatingSystems map[string]bool var ( // ValidOperatingSystems defines the group of operating systems @@ -18,7 +18,7 @@ var ( } ) -func (o OperatingSystems) Names() []string { //nolint:golint +func (o OperatingSystems) Names() []string { keys := make([]string, 0, len(o)) for k := range o { keys = append(keys, k) diff --git a/go.mod b/go.mod index 21a8b6c06..b98f825f0 100644 --- a/go.mod +++ b/go.mod @@ -1,45 +1,43 @@ module github.com/virtual-kubelet/virtual-kubelet -go 1.23 - -toolchain go1.23.4 +go 1.24.0 require ( contrib.go.opencensus.io/exporter/jaeger v0.2.1 contrib.go.opencensus.io/exporter/ocagent v0.7.0 github.com/bombsimon/logrusr/v3 v3.1.0 - github.com/google/go-cmp v0.6.0 + github.com/google/go-cmp v0.7.0 github.com/gorilla/mux v1.8.1 github.com/mitchellh/go-homedir v1.1.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.61.0 + github.com/prometheus/client_model v0.6.2 + github.com/prometheus/common v0.66.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.1 - github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.10.0 + github.com/spf13/cobra v1.9.1 + github.com/spf13/pflag v1.0.10 + github.com/stretchr/testify v1.11.1 go.opencensus.io v0.24.0 - go.opentelemetry.io/otel v1.33.0 - go.opentelemetry.io/otel/sdk v1.33.0 - go.opentelemetry.io/otel/trace v1.33.0 - golang.org/x/sync v0.10.0 - golang.org/x/time v0.9.0 - google.golang.org/protobuf v1.36.2 + go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/sdk v1.38.0 + go.opentelemetry.io/otel/trace v1.38.0 + golang.org/x/sync v0.17.0 + golang.org/x/time v0.13.0 + google.golang.org/protobuf v1.36.8 gotest.tools v2.2.0+incompatible - k8s.io/api v0.31.4 - k8s.io/apimachinery v0.31.4 - k8s.io/apiserver v0.31.4 - k8s.io/client-go v0.31.4 + k8s.io/api v0.34.0 + k8s.io/apimachinery v0.34.0 + k8s.io/apiserver v0.34.0 + k8s.io/client-go v0.34.0 k8s.io/klog/v2 v2.130.1 - k8s.io/kubelet v0.31.4 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.4 + k8s.io/kubelet v0.34.0 + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + sigs.k8s.io/controller-runtime v0.22.1 ) require ( + cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -48,78 +46,78 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.20.1 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/moby/spdystream v0.4.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.14 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect - go.etcd.io/etcd/client/v3 v3.5.14 // indirect + go.etcd.io/etcd/api/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/v3 v3.6.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect google.golang.org/api v0.30.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/grpc v1.72.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.31.0 // indirect - k8s.io/component-base v0.31.4 // indirect - k8s.io/kms v0.31.4 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/apiextensions-apiserver v0.34.0 // indirect + k8s.io/component-base v0.34.0 // indirect + k8s.io/kms v0.34.0 // indirect + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 6b7100fe0..8d774f6cd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -43,8 +45,6 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -67,7 +67,7 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -75,45 +75,46 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= 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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -144,12 +145,12 @@ 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 v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= -github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/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= @@ -158,12 +159,9 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -173,8 +171,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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= @@ -183,26 +181,24 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +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.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -211,8 +207,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -227,35 +223,36 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +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.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= -github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +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.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -265,52 +262,52 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6/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/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= -go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= -go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= -go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= -go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= -go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= -go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= -go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= -go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= -go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= -go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= -go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= -go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= -go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= +go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= +go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= +go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg= +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.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -320,37 +317,43 @@ 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.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -361,8 +364,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -411,15 +414,15 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -429,8 +432,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -458,22 +461,22 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= 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= @@ -515,8 +518,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= 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= @@ -577,12 +580,10 @@ google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -596,8 +597,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= 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= @@ -608,8 +609,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= -google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -623,10 +624,6 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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= @@ -639,38 +636,40 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.31.4 h1:I2QNzitPVsPeLQvexMEsj945QumYraqv9m74isPDKhM= -k8s.io/api v0.31.4/go.mod h1:d+7vgXLvmcdT1BCo79VEgJxHHryww3V5np2OYTr6jdw= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM= -k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.4 h1:JbtnTaXVYEAYIHJil6Wd74Wif9sd8jVcBw84kwEmp7o= -k8s.io/apiserver v0.31.4/go.mod h1:JJjoTjZ9PTMLdIFq7mmcJy2B9xLN3HeAUebW6xZyIP0= -k8s.io/client-go v0.31.4 h1:t4QEXt4jgHIkKKlx06+W3+1JOwAFU/2OPiOo7H92eRQ= -k8s.io/client-go v0.31.4/go.mod h1:kvuMro4sFYIa8sulL5Gi5GFqUPvfH2O/dXuKstbaaeg= -k8s.io/component-base v0.31.4 h1:wCquJh4ul9O8nNBSB8N/o8+gbfu3BVQkVw9jAUY/Qtw= -k8s.io/component-base v0.31.4/go.mod h1:G4dgtf5BccwiDT9DdejK0qM6zTK0jwDGEKnCmb9+u/s= +k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE= +k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug= +k8s.io/apiextensions-apiserver v0.34.0 h1:B3hiB32jV7BcyKcMU5fDaDxk882YrJ1KU+ZSkA9Qxoc= +k8s.io/apiextensions-apiserver v0.34.0/go.mod h1:hLI4GxE1BDBy9adJKxUxCEHBGZtGfIg98Q+JmTD7+g0= +k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0= +k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.0 h1:Z51fw1iGMqN7uJ1kEaynf2Aec1Y774PqU+FVWCFV3Jg= +k8s.io/apiserver v0.34.0/go.mod h1:52ti5YhxAvewmmpVRqlASvaqxt0gKJxvCeW7ZrwgazQ= +k8s.io/client-go v0.34.0 h1:YoWv5r7bsBfb0Hs2jh8SOvFbKzzxyNo0nSb0zC19KZo= +k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY= +k8s.io/component-base v0.34.0 h1:bS8Ua3zlJzapklsB1dZgjEJuJEeHjj8yTu1gxE2zQX8= +k8s.io/component-base v0.34.0/go.mod h1:RSCqUdvIjjrEm81epPcjQ/DS+49fADvGSCkIP3IC6vg= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.31.4 h1:DVk9T1PHxG7IUMfWs1sDhBTbzGnM7lhMJO8lOzOzTIs= -k8s.io/kms v0.31.4/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubelet v0.31.4 h1:6TokbMv+HnFG7Oe9tVS/J0VPGdC4GnsQZXuZoo7Ixi8= -k8s.io/kubelet v0.31.4/go.mod h1:8ZM5LZyANoVxUtmayUxD/nsl+6GjREo7kSanv8AoL4U= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kms v0.34.0 h1:u+/rcxQ3Jr7gC9AY5nXuEnBcGEB7ZOIJ9cdLdyHyEjQ= +k8s.io/kms v0.34.0/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/kubelet v0.34.0 h1:1nZt1Q6Kfx7xCaTS9vnqR9sjZDxf3cRSQkAFCczULmc= +k8s.io/kubelet v0.34.0/go.mod h1:NqbF8ViVettlZbf9hw9DJhubaWn7rGvDDTcLMDm6tQ0= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo= -sigs.k8s.io/controller-runtime v0.19.4/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.22.1 h1:Ah1T7I+0A7ize291nJZdS1CabF/lB4E++WizgV24Eqg= +sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/manager/resource.go b/internal/manager/resource.go index ccf5e5087..56889d578 100644 --- a/internal/manager/resource.go +++ b/internal/manager/resource.go @@ -32,7 +32,12 @@ type ResourceManager struct { } // NewResourceManager returns a ResourceManager with the internal maps initialized. -func NewResourceManager(podLister corev1listers.PodLister, secretLister corev1listers.SecretLister, configMapLister corev1listers.ConfigMapLister, serviceLister corev1listers.ServiceLister) (*ResourceManager, error) { +func NewResourceManager( + podLister corev1listers.PodLister, + secretLister corev1listers.SecretLister, + configMapLister corev1listers.ConfigMapLister, + serviceLister corev1listers.ServiceLister, +) (*ResourceManager, error) { rm := ResourceManager{ podLister: podLister, secretLister: secretLister, diff --git a/internal/queue/queue.go b/internal/queue/queue.go index 11dafabe1..e30c3cdd9 100644 --- a/internal/queue/queue.go +++ b/internal/queue/queue.go @@ -36,28 +36,28 @@ const ( ) // ShouldRetryFunc is a mechanism to have a custom retry policy -type ShouldRetryFunc func(ctx context.Context, key string, timesTried int, originallyAdded time.Time, err error) (*time.Duration, error) +type ShouldRetryFunc[K any] func(ctx context.Context, key K, timesTried int, originallyAdded time.Time, err error) (*time.Duration, error) // ItemHandler is a callback that handles a single key on the Queue -type ItemHandler func(ctx context.Context, key string) error +type ItemHandler[K any] func(ctx context.Context, key K) error // Queue implements a wrapper around workqueue with native VK instrumentation -type Queue struct { +type Queue[K comparable] struct { // clock is used for testing clock clock.Clock // lock protects running, and the items list / map lock sync.Mutex running bool name string - handler ItemHandler + handler ItemHandler[K] ratelimiter workqueue.TypedRateLimiter[any] // items are items that are marked dirty waiting for processing. items *list.List - // itemInQueue is a map of (string) key -> item while it is in the items list - itemsInQueue map[string]*list.Element - // itemsBeingProcessed is a map of (string) key -> item once it has been moved - itemsBeingProcessed map[string]*queueItem + // itemInQueue is a map of key -> item while it is in the items list + itemsInQueue map[K]*list.Element + // itemsBeingProcessed is a map of key -> item once it has been moved + itemsBeingProcessed map[K]*queueItem[K] // Wait for next semaphore is an exclusive (1 item) lock that is taken every time items is checked to see if there // is an item in queue for work waitForNextItemSemaphore *semaphore.Weighted @@ -65,11 +65,11 @@ type Queue struct { // wakeup wakeupCh chan struct{} - retryFunc ShouldRetryFunc + retryFunc ShouldRetryFunc[K] } -type queueItem struct { - key string +type queueItem[K comparable] struct { + key K plannedToStartWorkAt time.Time redirtiedAt time.Time redirtiedWithRatelimit bool @@ -82,25 +82,25 @@ type queueItem struct { delayedViaRateLimit *time.Duration } -func (item *queueItem) String() string { - return fmt.Sprintf("", item.plannedToStartWorkAt.String(), item.key) +func (item *queueItem[K]) String() string { + return fmt.Sprintf("", item.plannedToStartWorkAt.String(), item.key) } // New creates a queue // // It expects to get a item rate limiter, and a friendly name which is used in logs, and in the internal kubernetes // metrics. If retryFunc is nil, the default retry function. -func New(ratelimiter workqueue.TypedRateLimiter[any], name string, handler ItemHandler, retryFunc ShouldRetryFunc) *Queue { +func New[K comparable](ratelimiter workqueue.TypedRateLimiter[any], name string, handler ItemHandler[K], retryFunc ShouldRetryFunc[K]) *Queue[K] { if retryFunc == nil { retryFunc = DefaultRetryFunc } - return &Queue{ + return &Queue[K]{ clock: clock.RealClock{}, name: name, ratelimiter: ratelimiter, items: list.New(), - itemsBeingProcessed: make(map[string]*queueItem), - itemsInQueue: make(map[string]*list.Element), + itemsBeingProcessed: make(map[K]*queueItem[K]), + itemsInQueue: make(map[K]*list.Element), handler: handler, wakeupCh: make(chan struct{}, 1), waitForNextItemSemaphore: semaphore.NewWeighted(1), @@ -109,7 +109,7 @@ func New(ratelimiter workqueue.TypedRateLimiter[any], name string, handler ItemH } // Enqueue enqueues the key in a rate limited fashion -func (q *Queue) Enqueue(ctx context.Context, key string) { +func (q *Queue[K]) Enqueue(ctx context.Context, key K) { q.lock.Lock() defer q.lock.Unlock() @@ -117,7 +117,7 @@ func (q *Queue) Enqueue(ctx context.Context, key string) { } // EnqueueWithoutRateLimit enqueues the key without a rate limit -func (q *Queue) EnqueueWithoutRateLimit(ctx context.Context, key string) { +func (q *Queue[K]) EnqueueWithoutRateLimit(ctx context.Context, key K) { q.lock.Lock() defer q.lock.Unlock() @@ -125,7 +125,7 @@ func (q *Queue) EnqueueWithoutRateLimit(ctx context.Context, key string) { } // Forget forgets the key -func (q *Queue) Forget(ctx context.Context, key string) { +func (q *Queue[K]) Forget(ctx context.Context, key K) { q.lock.Lock() defer q.lock.Unlock() ctx, span := trace.StartSpan(ctx, "Forget") @@ -164,7 +164,7 @@ func durationDeref(duration *time.Duration, def time.Duration) time.Duration { // If ratelimit is specified, and delay is nil, then the ratelimiter's delay (return from When function) will be used // If ratelimit is specified, and the delay is non-nil, then the delay value will be used // If ratelimit is false, then only delay is used to schedule the work. If delay is nil, it will be considered 0. -func (q *Queue) insert(ctx context.Context, key string, ratelimit bool, delay *time.Duration) *queueItem { +func (q *Queue[K]) insert(ctx context.Context, key K, ratelimit bool, delay *time.Duration) *queueItem[K] { ctx, span := trace.StartSpan(ctx, "insert") defer span.End() @@ -205,7 +205,7 @@ func (q *Queue) insert(ctx context.Context, key string, ratelimit bool, delay *t // Is the item already in the queue? if item, ok := q.itemsInQueue[key]; ok { span.WithField(ctx, "status", "itemsInQueue") - qi := item.Value.(*queueItem) + qi := item.Value.(*queueItem[K]) when := q.clock.Now().Add(durationDeref(delay, 0)) q.adjustPosition(qi, item, when) return qi @@ -213,7 +213,7 @@ func (q *Queue) insert(ctx context.Context, key string, ratelimit bool, delay *t span.WithField(ctx, "status", "added") now := q.clock.Now() - val := &queueItem{ + val := &queueItem[K]{ key: key, plannedToStartWorkAt: now, originallyAdded: now, @@ -233,7 +233,7 @@ func (q *Queue) insert(ctx context.Context, key string, ratelimit bool, delay *t } for item := q.items.Back(); item != nil; item = item.Prev() { - qi := item.Value.(*queueItem) + qi := item.Value.(*queueItem[K]) if qi.plannedToStartWorkAt.Before(val.plannedToStartWorkAt) { q.itemsInQueue[key] = q.items.InsertAfter(val, item) return val @@ -244,7 +244,7 @@ func (q *Queue) insert(ctx context.Context, key string, ratelimit bool, delay *t return val } -func (q *Queue) adjustPosition(qi *queueItem, element *list.Element, when time.Time) { +func (q *Queue[K]) adjustPosition(qi *queueItem[K], element *list.Element, when time.Time) { if when.After(qi.plannedToStartWorkAt) { // The item has already been delayed appropriately return @@ -252,7 +252,7 @@ func (q *Queue) adjustPosition(qi *queueItem, element *list.Element, when time.T qi.plannedToStartWorkAt = when for prev := element.Prev(); prev != nil; prev = prev.Prev() { - item := prev.Value.(*queueItem) + item := prev.Value.(*queueItem[K]) // does this item plan to start work *before* the new time? If so add it if item.plannedToStartWorkAt.Before(when) { q.items.MoveAfter(element, prev) @@ -264,7 +264,7 @@ func (q *Queue) adjustPosition(qi *queueItem, element *list.Element, when time.T } // EnqueueWithoutRateLimitWithDelay enqueues without rate limiting, but work will not start for this given delay period -func (q *Queue) EnqueueWithoutRateLimitWithDelay(ctx context.Context, key string, after time.Duration) { +func (q *Queue[K]) EnqueueWithoutRateLimitWithDelay(ctx context.Context, key K, after time.Duration) { q.lock.Lock() defer q.lock.Unlock() q.insert(ctx, key, false, &after) @@ -273,12 +273,12 @@ func (q *Queue) EnqueueWithoutRateLimitWithDelay(ctx context.Context, key string // Empty returns if the queue has no items in it // // It should only be used for debugging. -func (q *Queue) Empty() bool { +func (q *Queue[K]) Empty() bool { return q.Len() == 0 } // Len includes items that are in the queue, and are being processed -func (q *Queue) Len() int { +func (q *Queue[K]) Len() int { q.lock.Lock() defer q.lock.Unlock() if q.items.Len() != len(q.itemsInQueue) { @@ -289,7 +289,7 @@ func (q *Queue) Len() int { } // UnprocessedLen returns the count of items yet to be processed in the queue -func (q *Queue) UnprocessedLen() int { +func (q *Queue[K]) UnprocessedLen() int { q.lock.Lock() defer q.lock.Unlock() if q.items.Len() != len(q.itemsInQueue) { @@ -300,7 +300,7 @@ func (q *Queue) UnprocessedLen() int { } // ProcessedLen returns the count items that are being processed -func (q *Queue) ItemsBeingProcessedLen() int { +func (q *Queue[K]) ItemsBeingProcessedLen() int { q.lock.Lock() defer q.lock.Unlock() return len(q.itemsBeingProcessed) @@ -309,7 +309,7 @@ func (q *Queue) ItemsBeingProcessedLen() int { // Run starts the workers // // It blocks until context is cancelled, and all of the workers exit. -func (q *Queue) Run(ctx context.Context, workers int) { +func (q *Queue[K]) Run(ctx context.Context, workers int) { if workers <= 0 { panic(fmt.Sprintf("Workers must be greater than 0, got: %d", workers)) } @@ -342,7 +342,7 @@ func (q *Queue) Run(ctx context.Context, workers int) { <-ctx.Done() } -func (q *Queue) worker(ctx context.Context, i int) { +func (q *Queue[K]) worker(ctx context.Context, i int) { ctx = log.WithLogger(ctx, log.G(ctx).WithFields(map[string]interface{}{ "workerId": i, "queue": q.name, @@ -351,7 +351,7 @@ func (q *Queue) worker(ctx context.Context, i int) { } } -func (q *Queue) getNextItem(ctx context.Context) (*queueItem, error) { +func (q *Queue[K]) getNextItem(ctx context.Context) (*queueItem[K], error) { if err := q.waitForNextItemSemaphore.Acquire(ctx, 1); err != nil { return nil, err } @@ -369,7 +369,7 @@ func (q *Queue) getNextItem(ctx context.Context) (*queueItem, error) { case <-q.wakeupCh: } } else { - qi := element.Value.(*queueItem) + qi := element.Value.(*queueItem[K]) timeUntilProcessing := time.Until(qi.plannedToStartWorkAt) // Do we need to sleep? If not, let's party. @@ -402,7 +402,7 @@ func (q *Queue) getNextItem(ctx context.Context) (*queueItem, error) { // handleQueueItem handles a single item // // A return value of "false" indicates that further processing should be stopped. -func (q *Queue) handleQueueItem(ctx context.Context) bool { +func (q *Queue[K]) handleQueueItem(ctx context.Context) bool { ctx, span := trace.StartSpan(ctx, "handleQueueItem") defer span.End() @@ -412,8 +412,7 @@ func (q *Queue) handleQueueItem(ctx context.Context) bool { return false } - // We expect strings to come off the work Queue. - // These are of the form namespace/name. + // We expect pod identifiers (namespace/name, UID) to come off the work Queue. // We do this as the delayed nature of the work Queue means the items in the informer cache may actually be more u // to date that when the item was initially put onto the workqueue. ctx = span.WithField(ctx, "key", qi.key) @@ -431,7 +430,7 @@ func (q *Queue) handleQueueItem(ctx context.Context) bool { return true } -func (q *Queue) handleQueueItemObject(ctx context.Context, qi *queueItem) error { +func (q *Queue[K]) handleQueueItemObject(ctx context.Context, qi *queueItem[K]) error { // This is a separate function / span, because the handleQueueItem span is the time spent waiting for the object // plus the time spend handling the object. Instead, this function / span is scoped to a single object. ctx, span := trace.StartSpan(ctx, "handleQueueItemObject") @@ -459,7 +458,7 @@ func (q *Queue) handleQueueItemObject(ctx context.Context, qi *queueItem) error delete(q.itemsBeingProcessed, qi.key) if qi.forget { q.ratelimiter.Forget(qi.key) - log.G(ctx).WithError(err).Warnf("forgetting %q as told to forget while in progress", qi.key) + log.G(ctx).WithError(err).Warnf("forgetting %+v as told to forget while in progress", qi.key) return nil } @@ -472,7 +471,7 @@ func (q *Queue) handleQueueItemObject(ctx context.Context, qi *queueItem) error delay, err = q.retryFunc(ctx, qi.key, qi.requeues+1, qi.originallyAdded, err) if err == nil { // Put the item back on the work Queue to handle any transient errors. - log.G(ctx).WithError(originalError).Warnf("requeuing %q due to failed sync", qi.key) + log.G(ctx).WithError(originalError).Warnf("requeuing %+v due to failed sync", qi.key) newQI := q.insert(ctx, qi.key, true, delay) newQI.requeues = qi.requeues + 1 newQI.originallyAdded = qi.originallyAdded @@ -480,9 +479,9 @@ func (q *Queue) handleQueueItemObject(ctx context.Context, qi *queueItem) error return nil } if !qi.redirtiedAt.IsZero() { - err = fmt.Errorf("temporarily (requeued) forgetting %q due to: %w", qi.key, err) + err = fmt.Errorf("temporarily (requeued) forgetting %+v due to: %w", qi.key, err) } else { - err = fmt.Errorf("forgetting %q due to: %w", qi.key, err) + err = fmt.Errorf("forgetting %+v due to: %w", qi.key, err) } } @@ -498,20 +497,20 @@ func (q *Queue) handleQueueItemObject(ctx context.Context, qi *queueItem) error return err } -func (q *Queue) String() string { +func (q *Queue[K]) String() string { q.lock.Lock() defer q.lock.Unlock() items := make([]string, 0, q.items.Len()) for next := q.items.Front(); next != nil; next = next.Next() { - items = append(items, next.Value.(*queueItem).String()) + items = append(items, next.Value.(*queueItem[K]).String()) } return fmt.Sprintf("", items) } // DefaultRetryFunc is the default function used for retries by the queue subsystem. -func DefaultRetryFunc(ctx context.Context, key string, timesTried int, originallyAdded time.Time, err error) (*time.Duration, error) { +func DefaultRetryFunc[K any](ctx context.Context, key K, timesTried int, originallyAdded time.Time, err error) (*time.Duration, error) { if timesTried < MaxRetries { return nil, nil } diff --git a/internal/queue/queue_test.go b/internal/queue/queue_test.go index 10c6d82b4..7ac0dd359 100644 --- a/internal/queue/queue_test.go +++ b/internal/queue/queue_test.go @@ -229,7 +229,7 @@ func TestQueueRedirty(t *testing.T) { defer cancel() var times int64 - var q *Queue + var q *Queue[string] q = New(workqueue.DefaultTypedItemBasedRateLimiter[any](), t.Name(), func(ctx context.Context, key string) error { assert.Assert(t, is.Equal(key, "foo")) if atomic.AddInt64(×, 1) == 1 { @@ -279,13 +279,13 @@ func TestHeapConcurrency(t *testing.T) { assert.Assert(t, time.Since(start) < 5*time.Second) } -func checkConsistency(t *testing.T, q *Queue) { +func checkConsistency(t *testing.T, q *Queue[string]) { q.lock.Lock() defer q.lock.Unlock() for next := q.items.Front(); next != nil && next.Next() != nil; next = next.Next() { - qi := next.Value.(*queueItem) - qiNext := next.Next().Value.(*queueItem) + qi := next.Value.(*queueItem[string]) + qiNext := next.Next().Value.(*queueItem[string]) assert.Assert(t, qi.plannedToStartWorkAt.Before(qiNext.plannedToStartWorkAt) || qi.plannedToStartWorkAt.Equal(qiNext.plannedToStartWorkAt)) } } @@ -420,7 +420,7 @@ func TestQueueForgetInProgress(t *testing.T) { defer cancel() var times int64 - var q *Queue + var q *Queue[string] q = New(workqueue.DefaultTypedItemBasedRateLimiter[any](), t.Name(), func(ctx context.Context, key string) error { assert.Assert(t, is.Equal(key, "foo")) atomic.AddInt64(×, 1) diff --git a/internal/test/e2e/framework/pod.go b/internal/test/e2e/framework/pod.go index da9a6fb47..6c306effc 100644 --- a/internal/test/e2e/framework/pod.go +++ b/internal/test/e2e/framework/pod.go @@ -118,7 +118,7 @@ func IsPodReady(pod *corev1.Pod) bool { func (f *Framework) WaitUntilPodDeleted(namespace, name string) (*corev1.Pod, error) { return f.WaitUntilPodCondition(namespace, name, func(event watchapi.Event) (bool, error) { pod := event.Object.(*corev1.Pod) - return event.Type == watchapi.Deleted || pod.ObjectMeta.DeletionTimestamp != nil, nil + return event.Type == watchapi.Deleted || pod.DeletionTimestamp != nil, nil }) } diff --git a/log/log.go b/log/log.go index e662db49f..e3e42f5e4 100644 --- a/log/log.go +++ b/log/log.go @@ -65,6 +65,15 @@ type Fields map[string]interface{} // WithLogger returns a new context with the provided logger. Use in // combination with logger.WithField(s) for great effect. func WithLogger(ctx context.Context, logger Logger) context.Context { + // nopSpan.Logger() passes in nil here any time trace.StartSpan is invoked, which overrides the + // logger from an externally provided context. This inadvertently suppresses all logging for + // the span, including for errors. Prevent clearing the existing logger here if, for example, + // trace.StartSpan does not pass in a new one. To use the default logger again, invoke + // log.WithLogger with log.L explicitly. + if logger == nil { + return ctx + } + return context.WithValue(ctx, loggerKey{}, logger) } diff --git a/node/api/attach.go b/node/api/attach.go index a2a6b13fe..e47e219b9 100644 --- a/node/api/attach.go +++ b/node/api/attach.go @@ -95,7 +95,16 @@ type containerAttachContext struct { // AttachToContainer Implements remotecommand.Attacher // This is called by remotecommand.ServeAttach -func (c *containerAttachContext) AttachToContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteutils.TerminalSize, timeout time.Duration) error { +func (c *containerAttachContext) AttachToContainer( + name string, + uid types.UID, + container string, + in io.Reader, + out, err io.WriteCloser, + tty bool, + resize <-chan remoteutils.TerminalSize, + timeout time.Duration, +) error { eio := &execIO{ tty: tty, diff --git a/node/api/exec.go b/node/api/exec.go index 9f493199a..889c319ff 100644 --- a/node/api/exec.go +++ b/node/api/exec.go @@ -171,7 +171,17 @@ type containerExecContext struct { // ExecInContainer Implements remotecommand.Executor // This is called by remotecommand.ServeExec -func (c *containerExecContext) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteutils.TerminalSize, timeout time.Duration) error { +func (c *containerExecContext) ExecInContainer( + name string, + uid types.UID, + container string, + cmd []string, + in io.Reader, + out, err io.WriteCloser, + tty bool, + resize <-chan remoteutils.TerminalSize, + timeout time.Duration, +) error { eio := &execIO{ tty: tty, diff --git a/node/api/pods.go b/node/api/pods.go index 3e44c6f42..702e131a7 100644 --- a/node/api/pods.go +++ b/node/api/pods.go @@ -24,9 +24,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" ) -type PodListerFunc func(context.Context) ([]*v1.Pod, error) //nolint:golint +type PodListerFunc func(context.Context) ([]*v1.Pod, error) -func HandleRunningPods(getPods PodListerFunc) http.HandlerFunc { //nolint:golint +func HandleRunningPods(getPods PodListerFunc) http.HandlerFunc { if getPods == nil { return NotImplemented } diff --git a/node/lease_controller_v1.go b/node/lease_controller_v1.go index 4f1f3d439..41ee60830 100644 --- a/node/lease_controller_v1.go +++ b/node/lease_controller_v1.go @@ -78,15 +78,15 @@ func newLeaseControllerWithRenewInterval( nodeController *NodeController) (*leaseController, error) { if leaseDurationSeconds <= 0 { - return nil, fmt.Errorf("Lease duration seconds %d is invalid, it must be > 0", leaseDurationSeconds) + return nil, fmt.Errorf("lease duration seconds %d is invalid, it must be > 0", leaseDurationSeconds) } if renewInterval == 0 { - return nil, fmt.Errorf("Lease renew interval %s is invalid, it must be > 0", renewInterval.String()) + return nil, fmt.Errorf("lease renew interval %s is invalid, it must be > 0", renewInterval.String()) } if float64(leaseDurationSeconds) <= renewInterval.Seconds() { - return nil, fmt.Errorf("Lease renew interval %s is invalid, it must be less than lease duration seconds %d", renewInterval.String(), leaseDurationSeconds) + return nil, fmt.Errorf("lease renew interval %s is invalid, it must be less than lease duration seconds %d", renewInterval.String(), leaseDurationSeconds) } return &leaseController{ @@ -128,7 +128,7 @@ func (c *leaseController) sync(ctx context.Context) { return } if node == nil { - err = errors.New("Servernode is null") + err = errors.New("server node is null") log.G(ctx).WithError(err).Error("servernode is null") span.SetStatus(err) return diff --git a/node/lifecycle_test.go b/node/lifecycle_test.go index b9a04b53d..857e74468 100644 --- a/node/lifecycle_test.go +++ b/node/lifecycle_test.go @@ -242,7 +242,7 @@ func (s *system) start(ctx context.Context) error { return s.pc.Err() } -func wireUpSystem(ctx context.Context, provider PodLifecycleHandler, f testFunction) error { +func wireUpSystem(ctx context.Context, provider PodUIDLifecycleHandler, f testFunction) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -266,7 +266,7 @@ func wireUpSystem(ctx context.Context, provider PodLifecycleHandler, f testFunct return wireUpSystemWithClient(ctx, provider, client, f) } -func wireUpSystemWithClient(ctx context.Context, provider PodLifecycleHandler, client kubernetes.Interface, f testFunction) error { +func wireUpSystemWithClient(ctx context.Context, provider PodUIDLifecycleHandler, client kubernetes.Interface, f testFunction) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -293,7 +293,7 @@ func wireUpSystemWithClient(ctx context.Context, provider PodLifecycleHandler, c PodClient: client.CoreV1(), PodInformer: podInformer, EventRecorder: fakeRecorder, - Provider: provider, + Provider: UIDBasedProvider(provider), ConfigMapInformer: configMapInformer, SecretInformer: secretInformer, ServiceInformer: serviceInformer, @@ -441,7 +441,7 @@ func testCreateStartDeleteScenario(ctx context.Context, t *testing.T, s *system, // TODO(Sargun): Make this "smarter" about the status the pod is in. func(ev watch.Event) (bool, error) { pod := ev.Object.(*corev1.Pod) - return pod.Name == p.ObjectMeta.Name, nil + return pod.Name == p.Name, nil }) sendErr(ctx, watchErrCh, watchErr) @@ -628,7 +628,7 @@ func benchmarkCreatePods(ctx context.Context, b *testing.B, s *system) { type podModifier func(*corev1.Pod) func randomizeUID(pod *corev1.Pod) { - pod.ObjectMeta.UID = uuid.NewUUID() + pod.UID = uuid.NewUUID() } func randomizeName(pod *corev1.Pod) { @@ -638,7 +638,7 @@ func randomizeName(pod *corev1.Pod) { func forRealAPIServer(pod *corev1.Pod) { pod.ResourceVersion = "" - pod.ObjectMeta.UID = "" + pod.UID = "" } func nameBasedOnTest(t *testing.T) podModifier { diff --git a/node/mock_test.go b/node/mock_test.go index 5e679331b..b69bf35fd 100644 --- a/node/mock_test.go +++ b/node/mock_test.go @@ -10,6 +10,7 @@ import ( "github.com/virtual-kubelet/virtual-kubelet/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ) const ( @@ -17,7 +18,7 @@ const ( ) var ( - _ PodLifecycleHandler = (*mockProvider)(nil) + _ PodUIDLifecycleHandler = (*mockProvider)(nil) ) type mockProvider struct { @@ -175,11 +176,11 @@ func (p *mockProvider) DeletePod(ctx context.Context, pod *v1.Pod) (err error) { return nil } -// GetPod returns a pod by name that is stored in memory. -func (p *mockProvider) GetPod(ctx context.Context, namespace, name string) (pod *v1.Pod, err error) { - log.G(ctx).Infof("receive GetPod %q", name) +// GetPodByUID returns a pod by name that is stored in memory. +func (p *mockProvider) GetPodByUID(ctx context.Context, namespace, name string, uid types.UID) (pod *v1.Pod, err error) { + log.G(ctx).Infof("receive GetPodByUID %q", name) - key, err := buildKeyFromNames(namespace, name) + key, err := buildKeyFromNames(namespace, name, uid) if err != nil { return nil, err } @@ -190,12 +191,12 @@ func (p *mockProvider) GetPod(ctx context.Context, namespace, name string) (pod return nil, errdefs.NotFoundf("pod \"%s/%s\" is not known to the provider", namespace, name) } -// GetPodStatus returns the status of a pod by name that is "running". +// GetPodStatusByUID returns the status of a pod by name that is "running". // returns nil if a pod by that name is not found. -func (p *mockProvider) GetPodStatus(ctx context.Context, namespace, name string) (*v1.PodStatus, error) { - log.G(ctx).Infof("receive GetPodStatus %q", name) +func (p *mockProvider) GetPodStatusByUID(ctx context.Context, namespace, name string, uid types.UID) (*v1.PodStatus, error) { + log.G(ctx).Infof("receive GetPodStatusByUID %q", name) - pod, err := p.GetPod(ctx, namespace, name) + pod, err := p.GetPodByUID(ctx, namespace, name, uid) if err != nil { return nil, err } @@ -237,21 +238,25 @@ func (p *mockProvider) getUpdates() *waitableInt { return p.updates } -func buildKeyFromNames(namespace string, name string) (string, error) { - return fmt.Sprintf("%s-%s", namespace, name), nil +func buildKeyFromNames(namespace string, name string, uid types.UID) (string, error) { + return fmt.Sprintf("%s/%s/%s", namespace, name, uid), nil } // buildKey is a helper for building the "key" for the providers pod store. func buildKey(pod *v1.Pod) (string, error) { - if pod.ObjectMeta.Namespace == "" { + if pod.Namespace == "" { return "", fmt.Errorf("pod namespace not found") } - if pod.ObjectMeta.Name == "" { + if pod.Name == "" { return "", fmt.Errorf("pod name not found") } - return buildKeyFromNames(pod.ObjectMeta.Namespace, pod.ObjectMeta.Name) + if pod.UID == "" { + return "", fmt.Errorf("pod UID not found") + } + + return buildKeyFromNames(pod.Namespace, pod.Name, pod.UID) } type mockProviderAsync struct { @@ -265,7 +270,7 @@ func (p *mockProviderAsync) NotifyPods(ctx context.Context, notifier func(*v1.Po } type testingProvider interface { - PodLifecycleHandler + PodUIDLifecycleHandler setErrorOnDelete(error) getAttemptedDeletes() *waitableInt getDeletes() *waitableInt diff --git a/node/node.go b/node/node.go index d2a972bde..a6a43735f 100644 --- a/node/node.go +++ b/node/node.go @@ -146,7 +146,7 @@ func WithNodeEnableLeaseV1WithRenewInterval(client coordclientset.LeaseInterface n, ) if err != nil { - return fmt.Errorf("Unable to configure lease controller: %w", err) + return fmt.Errorf("unable to configure lease controller: %w", err) } n.leaseController = leaseController @@ -327,9 +327,9 @@ func (n *NodeController) ensureNode(ctx context.Context, providerNode *corev1.No n.serverNodeLock.Unlock() // Bad things will happen if the node is deleted in k8s and recreated by someone else // we rely on this persisting - providerNode.ObjectMeta.Name = node.Name - providerNode.ObjectMeta.Namespace = node.Namespace - providerNode.ObjectMeta.UID = node.UID + providerNode.Name = node.Name + providerNode.Namespace = node.Namespace + providerNode.UID = node.UID return nil } @@ -346,7 +346,9 @@ func (n *NodeController) controlLoop(ctx context.Context, providerNode *corev1.N var sleepInterval time.Duration if n.leaseController == nil { - log.G(ctx).WithField("pingInterval", n.pingInterval).Debug("lease controller is not enabled, updating node status in Kube API server at Ping Time Interval") + log.G(ctx). + WithField("pingInterval", n.pingInterval). + Debug("lease controller is not enabled, updating node status in Kube API server at Ping Time Interval") sleepInterval = n.pingInterval } else { log.G(ctx).WithField("statusInterval", n.statusInterval).Debug("lease controller in use, updating at statusInterval") @@ -369,8 +371,8 @@ func (n *NodeController) controlLoop(ctx context.Context, providerNode *corev1.N log.G(ctx).Debug("Received node status update") providerNode.Status = updated.Status - providerNode.ObjectMeta.Annotations = updated.Annotations - providerNode.ObjectMeta.Labels = updated.Labels + providerNode.Annotations = updated.Annotations + providerNode.Labels = updated.Labels if err := n.updateStatus(ctx, providerNode, false); err != nil { log.G(ctx).WithError(err).Error("Error handling node status update") } @@ -401,7 +403,7 @@ func (n *NodeController) updateStatus(ctx context.Context, providerNode *corev1. if result, err := n.nodePingController.getResult(ctx); err != nil { return err } else if result.error != nil { - return fmt.Errorf("Not updating node status because node ping failed: %w", result.error) + return fmt.Errorf("not updating node status because node ping failed: %w", result.error) } updateNodeStatusHeartbeat(providerNode) @@ -429,7 +431,7 @@ func (n *NodeController) updateStatus(ctx context.Context, providerNode *corev1. } // Returns a copy of the server node object -func (n *NodeController) getServerNode(ctx context.Context) (*corev1.Node, error) { +func (n *NodeController) getServerNode(_ context.Context) (*corev1.Node, error) { n.serverNodeLock.Lock() defer n.serverNodeLock.Unlock() if n.serverNode == nil { diff --git a/node/pod.go b/node/pod.go index ecee718b0..2b732ea4a 100644 --- a/node/pod.go +++ b/node/pod.go @@ -17,9 +17,9 @@ package node import ( "context" "fmt" - "strings" "time" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/internal/queue" "github.com/google/go-cmp/cmp" @@ -30,6 +30,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" ) @@ -58,6 +59,19 @@ func addPodAttributes(ctx context.Context, span trace.Span, pod *corev1.Pod) con }) } +func (pc *PodController) getPodByUID(ctx context.Context, namespace, name string, uid types.UID) (*corev1.Pod, error) { + pod, err := pc.podsLister.Pods(namespace).Get(name) + switch { + case errors.IsNotFound(err): + return nil, errdefs.NotFoundf("pod %q not found: %w", objectName(namespace, name), err) + case err != nil: + return nil, err + case pod.UID != uid: + return nil, errdefs.NotFoundf("pod %q UID does not match (expected %q, got %q)", objectName(namespace, name), uid, pod.UID) + } + return pod, nil +} + func (pc *PodController) createOrUpdatePod(ctx context.Context, pod *corev1.Pod) error { ctx, span := trace.StartSpan(ctx, "createOrUpdatePod") @@ -85,7 +99,7 @@ func (pc *PodController) createOrUpdatePod(ctx context.Context, pod *corev1.Pod) // Check if the pod is already known by the provider. // NOTE: Some providers return a non-nil error in their GetPod implementation when the pod is not found while some other don't. // Hence, we ignore the error and just act upon the pod if it is non-nil (meaning that the provider still knows about the pod). - if podFromProvider, _ := pc.provider.GetPod(ctx, pod.Namespace, pod.Name); podFromProvider != nil { + if podFromProvider, _ := pc.provider.GetPodByUID(ctx, pod.Namespace, pod.Name, pod.UID); podFromProvider != nil { if !podsEqual(podFromProvider, podForProvider) { log.G(ctx).Debugf("Pod %s exists, updating pod in provider", podFromProvider.Name) if origErr := pc.provider.UpdatePod(ctx, podForProvider); origErr != nil { @@ -124,10 +138,11 @@ func podsEqual(pod1, pod2 *corev1.Pod) bool { return cmp.Equal(pod1.Spec.Containers, pod2.Spec.Containers) && cmp.Equal(pod1.Spec.InitContainers, pod2.Spec.InitContainers) && + cmp.Equal(pod1.Spec.EphemeralContainers, pod2.Spec.EphemeralContainers) && cmp.Equal(pod1.Spec.ActiveDeadlineSeconds, pod2.Spec.ActiveDeadlineSeconds) && cmp.Equal(pod1.Spec.Tolerations, pod2.Spec.Tolerations) && - cmp.Equal(pod1.ObjectMeta.Labels, pod2.Labels) && - cmp.Equal(pod1.ObjectMeta.Annotations, pod2.Annotations) + cmp.Equal(pod1.Labels, pod2.Labels) && + cmp.Equal(pod1.Annotations, pod2.Annotations) } @@ -202,7 +217,7 @@ func shouldSkipPodStatusUpdate(pod *corev1.Pod) bool { pod.Status.Phase == corev1.PodFailed } -func (pc *PodController) updatePodStatus(ctx context.Context, podFromKubernetes *corev1.Pod, key string) error { +func (pc *PodController) updatePodStatus(ctx context.Context, podFromKubernetes *corev1.Pod, key podUIDKey) error { if shouldSkipPodStatusUpdate(podFromKubernetes) { return nil } @@ -220,6 +235,11 @@ func (pc *PodController) updatePodStatus(ctx context.Context, podFromKubernetes kPod.Lock() podFromProvider := kPod.lastPodStatusReceivedFromProvider.DeepCopy() kPod.Unlock() + if podFromProvider == nil { + // there is a small period of time between when we have a known pod initialized but it hasn't + // been fully hydrated from the provider. + return nil + } // Pod deleted by provider due some reasons. e.g. a K8s provider, pod created by deployment would be evicted when node is not ready. // If we do not delete pod in K8s, deployment would not create a new one. if podFromProvider.DeletionTimestamp != nil && podFromKubernetes.DeletionTimestamp == nil { @@ -271,16 +291,11 @@ func (pc *PodController) enqueuePodStatusUpdate(ctx context.Context, pod *corev1 // TODO (Sargun): Make this asynchronousish. Right now, if we are not cache synced, and we receive notifications // from the provider for pods that do not exist yet in our known pods map, we can get into an awkward situation. - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - log.G(ctx).WithError(err).Error("Error getting pod meta namespace key") - span.SetStatus(err) - return - } + key := newPodUIDKey(pod) ctx = span.WithField(ctx, "key", key) var obj interface{} - err = wait.PollUntilContextCancel(ctx, notificationRetryPeriod, true, func(ctx context.Context) (bool, error) { + err := wait.PollUntilContextCancel(ctx, notificationRetryPeriod, true, func(ctx context.Context) (bool, error) { var ok bool obj, ok = pc.knownPods.Load(key) if ok { @@ -297,7 +312,7 @@ func (pc *PodController) enqueuePodStatusUpdate(ctx context.Context, pod *corev1 // should happen, and the pod *actually* exists is the above -- where we haven't been able to finish sync // before context times out. // The other class of errors is non-transient - _, err = pc.podsLister.Pods(pod.Namespace).Get(pod.Name) + _, err := pc.getPodByUID(ctx, pod.Namespace, pod.Name, pod.UID) if err != nil { return false, err } @@ -309,11 +324,11 @@ func (pc *PodController) enqueuePodStatusUpdate(ctx context.Context, pod *corev1 }) if err != nil { - if errors.IsNotFound(err) { - err = fmt.Errorf("Pod %q not found in pod lister: %w", key, err) - log.G(ctx).WithError(err).Debug("Not enqueuing pod status update") + if errdefs.IsNotFound(err) { + err = fmt.Errorf("pod %q not found in pod lister: %w", key, err) + log.G(ctx).WithError(err).Debug("not enqueuing pod status update") } else { - log.G(ctx).WithError(err).Warn("Not enqueuing pod status update due to error from pod lister") + log.G(ctx).WithError(err).Warn("not enqueuing pod status update due to error from pod lister") } span.SetStatus(err) return @@ -332,7 +347,7 @@ func (pc *PodController) enqueuePodStatusUpdate(ctx context.Context, pod *corev1 pc.syncPodStatusFromProvider.Enqueue(ctx, key) } -func (pc *PodController) syncPodStatusFromProviderHandler(ctx context.Context, key string) (retErr error) { +func (pc *PodController) syncPodStatusFromProviderHandler(ctx context.Context, key podUIDKey) (retErr error) { ctx, span := trace.StartSpan(ctx, "syncPodStatusFromProviderHandler") defer span.End() @@ -345,14 +360,13 @@ func (pc *PodController) syncPodStatusFromProviderHandler(ctx context.Context, k } }() - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return pkgerrors.Wrap(err, "error splitting cache key") - } + namespace := key.Namespace + name := key.Name + uid := key.UID - pod, err := pc.podsLister.Pods(namespace).Get(name) + pod, err := pc.getPodByUID(ctx, namespace, name, uid) if err != nil { - if errors.IsNotFound(err) { + if errdefs.IsNotFound(err) { log.G(ctx).WithError(err).Debug("Skipping pod status update for pod missing in Kubernetes") return nil } @@ -362,24 +376,19 @@ func (pc *PodController) syncPodStatusFromProviderHandler(ctx context.Context, k return pc.updatePodStatus(ctx, pod, key) } -func (pc *PodController) deletePodsFromKubernetesHandler(ctx context.Context, key string) (retErr error) { +func (pc *PodController) deletePodsFromKubernetesHandler(ctx context.Context, key podUIDKey) (retErr error) { ctx, span := trace.StartSpan(ctx, "deletePodsFromKubernetesHandler") defer span.End() - uid, metaKey := getUIDAndMetaNamespaceKey(key) - namespace, name, err := cache.SplitMetaNamespaceKey(metaKey) + namespace := key.Namespace + name := key.Name + uid := key.UID + ctx = span.WithFields(ctx, log.Fields{ "namespace": namespace, "name": name, }) - if err != nil { - // Log the error as a warning, but do not requeue the key as it is invalid. - log.G(ctx).Warn(pkgerrors.Wrapf(err, "invalid resource key: %q", key)) - span.SetStatus(err) - return nil - } - defer func() { if retErr == nil { if w, ok := pc.provider.(syncWrapper); ok { @@ -389,18 +398,14 @@ func (pc *PodController) deletePodsFromKubernetesHandler(ctx context.Context, ke }() // If the pod has been deleted from API server, we don't need to do anything. - k8sPod, err := pc.podsLister.Pods(namespace).Get(name) - if errors.IsNotFound(err) { + k8sPod, err := pc.getPodByUID(ctx, namespace, name, uid) + if errdefs.IsNotFound(err) { return nil } if err != nil { span.SetStatus(err) return err } - if string(k8sPod.UID) != uid { - log.G(ctx).WithField("k8sPodUID", k8sPod.UID).WithField("uid", uid).Warn("Not deleting pod because remote pod has different UID") - return nil - } if running(&k8sPod.Status) { log.G(ctx).Error("Force deleting pod in running state") } @@ -408,7 +413,7 @@ func (pc *PodController) deletePodsFromKubernetesHandler(ctx context.Context, ke // We don't check with the provider before doing this delete. At this point, even if an outstanding pod status update // was in progress, deleteOptions := metav1.NewDeleteOptions(0) - deleteOptions.Preconditions = metav1.NewUIDPreconditions(uid) + deleteOptions.Preconditions = &metav1.Preconditions{UID: &uid} err = pc.client.Pods(namespace).Delete(ctx, name, *deleteOptions) if errors.IsNotFound(err) { log.G(ctx).Warnf("Not deleting pod because %v", err) @@ -424,10 +429,3 @@ func (pc *PodController) deletePodsFromKubernetesHandler(ctx context.Context, ke } return nil } - -func getUIDAndMetaNamespaceKey(key string) (string, string) { - idx := strings.LastIndex(key, "/") - uid := key[idx+1:] - metaKey := key[:idx] - return uid, metaKey -} diff --git a/node/pod_test.go b/node/pod_test.go index 6d5098cfe..3b660d172 100644 --- a/node/pod_test.go +++ b/node/pod_test.go @@ -29,6 +29,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/uuid" kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" @@ -53,7 +54,7 @@ func newTestController() *TestController { PodClient: fk8s.CoreV1(), PodInformer: iFactory.Core().V1().Pods(), EventRecorder: testutil.FakeEventRecorder(5), - Provider: p, + Provider: UIDBasedProvider(p), ConfigMapInformer: iFactory.Core().V1().ConfigMaps(), SecretInformer: iFactory.Core().V1().Secrets(), ServiceInformer: iFactory.Core().V1().Services(), @@ -212,9 +213,10 @@ func TestPodCreateNewPod(t *testing.T) { svr := newTestController() pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" //nolint:goconst - pod.ObjectMeta.Name = "nginx" //nolint:goconst + pod.Namespace = "default" //nolint:goconst + pod.Name = "nginx" //nolint:goconst pod.Spec = newPodSpec() + pod.UID = uuid.NewUUID() err := svr.createOrUpdatePod(context.Background(), pod.DeepCopy()) @@ -229,8 +231,8 @@ func TestPodCreateNewPodWithNoDownwardAPIResolution(t *testing.T) { svr.skipDownwardAPIResolution = true pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" //nolint:goconst - pod.ObjectMeta.Name = "nginx" //nolint:goconst + pod.Namespace = "default" //nolint:goconst + pod.Name = "nginx" //nolint:goconst pod.Spec = newPodSpec() pod.Spec.Containers[0].Env = []corev1.EnvVar{ { @@ -242,6 +244,7 @@ func TestPodCreateNewPodWithNoDownwardAPIResolution(t *testing.T) { }, }, } + pod.UID = uuid.NewUUID() err := svr.createOrUpdatePod(context.Background(), pod.DeepCopy()) assert.Check(t, is.Nil(err)) @@ -264,9 +267,10 @@ func TestPodUpdateExisting(t *testing.T) { svr := newTestController() pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" - pod.ObjectMeta.Name = "nginx" + pod.Namespace = "default" + pod.Name = "nginx" pod.Spec = newPodSpec() + pod.UID = uuid.NewUUID() err := svr.createOrUpdatePod(context.Background(), pod.DeepCopy()) assert.Check(t, is.Nil(err)) @@ -288,9 +292,10 @@ func TestPodNoSpecChange(t *testing.T) { svr := newTestController() pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" - pod.ObjectMeta.Name = "nginx" + pod.Namespace = "default" + pod.Name = "nginx" pod.Spec = newPodSpec() + pod.UID = uuid.NewUUID() err := svr.createOrUpdatePod(context.Background(), pod.DeepCopy()) assert.Check(t, is.Nil(err)) @@ -309,8 +314,9 @@ func TestPodStatusDelete(t *testing.T) { ctx := context.Background() c := newTestController() pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" - pod.ObjectMeta.Name = "nginx" + pod.Namespace = "default" + pod.Name = "nginx" + pod.UID = uuid.NewUUID() pod.Spec = newPodSpec() fk8s := fake.NewSimpleClientset(pod) c.client = fk8s @@ -318,7 +324,7 @@ func TestPodStatusDelete(t *testing.T) { podCopy := pod.DeepCopy() deleteTime := v1.Time{Time: time.Now().Add(30 * time.Second)} podCopy.DeletionTimestamp = &deleteTime - key := fmt.Sprintf("%s/%s", pod.Namespace, pod.Name) + key := newPodUIDKey(pod) c.knownPods.Store(key, &knownPod{lastPodStatusReceivedFromProvider: podCopy}) // test pod in provider delete @@ -375,8 +381,8 @@ func TestReCreatePodRace(t *testing.T) { ctx := context.Background() c := newTestController() pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" - pod.ObjectMeta.Name = "nginx" + pod.Namespace = "default" + pod.Name = "nginx" pod.Spec = newPodSpec() pod.UID = "aaaaa" podCopy := pod.DeepCopy() @@ -386,7 +392,7 @@ func TestReCreatePodRace(t *testing.T) { fk8s := &fake.Clientset{} c.client = fk8s c.PodController.client = fk8s.CoreV1() - key := fmt.Sprintf("%s/%s/%s", pod.Namespace, pod.Name, pod.UID) + key := newPodUIDKey(pod) c.knownPods.Store(key, &knownPod{lastPodStatusReceivedFromProvider: podCopy}) c.deletePodsFromKubernetes.Enqueue(ctx, key) if err := c.podsInformer.Informer().GetStore().Add(pod); err != nil { @@ -488,6 +494,42 @@ func TestReCreatePodRace(t *testing.T) { t.Log("pod uid conflict test success") } +func TestUpdatePodStatusWithNilProviderStatus(t *testing.T) { + ctx := context.Background() + c := newTestController() + pod := &corev1.Pod{} + pod.Namespace = "default" + pod.Name = "nginx" + pod.Spec = newPodSpec() + pod.UID = uuid.NewUUID() + + fk8s := fake.NewSimpleClientset(pod) + c.client = fk8s + c.PodController.client = fk8s.CoreV1() + + key := newPodUIDKey(pod) + + // Store a known pod with default values + // This simulates the case where a known pod exists but hasn't been fully hydrated from the provider + c.knownPods.Store(key, &knownPod{}) + + err := c.updatePodStatus(ctx, pod, key) + if err != nil { + t.Fatalf("Expected updatePodStatus to return nil when lastPodStatusReceivedFromProvider is nil, got error: %v", err) + } + + // Verify that the pod still exists in the client (no deletion occurred) + existingPod, err := c.client.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, v1.GetOptions{}) + if err != nil { + t.Fatalf("Expected pod to still exist, got error: %v", err) + } + if existingPod == nil { + t.Fatal("Expected pod to still exist, but it was nil") + } + + t.Log("Successfully handled nil lastPodStatusReceivedFromProvider case") +} + func newPodSpec() corev1.PodSpec { return corev1.PodSpec{ Containers: []corev1.Container{ diff --git a/node/podcontroller.go b/node/podcontroller.go index 97c263a04..c74958cef 100644 --- a/node/podcontroller.go +++ b/node/podcontroller.go @@ -28,7 +28,7 @@ import ( "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" corev1informers "k8s.io/client-go/informers/core/v1" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" @@ -38,13 +38,10 @@ import ( "k8s.io/client-go/util/workqueue" ) -// PodLifecycleHandler defines the interface used by the PodController to react -// to new and changed pods scheduled to the node that is being managed. -// -// Errors produced by these methods should implement an interface from -// github.com/virtual-kubelet/virtual-kubelet/errdefs package in order for the -// core logic to be able to understand the type of failure. -type PodLifecycleHandler interface { +// podLifecycleHandler contains the methods shared between PodUIDLifecycleHandler and the legacy +// PodLifecycleHandler. In the future, when PodLifecycleHandler is replaced with PodUIDLifecycleHandler, +// this common interface can be incorporated directly into PodUIDLifecycleHandler. +type podLifecycleHandler interface { // CreatePod takes a Kubernetes Pod and deploys it within the provider. CreatePod(ctx context.Context, pod *corev1.Pod) error @@ -56,6 +53,22 @@ type PodLifecycleHandler interface { // state, as well as the pod. DeletePod may be called multiple times for the same pod. DeletePod(ctx context.Context, pod *corev1.Pod) error + // GetPods retrieves a list of all pods running on the provider (can be cached). + // The Pods returned are expected to be immutable, and may be accessed + // concurrently outside of the calling goroutine. Therefore it is recommended + // to return a version after DeepCopy. + GetPods(context.Context) ([]*corev1.Pod, error) +} + +// PodLifecycleHandler defines the interface used by the PodController to react +// to new and changed pods scheduled to the node that is being managed. +// +// Errors produced by these methods should implement an interface from +// github.com/virtual-kubelet/virtual-kubelet/errdefs package in order for the +// core logic to be able to understand the type of failure. +type PodLifecycleHandler interface { + podLifecycleHandler + // GetPod retrieves a pod by name from the provider (can be cached). // The Pod returned is expected to be immutable, and may be accessed // concurrently outside of the calling goroutine. Therefore it is recommended @@ -67,12 +80,22 @@ type PodLifecycleHandler interface { // concurrently outside of the calling goroutine. Therefore it is recommended // to return a version after DeepCopy. GetPodStatus(ctx context.Context, namespace, name string) (*corev1.PodStatus, error) +} - // GetPods retrieves a list of all pods running on the provider (can be cached). - // The Pods returned are expected to be immutable, and may be accessed +type PodUIDLifecycleHandler interface { + podLifecycleHandler + + // GetPodByUID retrieves a pod by name and UID from the provider (can be cached). + // The Pod returned is expected to be immutable, and may be accessed // concurrently outside of the calling goroutine. Therefore it is recommended // to return a version after DeepCopy. - GetPods(context.Context) ([]*corev1.Pod, error) + GetPodByUID(ctx context.Context, namespace, name string, uid types.UID) (*corev1.Pod, error) + + // GetPodStatusByUID retrieves the status of a pod by name and UID from the provider. + // The PodStatus returned is expected to be immutable, and may be accessed + // concurrently outside of the calling goroutine. Therefore it is recommended + // to return a version after DeepCopy. + GetPodStatusByUID(ctx context.Context, namespace, name string, uid types.UID) (*corev1.PodStatus, error) } // PodNotifier is used as an extension to PodLifecycleHandler to support async updates of pod statuses. @@ -97,7 +120,7 @@ type PodEventFilterFunc func(context.Context, *corev1.Pod) bool // PodController is the controller implementation for Pod resources. type PodController struct { - provider PodLifecycleHandler + provider PodUIDLifecycleHandler // podsInformer is an informer for Pod resources. podsInformer corev1informers.PodInformer @@ -111,13 +134,13 @@ type PodController struct { resourceManager *manager.ResourceManager - syncPodsFromKubernetes *queue.Queue + syncPodsFromKubernetes *queue.Queue[podUIDKey] // deletePodsFromKubernetes is a queue on which pods are reconciled, and we check if pods are in API server after // the grace period - deletePodsFromKubernetes *queue.Queue + deletePodsFromKubernetes *queue.Queue[podUIDKey] - syncPodStatusFromProvider *queue.Queue + syncPodStatusFromProvider *queue.Queue[podUIDKey] // From the time of creation, to termination the knownPods map will contain the pods key // (derived from Kubernetes' cache library) -> a *knownPod struct. @@ -208,6 +231,15 @@ type PodControllerConfig struct { SkipDownwardAPIResolution bool } +func shouldRetryWrapper(retryFunc ShouldRetryFunc) queue.ShouldRetryFunc[podUIDKey] { + if retryFunc == nil { + retryFunc = DefaultRetryFunc + } + return func(ctx context.Context, key podUIDKey, timesTried int, originallyAdded time.Time, err error) (*time.Duration, error) { + return retryFunc(ctx, key.ObjectName(), timesTried, originallyAdded, err) + } +} + // NewPodController creates a new pod controller with the provided config. func NewPodController(cfg PodControllerConfig) (*PodController, error) { if cfg.PodClient == nil { @@ -245,11 +277,24 @@ func NewPodController(cfg PodControllerConfig) (*PodController, error) { return nil, pkgerrors.Wrap(err, "could not create resource manager") } + // Under the hood, we expect the provider to implement PodUIDLifecycleHandler. + // However, PodControllerConfig accepts PodLifecycleHandler, which might not + // implement this. For backwards compatibility, we haven't changed the type + // in PodControllerConfig, but if the provider doesn't implement PodUIDLifecycleHandler + // we wrap it in uidProviderWrapper. In the future, we will require asyncProvider + // to be implemented directly (PodUIDLifecycleHandler + PodNotifier). + var provider PodUIDLifecycleHandler + if p, ok := cfg.Provider.(PodUIDLifecycleHandler); ok { + provider = p + } else { + provider = &uidProviderWrapper{PodLifecycleHandler: cfg.Provider} + } + pc := &PodController{ client: cfg.PodClient, podsInformer: cfg.PodInformer, podsLister: cfg.PodInformer.Lister(), - provider: cfg.Provider, + provider: provider, resourceManager: rm, ready: make(chan struct{}), done: make(chan struct{}), @@ -258,15 +303,15 @@ func NewPodController(cfg PodControllerConfig) (*PodController, error) { skipDownwardAPIResolution: cfg.SkipDownwardAPIResolution, } - pc.syncPodsFromKubernetes = queue.New(cfg.SyncPodsFromKubernetesRateLimiter, "syncPodsFromKubernetes", pc.syncPodFromKubernetesHandler, cfg.SyncPodsFromKubernetesShouldRetryFunc) - pc.deletePodsFromKubernetes = queue.New(cfg.DeletePodsFromKubernetesRateLimiter, "deletePodsFromKubernetes", pc.deletePodsFromKubernetesHandler, cfg.DeletePodsFromKubernetesShouldRetryFunc) - pc.syncPodStatusFromProvider = queue.New(cfg.SyncPodStatusFromProviderRateLimiter, "syncPodStatusFromProvider", pc.syncPodStatusFromProviderHandler, cfg.SyncPodStatusFromProviderShouldRetryFunc) + pc.syncPodsFromKubernetes = queue.New(cfg.SyncPodsFromKubernetesRateLimiter, "syncPodsFromKubernetes", pc.syncPodFromKubernetesHandler, shouldRetryWrapper(cfg.SyncPodsFromKubernetesShouldRetryFunc)) + pc.deletePodsFromKubernetes = queue.New(cfg.DeletePodsFromKubernetesRateLimiter, "deletePodsFromKubernetes", pc.deletePodsFromKubernetesHandler, shouldRetryWrapper(cfg.DeletePodsFromKubernetesShouldRetryFunc)) + pc.syncPodStatusFromProvider = queue.New(cfg.SyncPodStatusFromProviderRateLimiter, "syncPodStatusFromProvider", pc.syncPodStatusFromProviderHandler, shouldRetryWrapper(cfg.SyncPodStatusFromProviderShouldRetryFunc)) return pc, nil } type asyncProvider interface { - PodLifecycleHandler + PodUIDLifecycleHandler PodNotifier } @@ -293,10 +338,16 @@ func (pc *PodController) Run(ctx context.Context, podSyncWorkers int) (retErr er var provider asyncProvider runProvider := func(context.Context) {} + // Under the hood, we expect the provider to implement PodNotifier. + // However, PodControllerConfig accepts PodLifecycleHandler, which might not + // implement this. For backwards compatibility, we haven't changed the type + // in PodControllerConfig, but if the provider doesn't implement PodNotifier + // we wrap it in syncProviderWrapper. In the future, we will require asyncProvider + // to be implemented directly (PodUIDLifecycleHandler + PodNotifier). if p, ok := pc.provider.(asyncProvider); ok { provider = p } else { - wrapped := &syncProviderWrapper{PodLifecycleHandler: pc.provider, l: pc.podsLister} + wrapped := &syncProviderWrapper{PodUIDLifecycleHandler: pc.provider, l: pc.podsLister} runProvider = wrapped.run provider = wrapped log.G(ctx).Debug("Wrapped non-async provider with async") @@ -319,15 +370,16 @@ func (pc *PodController) Run(ctx context.Context, podSyncWorkers int) (retErr er // syncing. var eventHandler cache.ResourceEventHandler = cache.ResourceEventHandlerFuncs{ - AddFunc: func(pod interface{}) { + AddFunc: func(obj interface{}) { ctx, cancel := context.WithCancel(ctx) defer cancel() ctx, span := trace.StartSpan(ctx, "AddFunc") defer span.End() - if key, err := cache.MetaNamespaceKeyFunc(pod); err != nil { - log.G(ctx).Error(err) - } else { + pod := obj.(*corev1.Pod) + + key := newPodUIDKey(pod) + { ctx = span.WithField(ctx, "key", key) pc.knownPods.Store(key, &knownPod{}) pc.syncPodsFromKubernetes.Enqueue(ctx, key) @@ -344,9 +396,8 @@ func (pc *PodController) Run(ctx context.Context, podSyncWorkers int) (retErr er newPod := newObj.(*corev1.Pod) // At this point we know that something in .metadata or .spec has changed, so we must proceed to sync the pod. - if key, err := cache.MetaNamespaceKeyFunc(newPod); err != nil { - log.G(ctx).Error(err) - } else { + key := newPodUIDKey(newPod) + { ctx = span.WithField(ctx, "key", key) obj, ok := pc.knownPods.Load(key) if !ok { @@ -377,24 +428,23 @@ func (pc *PodController) Run(ctx context.Context, podSyncWorkers int) (retErr er } } }, - DeleteFunc: func(pod interface{}) { + DeleteFunc: func(obj interface{}) { ctx, cancel := context.WithCancel(ctx) defer cancel() ctx, span := trace.StartSpan(ctx, "DeleteFunc") defer span.End() - if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(pod); err != nil { - log.G(ctx).Error(err) - } else { - k8sPod, ok := pod.(*corev1.Pod) - if !ok { - return - } + pod, ok := obj.(*corev1.Pod) + if !ok { + return + } + + key := newPodUIDKey(pod) + { ctx = span.WithField(ctx, "key", key) pc.knownPods.Delete(key) pc.syncPodsFromKubernetes.Enqueue(ctx, key) // If this pod was in the deletion queue, forget about it - key = fmt.Sprintf("%v/%v", key, k8sPod.UID) pc.deletePodsFromKubernetes.Forget(ctx, key) } }, @@ -510,7 +560,7 @@ func (pc *PodController) SyncPodStatusFromProviderQueueItemsBeingProcessedLen() } // syncPodFromKubernetesHandler compares the actual state with the desired, and attempts to converge the two. -func (pc *PodController) syncPodFromKubernetesHandler(ctx context.Context, key string) error { +func (pc *PodController) syncPodFromKubernetesHandler(ctx context.Context, key podUIDKey) error { ctx, span := trace.StartSpan(ctx, "syncPodFromKubernetesHandler") defer span.End() @@ -518,18 +568,14 @@ func (pc *PodController) syncPodFromKubernetesHandler(ctx context.Context, key s ctx = span.WithField(ctx, "key", key) log.G(ctx).WithField("key", key).Debug("sync handled") - // Convert the namespace/name string into a distinct namespace and name. - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // Log the error as a warning, but do not requeue the key as it is invalid. - log.G(ctx).Warn(pkgerrors.Wrapf(err, "invalid resource key: %q", key)) - return nil - } + namespace := key.Namespace + name := key.Name + uid := key.UID - // Get the Pod resource with this namespace/name. - pod, err := pc.podsLister.Pods(namespace).Get(name) + // Get the Pod resource with this namespace/name and UID. + pod, err := pc.getPodByUID(ctx, namespace, name, uid) if err != nil { - if !errors.IsNotFound(err) { + if !errdefs.IsNotFound(err) { // We've failed to fetch the pod from the lister, but the error is not a 404. // Hence, we add the key back to the work queue so we can retry processing it later. err := pkgerrors.Wrapf(err, "failed to fetch pod with key %q from lister", key) @@ -537,7 +583,7 @@ func (pc *PodController) syncPodFromKubernetesHandler(ctx context.Context, key s return err } - pod, err = pc.provider.GetPod(ctx, namespace, name) + pod, err = pc.provider.GetPodByUID(ctx, namespace, name, uid) if err != nil && !errdefs.IsNotFound(err) { err = pkgerrors.Wrapf(err, "failed to fetch pod with key %q from provider", key) span.SetStatus(err) @@ -564,7 +610,7 @@ func (pc *PodController) syncPodFromKubernetesHandler(ctx context.Context, key s } // syncPodInProvider tries and reconciles the state of a pod by comparing its Kubernetes representation and the provider's representation. -func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod, key string) (retErr error) { +func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod, key podUIDKey) (retErr error) { ctx, span := trace.StartSpan(ctx, "syncPodInProvider") defer span.End() @@ -575,7 +621,6 @@ func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod, // more context is here: https://github.com/virtual-kubelet/virtual-kubelet/pull/760 if pod.DeletionTimestamp != nil && !running(&pod.Status) { log.G(ctx).Debug("Force deleting pod from API Server as it is no longer running") - key = fmt.Sprintf("%v/%v", key, pod.UID) pc.deletePodsFromKubernetes.EnqueueWithoutRateLimit(ctx, key) return nil } @@ -612,7 +657,6 @@ func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod, return err } - key = fmt.Sprintf("%v/%v", key, pod.UID) pc.deletePodsFromKubernetes.EnqueueWithoutRateLimitWithDelay(ctx, key, time.Second*time.Duration(*pod.DeletionGracePeriodSeconds)) return nil } @@ -652,8 +696,8 @@ func (pc *PodController) deleteDanglingPods(ctx context.Context, threadiness int // Iterate over the pods known to the provider, marking for deletion those that don't exist in Kubernetes. // Take on this opportunity to populate the list of key that correspond to pods known to the provider. for _, pp := range pps { - if _, err := pc.podsLister.Pods(pp.Namespace).Get(pp.Name); err != nil { - if errors.IsNotFound(err) { + if _, err := pc.getPodByUID(ctx, pp.Namespace, pp.Name, pp.UID); err != nil { + if errdefs.IsNotFound(err) { // The current pod does not exist in Kubernetes, so we mark it for deletion. ptd = append(ptd, pp) continue diff --git a/node/podcontroller_test.go b/node/podcontroller_test.go index 37b31b99f..305e57ca0 100644 --- a/node/podcontroller_test.go +++ b/node/podcontroller_test.go @@ -123,8 +123,8 @@ func TestPodEventFilter(t *testing.T) { } pod := &corev1.Pod{} - pod.ObjectMeta.Namespace = "default" - pod.ObjectMeta.Name = "nginx" + pod.Namespace = "default" + pod.Name = "nginx" pod.Spec = newPodSpec() podC := tc.client.CoreV1().Pods(testNamespace) diff --git a/node/queue.go b/node/queue.go index 0a9137090..af00be39a 100644 --- a/node/queue.go +++ b/node/queue.go @@ -24,11 +24,11 @@ import ( // // If the delay is negative, the item will be scheduled "earlier" than now. This will result in the item being executed // earlier than other items in the FIFO work order. -type ShouldRetryFunc = queue.ShouldRetryFunc +type ShouldRetryFunc = queue.ShouldRetryFunc[string] // DefaultRetryFunc is the default function used for retries by the queue subsystem. Its only policy is that it gives up // after MaxRetries, and falls back to the rate limiter for all other retries. -var DefaultRetryFunc = queue.DefaultRetryFunc +var DefaultRetryFunc = queue.DefaultRetryFunc[string] // MaxRetries is the number of times we try to process a given key before permanently forgetting it. var MaxRetries = queue.MaxRetries diff --git a/node/sync.go b/node/sync.go index 2a0a158f5..0411e4c40 100644 --- a/node/sync.go +++ b/node/sync.go @@ -13,7 +13,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/tools/cache" ) const ( @@ -26,9 +25,9 @@ const ( containerStatusTerminatedMessage = "Container was terminated. The exit code may not reflect the real exit code" ) -// syncProviderWrapper wraps a PodLifecycleHandler to give it async-like pod status notification behavior. +// syncProviderWrapper wraps a PodUIDLifecycleHandler to give it async-like pod status notification behavior. type syncProviderWrapper struct { - PodLifecycleHandler + PodUIDLifecycleHandler notify func(*corev1.Pod) l corev1listers.PodLister @@ -40,27 +39,24 @@ type syncProviderWrapper struct { // This is used to clean up keys for deleted pods after they have been fully deleted in the API server. type syncWrapper interface { - _deletePodKey(context.Context, string) + _deletePodKey(context.Context, podUIDKey) } func (p *syncProviderWrapper) NotifyPods(ctx context.Context, f func(*corev1.Pod)) { p.notify = f } -func (p *syncProviderWrapper) _deletePodKey(ctx context.Context, key string) { +func (p *syncProviderWrapper) _deletePodKey(ctx context.Context, key podUIDKey) { log.G(ctx).WithField("key", key).Debug("Cleaning up pod from deletion cache") p.deletedPods.Delete(key) } func (p *syncProviderWrapper) DeletePod(ctx context.Context, pod *corev1.Pod) error { log.G(ctx).Debug("syncProviderWrappper.DeletePod") - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } + key := newPodUIDKey(pod) p.deletedPods.Store(key, pod) - if err := p.PodLifecycleHandler.DeletePod(ctx, pod.DeepCopy()); err != nil { + if err := p.PodUIDLifecycleHandler.DeletePod(ctx, pod.DeepCopy()); err != nil { log.G(ctx).WithField("key", key).WithError(err).Debug("Removed key from deleted pods cache") // We aren't going to actually delete the pod from the provider since there is an error so delete it from our cache, // otherwise we could end up leaking pods in our deletion cache. @@ -158,7 +154,7 @@ func (p *syncProviderWrapper) updatePodStatus(ctx context.Context, podFromKubern ctx = addPodAttributes(ctx, span, podFromKubernetes) var statusErr error - podStatus, err := p.PodLifecycleHandler.GetPodStatus(ctx, podFromKubernetes.Namespace, podFromKubernetes.Name) + podStatus, err := p.GetPodStatusByUID(ctx, podFromKubernetes.Namespace, podFromKubernetes.Name, podFromKubernetes.UID) if err != nil { if !errdefs.IsNotFound(err) { span.SetStatus(err) @@ -173,18 +169,13 @@ func (p *syncProviderWrapper) updatePodStatus(ctx context.Context, podFromKubern return nil } - key, err := cache.MetaNamespaceKeyFunc(podFromKubernetes) - if err != nil { - span.SetStatus(err) - return err - } - + key := newPodUIDKey(podFromKubernetes) if _, exists := p.deletedPods.Load(key); exists { log.G(ctx).Debug("pod is in known deleted state, ignoring") return nil } - if podFromKubernetes.Status.Phase != corev1.PodRunning && time.Since(podFromKubernetes.ObjectMeta.CreationTimestamp.Time) <= time.Minute { + if podFromKubernetes.Status.Phase != corev1.PodRunning && time.Since(podFromKubernetes.CreationTimestamp.Time) <= time.Minute { span.SetStatus(statusErr) return statusErr } diff --git a/node/uid.go b/node/uid.go new file mode 100644 index 000000000..be5609c5c --- /dev/null +++ b/node/uid.go @@ -0,0 +1,77 @@ +package node + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" +) + +type podUIDKey struct { + Namespace string + Name string + UID types.UID +} + +func newPodUIDKey(pod *corev1.Pod) podUIDKey { + return podUIDKey{ + Namespace: pod.Namespace, + Name: pod.Name, + UID: pod.UID, + } +} + +func objectName(namespace, name string) string { + if len(namespace) > 0 { + return namespace + "/" + name + } + return name +} + +func (k *podUIDKey) ObjectName() string { + return objectName(k.Namespace, k.Name) +} + +func (k *podUIDKey) String() string { + return k.ObjectName() + "/" + string(k.UID) +} + +// uidProviderWrapper wraps a legacy PodLifecycleHandler to handle GetPodByUID/GetPodStatusByUID, +// by ignoring the pod UID and calling GetPod/GetPodStatus using only the pod namespace/name. +type uidProviderWrapper struct { + PodLifecycleHandler +} + +var _ PodUIDLifecycleHandler = (*uidProviderWrapper)(nil) + +func (p *uidProviderWrapper) GetPodByUID(ctx context.Context, namespace, name string, uid types.UID) (*corev1.Pod, error) { + return p.GetPod(ctx, namespace, name) +} + +func (p *uidProviderWrapper) GetPodStatusByUID(ctx context.Context, namespace, name string, uid types.UID) (*corev1.PodStatus, error) { + return p.GetPodStatus(ctx, namespace, name) +} + +// uidBasedProvider wraps a PodUIDLifecycleHandler to implement PodLifecycleHandler, by stubbing +// the legacy GetPod/GetPodStatus methods. These methods are never called if the provider implements +// PodUIDLifecycleHandler, but are required to be implemented as PodControllerConfig takes a +// PodLifecycleHandler. In the future, PodControllerConfig will take an asyncProvider, and this will +// no longer be necessary. +type uidBasedProvider struct { + PodUIDLifecycleHandler +} + +// UIDBasedProvider wraps a PodUIDLifecycleHandler into a PodLifecycleHandler that can be used in +// PodControllerConfig. +func UIDBasedProvider(p PodUIDLifecycleHandler) PodLifecycleHandler { + return &uidBasedProvider{PodUIDLifecycleHandler: p} +} + +func (p *uidBasedProvider) GetPod(ctx context.Context, namespace, name string) (*v1.Pod, error) { + panic("GetPod should never be called when GetPodByUID is implemented") +} + +func (p *uidBasedProvider) GetPodStatus(ctx context.Context, namespace, name string) (*v1.PodStatus, error) { + panic("GetPodStatus should never be called when GetPodStatusByUID is implemented") +} diff --git a/test/e2e/basic.go b/test/e2e/basic.go index 828d38dbb..3dc3c1f70 100644 --- a/test/e2e/basic.go +++ b/test/e2e/basic.go @@ -8,6 +8,7 @@ import ( "time" "github.com/prometheus/common/expfmt" + "github.com/prometheus/common/model" "github.com/virtual-kubelet/virtual-kubelet/internal/podutils" "gotest.tools/assert" v1 "k8s.io/api/core/v1" @@ -143,7 +144,7 @@ func (ts *EndToEndTestSuite) TestGetMetricsResource(t *testing.T) { // decode metrics response bytes to metric family reader := bytes.NewReader(metricsResourceResponse) - parser := expfmt.TextParser{} + parser := expfmt.NewTextParser(model.UTF8Validation) metricsFamilyMap, err := parser.TextToMetricFamilies(reader) if err != nil { t.Fatal(err) @@ -251,8 +252,8 @@ func (ts *EndToEndTestSuite) TestPodLifecycleGracefulDelete(t *testing.T) { // Make sure we saw the delete event, and the delete event was graceful assert.Assert(t, podLast != nil) - assert.Assert(t, podLast.ObjectMeta.GetDeletionGracePeriodSeconds() != nil) - assert.Assert(t, *podLast.ObjectMeta.GetDeletionGracePeriodSeconds() > 0) + assert.Assert(t, podLast.GetDeletionGracePeriodSeconds() != nil) + assert.Assert(t, *podLast.GetDeletionGracePeriodSeconds() > 0) } // TestPodLifecycleForceDelete creates one podsand verifies that the provider has created them