diff --git a/Dockerfile b/Dockerfile index 3da2dbe..b68fbf5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.25.5 AS builder +FROM docker.io/golang:1.26.1 AS builder ARG TARGETOS ARG TARGETARCH ARG GITHUB_TOKEN diff --git a/Makefile b/Makefile index 3487014..7b5cfc8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ # Image URL to use all building/pushing image targets -#IMG ?= controller:latest -IMG = ncr.sky.nhn.no/ghcr/vitistack/ipam-operator:latest +IMG ?= controller:latest # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -20,6 +19,21 @@ CONTAINER_TOOL ?= docker SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec +# Basic colors +BLACK=\033[0;30m +RED=\033[0;31m +GREEN=\033[0;32m +YELLOW=\033[0;33m +BLUE=\033[0;34m +PURPLE=\033[0;35m +CYAN=\033[0;36m +WHITE=\033[0;37m + +# Text formatting +BOLD=\033[1m +UNDERLINE=\033[4m +RESET=\033[0m + .PHONY: all all: build @@ -32,30 +46,6 @@ generate-certs: ## Generates the certs required to run webhooks locally openssl genrsa 2048 > tls.key && \ openssl req -new -x509 -nodes -sha256 -days 365 -key tls.key -out tls.crt -subj "/C=NO/ST=TRONDELAG/L=Trondheim/CN=host.docker.internal" -addext "subjectAltName = DNS:localhost,DNS:host.docker.internal" -##@ Helm - -HELM_VERSION ?= v3.7.1 - -.PHONY: helm -helm: ## Download helm locally if necessary. -ifeq (, $(shell which helm)) - @{ \ - set -e ;\ - curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash ;\ - } -endif - -.PHONY: install-cert-manager -install-cert-manager: helm ## Install cert-manager using Helm. - helm repo add jetstack https://charts.jetstack.io - helm repo update - helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.15.0 --set crds.enabled=true - -.PHONY: uninstall-cert-manager -uninstall-cert-manager: helm ## Uninstall cert-manager using Helm. - helm uninstall cert-manager --namespace cert-manager - kubectl delete namespace cert-manager - ##@ General # The help target prints out all targets with their descriptions organized @@ -91,6 +81,10 @@ fmt: ## Run go fmt against code. vet: ## Run go vet against code. go vet ./... +.PHONY: fix +fix: ## Run go fix against code. + go fix ./... + .PHONY: test test: manifests generate fmt vet setup-envtest ## Run tests. KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out @@ -99,17 +93,30 @@ test: manifests generate fmt vet setup-envtest ## Run tests. # The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. # CertManager is installed by default; skip with: # - CERT_MANAGER_INSTALL_SKIP=true -.PHONY: test-e2e -test-e2e: manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. +KIND_CLUSTER ?= static-ip-operator-test-e2e + +.PHONY: setup-test-e2e +setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist @command -v $(KIND) >/dev/null 2>&1 || { \ echo "Kind is not installed. Please install Kind manually."; \ exit 1; \ } - @$(KIND) get clusters | grep -q 'kind' || { \ - echo "No Kind cluster is running. Please start a Kind cluster before running the e2e tests."; \ - exit 1; \ - } - go test ./test/e2e/ -v -ginkgo.v + @case "$$($(KIND) get clusters)" in \ + *"$(KIND_CLUSTER)"*) \ + echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \ + *) \ + echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \ + $(KIND) create cluster --name $(KIND_CLUSTER) ;; \ + esac + +.PHONY: test-e2e +test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. + KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v + $(MAKE) cleanup-test-e2e + +.PHONY: cleanup-test-e2e +cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests + @$(KIND) delete cluster --name $(KIND_CLUSTER) .PHONY: lint lint: golangci-lint ## Run golangci-lint linter @@ -123,12 +130,36 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes lint-config: golangci-lint ## Verify golangci-lint linter configuration $(GOLANGCI_LINT) config verify -.PHONY: go-security-scan -go-security-scan: ## Run security scan - @echo "Running security scan..." - @command -v gosec >/dev/null 2>&1 || { echo "Installing gosec..."; go install github.com/securego/gosec/v2/cmd/gosec@latest; } - @gosec ./... - @echo "Security scan complete!" +##@ SBOM (Software Bill of Materials) +SYFT ?= $(LOCALBIN)/syft +SYFT_VERSION ?= latest +SBOM_OUTPUT_DIR ?= sbom +SBOM_PROJECT_NAME ?= static-ip-operator + +.PHONY: install-syft +install-syft: $(SYFT) ## Install syft SBOM generator locally +$(SYFT): $(LOCALBIN) + @set -e; echo "Installing syft $(SYFT_VERSION)"; \ + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b $(LOCALBIN) + +.PHONY: sbom-source +sbom-source: install-syft ## Generate SBOMs for Go source code (CycloneDX + SPDX) + @mkdir -p $(SBOM_OUTPUT_DIR) + @echo "Generating source code SBOMs..." + $(SYFT) dir:. --source-name=$(SBOM_PROJECT_NAME) -o cyclonedx-json=$(SBOM_OUTPUT_DIR)/sbom-source.cdx.json + $(SYFT) dir:. --source-name=$(SBOM_PROJECT_NAME) -o spdx-json=$(SBOM_OUTPUT_DIR)/sbom-source.spdx.json + @echo "SBOMs generated: $(SBOM_OUTPUT_DIR)/sbom-source.{cdx,spdx}.json" + +.PHONY: sbom-container +sbom-container: install-syft ## Generate SBOMs for container image (CycloneDX + SPDX, requires IMG) + @mkdir -p $(SBOM_OUTPUT_DIR) + @echo "Generating container SBOMs for $(IMG)..." + $(SYFT) $(IMG) -o cyclonedx-json=$(SBOM_OUTPUT_DIR)/sbom-container.cdx.json + $(SYFT) $(IMG) -o spdx-json=$(SBOM_OUTPUT_DIR)/sbom-container.spdx.json + @echo "SBOMs generated: $(SBOM_OUTPUT_DIR)/sbom-container.{cdx,spdx}.json" + +.PHONY: sbom +sbom: sbom-source ## Alias for sbom-source ##@ Build @@ -138,7 +169,7 @@ build: manifests generate fmt vet ## Build manager binary. .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - export KUBEBUILDER="local" && export IPAM_API_URL="http://host.docker.internal:3000" && go run ./cmd/main.go + go run ./cmd/main.go # If you wish to build the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. @@ -162,10 +193,10 @@ PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le docker-buildx: ## Build and push docker image for the manager for cross-platform support # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - $(CONTAINER_TOOL) buildx create --name ipam-builder - $(CONTAINER_TOOL) buildx use ipam-builder - - $(CONTAINER_TOOL) buildx build --build-arg GITHUB_TOKEN=$$GH_TOKEN --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . - - $(CONTAINER_TOOL) buildx rm ipam-builder + - $(CONTAINER_TOOL) buildx create --name static-ip-operator-builder + $(CONTAINER_TOOL) buildx use static-ip-operator-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm static-ip-operator-builder rm Dockerfile.cross .PHONY: build-installer @@ -197,8 +228,35 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - +##@ Security +.PHONY: gosec +gosec: install-security-scanner ## Run gosec security scan (fails on findings) + $(GOSEC) ./... + +.PHONY: govulncheck +govulncheck: install-govulncheck ## Run govulncheck vulnerability scan (fails on findings) + $(GOVULNCHECK) ./... + +.PHONY: go-security-scan-docker +go-security-scan-docker: ## Run gosec scan using official container (alternative if local install fails) + @echo "Running gosec via Docker container..."; \ + $(CONTAINER_TOOL) run --rm -v $(PWD):/workspace -w /workspace securego/gosec/gosec:latest ./... + ##@ Dependencies +deps: ## Download and verify dependencies + @echo -e "Downloading dependencies..." + @go mod download + @go mod verify + @go mod tidy + @echo -e "Dependencies updated!" + +update-deps: ## Update dependencies + @echo -e "Updating dependencies..." + @go get -u ./... + @go mod tidy + @echo -e "Dependencies updated!" + ## Location to install dependencies to LOCALBIN ?= $(shell pwd)/bin $(LOCALBIN): @@ -211,15 +269,19 @@ KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOSEC ?= $(LOCALBIN)/gosec +GOVULNCHECK ?= $(LOCALBIN)/govulncheck ## Tool Versions -KUSTOMIZE_VERSION ?= v5.6.0 -CONTROLLER_TOOLS_VERSION ?= v0.17.2 +KUSTOMIZE_VERSION ?= latest +CONTROLLER_TOOLS_VERSION ?= latest #ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20) ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}') #ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}') -GOLANGCI_LINT_VERSION ?= v1.63.4 +GOLANGCI_LINT_VERSION ?= latest +GOSEC_VERSION ?= latest +GOVULNCHECK_VERSION ?= latest .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. @@ -247,20 +309,50 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. $(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + + +.PHONY: install-security-scanner +install-security-scanner: $(GOSEC) ## Install gosec security scanner locally (static analysis for security issues) +$(GOSEC): $(LOCALBIN) + @set -e; echo "Attempting to install gosec $(GOSEC_VERSION)"; \ + if ! GOBIN=$(LOCALBIN) go install github.com/securego/gosec/v2/cmd/gosec@$(GOSEC_VERSION) 2>/dev/null; then \ + echo "Primary install failed, attempting install from @main (compatibility fallback)"; \ + if ! GOBIN=$(LOCALBIN) go install github.com/securego/gosec/v2/cmd/gosec@main; then \ + echo "gosec installation failed for versions $(GOSEC_VERSION) and @main"; \ + exit 1; \ + fi; \ + fi; \ + echo "gosec installed at $(GOSEC)"; \ + chmod +x $(GOSEC) + +.PHONY: install-govulncheck +install-govulncheck: $(GOVULNCHECK) ## Install govulncheck locally (vulnerability scanner for Go) +$(GOVULNCHECK): $(LOCALBIN) + @set -e; echo "Attempting to install govulncheck $(GOVULNCHECK_VERSION)"; \ + if ! GOBIN=$(LOCALBIN) go install golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION) 2>/dev/null; then \ + echo "Primary install failed, attempting install from @latest (compatibility fallback)"; \ + if ! GOBIN=$(LOCALBIN) go install golang.org/x/vuln/cmd/govulncheck@latest; then \ + echo "govulncheck installation failed for versions $(GOVULNCHECK_VERSION) and @latest"; \ + exit 1; \ + fi; \ + fi; \ + echo "govulncheck installed at $(GOVULNCHECK)"; \ + chmod +x $(GOVULNCHECK) + # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary # $2 - package url which can be installed # $3 - specific version of package define go-install-tool -@[ -f "$(1)-$(3)" ] || { \ +@[ -f "$(1)-$(3)" ] && [ "$$(readlink -- "$(1)" 2>/dev/null)" = "$(1)-$(3)" ] || { \ set -e; \ package=$(2)@$(3) ;\ echo "Downloading $${package}" ;\ -rm -f $(1) || true ;\ +rm -f $(1) ;\ GOBIN=$(LOCALBIN) go install $${package} ;\ mv $(1) $(1)-$(3) ;\ } ;\ -ln -sf $(1)-$(3) $(1) -endef +ln -sf $$(realpath $(1)-$(3)) $(1) +endef \ No newline at end of file diff --git a/README.md b/README.md index 2b9c2dd..f1a5921 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ kubectl apply -f ./config/webhook/manifests-local.yaml ### Run Controller locally ```sh +export KUBEBUILDER=local +export IPAM_API_URL=https://ipam-api.vitistack.io/v2 make run ``` diff --git a/config/webhook/manifests-local.yaml b/config/webhook/manifests-local.yaml index ea0577a..347f012 100644 --- a/config/webhook/manifests-local.yaml +++ b/config/webhook/manifests-local.yaml @@ -8,7 +8,7 @@ webhooks: - v1 clientConfig: url: https://host.docker.internal:9443/mutate--v1-service - caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR0VENDQXAyZ0F3SUJBZ0lVTFB5RHg0c21md3NOOG1oNGl2QURnOXlWbkNJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZERUxNQWtHQTFVRUJoTUNUazh4RWpBUUJnTlZCQWdNQ1ZSU1QwNUVSVXhCUnpFU01CQUdBMVVFQnd3SgpWSEp2Ym1Sb1pXbHRNUjB3R3dZRFZRUUREQlJvYjNOMExtUnZZMnRsY2k1cGJuUmxjbTVoYkRBZUZ3MHlOVEV3Ck1qQXdOakV4TVRkYUZ3MHlOakV3TWpBd05qRXhNVGRhTUZReEN6QUpCZ05WQkFZVEFrNVBNUkl3RUFZRFZRUUkKREFsVVVrOU9SRVZNUVVjeEVqQVFCZ05WQkFjTUNWUnliMjVrYUdWcGJURWRNQnNHQTFVRUF3d1VhRzl6ZEM1awpiMk5yWlhJdWFXNTBaWEp1WVd3d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURVCmhGMXJXRVNxZmt3RCtXaDZpVGlrNUxFME5wWFhYUlgyTFkwMnlXYWNzOVo4cEZGZ3FBTkxoVFFiZ2o5bmZKNHoKUmw4YWdCN3NtVjR0NXNyRytxaWVyc2ZKamZJcUZ5cUlvd1o3MmJySFB5Y09QVENRYlFtdVk5dVV3SzUyVnhQbgpjZkhDNm1wZ1ROaWthZ0hPZHVROGdNUTZpQ21naDR4MGZzSDJ5MW5vanZaRnVaSTRBVWVsZlY2cmlmNDEwZVdaCnlOckRWRk9KdXNsSXB1UmEwb3d6WDNrMDdReE1BR3FNbGdCRllaQmo3MzRFS2g5VzlNaFdsMjVRSUtHSXFCWWgKenpUSVREaE14NW95cDkyakVoVjNlOWJhR3JGQ2RHeHlWSEdYcXRPdkR1Mk4rRUY3K3JCTXZERlNRVUJoVjlVZgorZlp0ZGNTTVk0SFJSdnZiYUpFWkFnTUJBQUdqZnpCOU1CMEdBMVVkRGdRV0JCU2pmVEFlcEhMYWFVcGNoMTNrCnVqd2daZERvOFRBZkJnTlZIU01FR0RBV2dCU2pmVEFlcEhMYWFVcGNoMTNrdWp3Z1pkRG84VEFQQmdOVkhSTUIKQWY4RUJUQURBUUgvTUNvR0ExVWRFUVFqTUNHQ0NXeHZZMkZzYUc5emRJSVVhRzl6ZEM1a2IyTnJaWEl1YVc1MApaWEp1WVd3d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZm1sbktxNXdaNTF4SGZLaHlGdTRRdy9JWTZ2ZGZrCjRLS1BzTUlVbkdTMlZ5cDlRWCtVOWJINXVrWTF4S2NScy9lNkxXMTY1SktQZXI4YzFSVDVxanoxMmM1U2IvZysKREtnRVhxemdqaVpIRTd1MFFZWGd5SmNwQ2l6WGhLdjVXVHdmbmsrME03UjJQSlRoNllrdHo1dDJHUnFWL3ltVQppWmdMWGxXZEtnYmNidEtmanVlSm1vek5ETU8yU1RBNGJxNy8vMEw5QWxIYWZMVlZJbWxoTjdIbTRWY2tyUm9xCmt1UEYyOC93bTJzZjlxWG96ZFlhd3pzZUlab3FBVWtYSnhiWW1lWldTZ0t5dk11SjhIOGQ4NXBFeS84bHlGangKUW1IRmF5RTh4cjRuNkxJSWs2N1FkRGlwTkErYmFVNDVZdHF6L2RpbEdISXBRT2lQckIrL2tocz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR0VENDQXAyZ0F3SUJBZ0lVUUdkM2VkdmJsc1dycEtqenFYbXJBREU1Z0lrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZERUxNQWtHQTFVRUJoTUNUazh4RWpBUUJnTlZCQWdNQ1ZSU1QwNUVSVXhCUnpFU01CQUdBMVVFQnd3SgpWSEp2Ym1Sb1pXbHRNUjB3R3dZRFZRUUREQlJvYjNOMExtUnZZMnRsY2k1cGJuUmxjbTVoYkRBZUZ3MHlOakF6Ck1USXhNalV4TUROYUZ3MHlOekF6TVRJeE1qVXhNRE5hTUZReEN6QUpCZ05WQkFZVEFrNVBNUkl3RUFZRFZRUUkKREFsVVVrOU9SRVZNUVVjeEVqQVFCZ05WQkFjTUNWUnliMjVrYUdWcGJURWRNQnNHQTFVRUF3d1VhRzl6ZEM1awpiMk5yWlhJdWFXNTBaWEp1WVd3d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNlCjRwa1ZlNlUwdmVVVUVqUVFscS9ab09QbE9qaG50U01uMHM3b1Q5b1Z3dnBPNWxyWDRQR1E2KytZbmFkelpwYVQKU2JwK3pJd1FJWHpjWmJ5TTNIVmI2N3dibFArdmVnR0tFVTNBRnhhWVE3Q1ZWdWJKSkVDRE9uNHZsT1NWNk1YcQpqLzUwN2ZOckZ2Z3ZhaE4vK283SDdpVjFSZjFWbE9VdzZ3SnljMWdzWE5BektaY2FRL0ZHcE5Ca1haWWNpZFRUCittWlBXTE5yMGQ3M00wUTdWaTZreXc0bk9PS1JjNWVOMXAvNE0rTGE1N04vR28wTE1UTCtPTVJoZGlhTm1zUloKZzF3L2JsRVNqMnljVndLTEhLSnp0MUlOMW0yZFNOUHg1YTBQbytMMlhzeFJGOHpNSWRNNVdnYmZHYml4Z2cyRAovb2dTV2txSFlDVnlGbm1Sc0JhUEFnTUJBQUdqZnpCOU1CMEdBMVVkRGdRV0JCU3g4dzJwTDdnQjJrL2c5ZGpsCmtvUE5BNmlPM0RBZkJnTlZIU01FR0RBV2dCU3g4dzJwTDdnQjJrL2c5ZGpsa29QTkE2aU8zREFQQmdOVkhSTUIKQWY4RUJUQURBUUgvTUNvR0ExVWRFUVFqTUNHQ0NXeHZZMkZzYUc5emRJSVVhRzl6ZEM1a2IyTnJaWEl1YVc1MApaWEp1WVd3d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFEeEorM00rZDJzNVZIUjJJZElOMDFsZ3FTemppc2ZkClVVS1ZLMEZ3VUNMVkJ5TXlrdExTTHZGcXNMNEpLUUZkcysycDh0dFdWQW43ckUrQmFPNkM0OEVIOC9RS0p6RTQKOGN4RFpCS2ZuVGhJcEtJekpOS213RElXYzNHOW1BZWRwQi9JK215S040NUdVL3h0UXk5VnlVdXkxTGlURGRQSQpHVlAxOVphNU5aellSNGxnWklBWkkvV3lXbmFCcTkrL3B4ZkN6V1hmU3RlQ1cxR1NxSkFxbmZ3YWExSmN3ajArCnlYcUF1WU52bGswUXlqa2wvbEg0M1dyWmZ5L0dwRndDek1pMkhmRXVjVkE4a05CdEN0aE5JdXl5eUE5SHhiNHAKM1E1K2JpNlZLVVpVTVNhd2tEd3VMczJRR1p1VFpVRCtpcHpkWWlBS2ltWG1XUFBiNHBVb0lsdz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= failurePolicy: Fail name: host.docker.internal rules: @@ -53,7 +53,7 @@ webhooks: name: host.docker.internal clientConfig: url: https://host.docker.internal:9443/validate--v1-service - caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR0VENDQXAyZ0F3SUJBZ0lVTFB5RHg0c21md3NOOG1oNGl2QURnOXlWbkNJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZERUxNQWtHQTFVRUJoTUNUazh4RWpBUUJnTlZCQWdNQ1ZSU1QwNUVSVXhCUnpFU01CQUdBMVVFQnd3SgpWSEp2Ym1Sb1pXbHRNUjB3R3dZRFZRUUREQlJvYjNOMExtUnZZMnRsY2k1cGJuUmxjbTVoYkRBZUZ3MHlOVEV3Ck1qQXdOakV4TVRkYUZ3MHlOakV3TWpBd05qRXhNVGRhTUZReEN6QUpCZ05WQkFZVEFrNVBNUkl3RUFZRFZRUUkKREFsVVVrOU9SRVZNUVVjeEVqQVFCZ05WQkFjTUNWUnliMjVrYUdWcGJURWRNQnNHQTFVRUF3d1VhRzl6ZEM1awpiMk5yWlhJdWFXNTBaWEp1WVd3d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURVCmhGMXJXRVNxZmt3RCtXaDZpVGlrNUxFME5wWFhYUlgyTFkwMnlXYWNzOVo4cEZGZ3FBTkxoVFFiZ2o5bmZKNHoKUmw4YWdCN3NtVjR0NXNyRytxaWVyc2ZKamZJcUZ5cUlvd1o3MmJySFB5Y09QVENRYlFtdVk5dVV3SzUyVnhQbgpjZkhDNm1wZ1ROaWthZ0hPZHVROGdNUTZpQ21naDR4MGZzSDJ5MW5vanZaRnVaSTRBVWVsZlY2cmlmNDEwZVdaCnlOckRWRk9KdXNsSXB1UmEwb3d6WDNrMDdReE1BR3FNbGdCRllaQmo3MzRFS2g5VzlNaFdsMjVRSUtHSXFCWWgKenpUSVREaE14NW95cDkyakVoVjNlOWJhR3JGQ2RHeHlWSEdYcXRPdkR1Mk4rRUY3K3JCTXZERlNRVUJoVjlVZgorZlp0ZGNTTVk0SFJSdnZiYUpFWkFnTUJBQUdqZnpCOU1CMEdBMVVkRGdRV0JCU2pmVEFlcEhMYWFVcGNoMTNrCnVqd2daZERvOFRBZkJnTlZIU01FR0RBV2dCU2pmVEFlcEhMYWFVcGNoMTNrdWp3Z1pkRG84VEFQQmdOVkhSTUIKQWY4RUJUQURBUUgvTUNvR0ExVWRFUVFqTUNHQ0NXeHZZMkZzYUc5emRJSVVhRzl6ZEM1a2IyTnJaWEl1YVc1MApaWEp1WVd3d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZm1sbktxNXdaNTF4SGZLaHlGdTRRdy9JWTZ2ZGZrCjRLS1BzTUlVbkdTMlZ5cDlRWCtVOWJINXVrWTF4S2NScy9lNkxXMTY1SktQZXI4YzFSVDVxanoxMmM1U2IvZysKREtnRVhxemdqaVpIRTd1MFFZWGd5SmNwQ2l6WGhLdjVXVHdmbmsrME03UjJQSlRoNllrdHo1dDJHUnFWL3ltVQppWmdMWGxXZEtnYmNidEtmanVlSm1vek5ETU8yU1RBNGJxNy8vMEw5QWxIYWZMVlZJbWxoTjdIbTRWY2tyUm9xCmt1UEYyOC93bTJzZjlxWG96ZFlhd3pzZUlab3FBVWtYSnhiWW1lWldTZ0t5dk11SjhIOGQ4NXBFeS84bHlGangKUW1IRmF5RTh4cjRuNkxJSWs2N1FkRGlwTkErYmFVNDVZdHF6L2RpbEdISXBRT2lQckIrL2tocz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR0VENDQXAyZ0F3SUJBZ0lVUUdkM2VkdmJsc1dycEtqenFYbXJBREU1Z0lrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZERUxNQWtHQTFVRUJoTUNUazh4RWpBUUJnTlZCQWdNQ1ZSU1QwNUVSVXhCUnpFU01CQUdBMVVFQnd3SgpWSEp2Ym1Sb1pXbHRNUjB3R3dZRFZRUUREQlJvYjNOMExtUnZZMnRsY2k1cGJuUmxjbTVoYkRBZUZ3MHlOakF6Ck1USXhNalV4TUROYUZ3MHlOekF6TVRJeE1qVXhNRE5hTUZReEN6QUpCZ05WQkFZVEFrNVBNUkl3RUFZRFZRUUkKREFsVVVrOU9SRVZNUVVjeEVqQVFCZ05WQkFjTUNWUnliMjVrYUdWcGJURWRNQnNHQTFVRUF3d1VhRzl6ZEM1awpiMk5yWlhJdWFXNTBaWEp1WVd3d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNlCjRwa1ZlNlUwdmVVVUVqUVFscS9ab09QbE9qaG50U01uMHM3b1Q5b1Z3dnBPNWxyWDRQR1E2KytZbmFkelpwYVQKU2JwK3pJd1FJWHpjWmJ5TTNIVmI2N3dibFArdmVnR0tFVTNBRnhhWVE3Q1ZWdWJKSkVDRE9uNHZsT1NWNk1YcQpqLzUwN2ZOckZ2Z3ZhaE4vK283SDdpVjFSZjFWbE9VdzZ3SnljMWdzWE5BektaY2FRL0ZHcE5Ca1haWWNpZFRUCittWlBXTE5yMGQ3M00wUTdWaTZreXc0bk9PS1JjNWVOMXAvNE0rTGE1N04vR28wTE1UTCtPTVJoZGlhTm1zUloKZzF3L2JsRVNqMnljVndLTEhLSnp0MUlOMW0yZFNOUHg1YTBQbytMMlhzeFJGOHpNSWRNNVdnYmZHYml4Z2cyRAovb2dTV2txSFlDVnlGbm1Sc0JhUEFnTUJBQUdqZnpCOU1CMEdBMVVkRGdRV0JCU3g4dzJwTDdnQjJrL2c5ZGpsCmtvUE5BNmlPM0RBZkJnTlZIU01FR0RBV2dCU3g4dzJwTDdnQjJrL2c5ZGpsa29QTkE2aU8zREFQQmdOVkhSTUIKQWY4RUJUQURBUUgvTUNvR0ExVWRFUVFqTUNHQ0NXeHZZMkZzYUc5emRJSVVhRzl6ZEM1a2IyTnJaWEl1YVc1MApaWEp1WVd3d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFEeEorM00rZDJzNVZIUjJJZElOMDFsZ3FTemppc2ZkClVVS1ZLMEZ3VUNMVkJ5TXlrdExTTHZGcXNMNEpLUUZkcysycDh0dFdWQW43ckUrQmFPNkM0OEVIOC9RS0p6RTQKOGN4RFpCS2ZuVGhJcEtJekpOS213RElXYzNHOW1BZWRwQi9JK215S040NUdVL3h0UXk5VnlVdXkxTGlURGRQSQpHVlAxOVphNU5aellSNGxnWklBWkkvV3lXbmFCcTkrL3B4ZkN6V1hmU3RlQ1cxR1NxSkFxbmZ3YWExSmN3ajArCnlYcUF1WU52bGswUXlqa2wvbEg0M1dyWmZ5L0dwRndDek1pMkhmRXVjVkE4a05CdEN0aE5JdXl5eUE5SHhiNHAKM1E1K2JpNlZLVVpVTVNhd2tEd3VMczJRR1p1VFpVRCtpcHpkWWlBS2ltWG1XUFBiNHBVb0lsdz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= failurePolicy: Fail rules: - apiGroups: diff --git a/go.mod b/go.mod index f816dec..926894f 100644 --- a/go.mod +++ b/go.mod @@ -1,103 +1,119 @@ module github.com/vitistack/ipam-operator -go 1.25.5 +go 1.26.1 -godebug default=go1.25.5 +godebug default=go1.26.1 require ( - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 - github.com/vitistack/ipam-api v0.0.1-rc4 - go.universe.tf/metallb v0.14.9 - k8s.io/api v0.32.1 - k8s.io/apimachinery v0.32.1 - k8s.io/client-go v0.32.1 - sigs.k8s.io/controller-runtime v0.20.4 + github.com/onsi/ginkgo/v2 v2.28.1 + github.com/onsi/gomega v1.39.0 + github.com/vitistack/ipam-api v1.0.34 + go.universe.tf/metallb v0.15.3 + k8s.io/api v0.35.2 + k8s.io/apimachinery v0.35.2 + k8s.io/client-go v0.35.2 + sigs.k8s.io/controller-runtime v0.23.3 ) require ( - cel.dev/expr v0.18.0 // indirect - github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect + cel.dev/expr v0.25.1 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // 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-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.21.1 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/jsonreference v0.21.5 // indirect + github.com/go-openapi/swag v0.25.5 // indirect + github.com/go-openapi/swag/cmdutils v0.25.5 // indirect + github.com/go-openapi/swag/conv v0.25.5 // indirect + github.com/go-openapi/swag/fileutils v0.25.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect + github.com/go-openapi/swag/jsonutils v0.25.5 // indirect + github.com/go-openapi/swag/loading v0.25.5 // indirect + github.com/go-openapi/swag/mangling v0.25.5 // indirect + github.com/go-openapi/swag/netutils v0.25.5 // indirect + github.com/go-openapi/swag/stringutils v0.25.5 // indirect + github.com/go-openapi/swag/typeutils v0.25.5 // indirect + github.com/go-openapi/swag/yamlutils v0.25.5 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.22.0 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/cel-go v0.27.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // 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/mailru/easyjson v0.9.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/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/cobra v1.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect - github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/sagikazarmark/locafero v0.12.0 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/cobra v1.10.2 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.mongodb.org/mongo-driver/v2 v2.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.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.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect + go.opentelemetry.io/otel v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect + go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/otel/sdk v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/oauth2 v0.27.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.33.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/term v0.41.0 // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.43.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect + google.golang.org/grpc v1.79.2 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.32.1 // indirect - k8s.io/apiserver v0.32.1 // indirect - k8s.io/component-base v0.32.1 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/apiextensions-apiserver v0.35.2 // indirect + k8s.io/apiserver v0.35.2 // indirect + k8s.io/component-base v0.35.2 // indirect + k8s.io/klog/v2 v2.140.0 // indirect + k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf // indirect + k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 8dbbe62..ba7234b 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,15 @@ -cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo= -cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -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= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= 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= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -17,231 +17,274 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= -github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= +github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +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/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= 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.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= -github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= +github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= +github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= +github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= +github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= +github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= +github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk= +github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= +github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= +github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= +github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= +github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU= +github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14= +github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= +github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= +github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= +github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= -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/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/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo= +github.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +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/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw= +github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/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.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -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.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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= 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/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/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= +github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= +github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= +github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +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.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -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 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/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/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= +github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= 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.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/vitistack/ipam-api v0.0.1-rc4 h1:AKk6Z9GUFJneCY/RhV1iKTQ5l3Ycuf57RSs12r/8ZUg= -github.com/vitistack/ipam-api v0.0.1-rc4/go.mod h1:1wshNfOHyqy5va23qDUujzvlhgaC2GDjzthbXQ65hm4= +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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/vitistack/ipam-api v1.0.34 h1:/5FquaVwNtUDEotW4JucmUR+oq4vPmcMYaWmGX/f4M0= +github.com/vitistack/ipam-api v1.0.34/go.mod h1:Sd7reXtFwYwnZnEAIk9cmJeHoYXxc2sgkNO2suZCKCw= 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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.mongodb.org/mongo-driver/v2 v2.2.1 h1:w5xra3yyu/sGrziMzK1D0cRRaH/b7lWCSsoN6+WV6AM= -go.mongodb.org/mongo-driver/v2 v2.2.1/go.mod h1:qQkDMhCGWl3FN509DfdPd4GRBLU/41zqF/k8eTRceps= -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.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -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.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -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.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= +go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= 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.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.universe.tf/metallb v0.14.9 h1:FYLII4Rpnju8pLY79H0BIoJVQI4mmEzeO9BJ0X44HX8= -go.universe.tf/metallb v0.14.9/go.mod h1:qUh1zVwYAfp3JLxhZrDH20j55QvYwCkI37QU4gUG3ns= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= -google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -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/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.universe.tf/metallb v0.15.3 h1:jmTFharsaP9yBW0p/giOahfuVNTBIvwQqxx2eYxM6fc= +go.universe.tf/metallb v0.15.3/go.mod h1:bvvGwZSz20f/PH1wn1D8GRHsNXXA6ZaYtxTAzyZsQAA= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +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/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c h1:OyQPd6I3pN/9gDxz6L13kYGJgqkpdrAohJRBeXyxlgI= +google.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c/go.mod h1:X2gu9Qwng7Nn009s/r3RUxqkzQNqOrAy79bluY7ojIg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= +google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -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= -k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= -k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= -k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+6UXZw= -k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto= -k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= -k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apiserver v0.32.1 h1:oo0OozRos66WFq87Zc5tclUX2r0mymoVHRq8JmR7Aak= -k8s.io/apiserver v0.32.1/go.mod h1:UcB9tWjBY7aryeI5zAgzVJB/6k7E97bkr1RgqDz0jPw= -k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= -k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= -k8s.io/component-base v0.32.1 h1:/5IfJ0dHIKBWysGV0yKTFfacZ5yNV1sulPh3ilJjRZk= -k8s.io/component-base v0.32.1/go.mod h1:j1iMMHi/sqAHeG5z+O9BFNCF698a1u0186zkjMZQ28w= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= -sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw= +k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60= +k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0= +k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU= +k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= +k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apiserver v0.35.2 h1:rb52v0CZGEL0FkhjS+I6jHflAp7fZ4MIaKcEHX7wmDk= +k8s.io/apiserver v0.35.2/go.mod h1:CROJUAu0tfjZLyYgSeBsBan2T7LUJGh0ucWwTCSSk7g= +k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o= +k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g= +k8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc= +k8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf h1:btPscg4cMql0XdYK2jLsJcNEKmACJz8l+U7geC06FiM= +k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= +sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2/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/utils/ipam-api.go b/internal/utils/ipam-api.go index e4d708d..c3a49ed 100644 --- a/internal/utils/ipam-api.go +++ b/internal/utils/ipam-api.go @@ -20,39 +20,39 @@ const ( IPv4Family = "ipv4" ) -func RequestIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiResponse, error) { +func RequestIP(request apicontracts.IpamAPIRequest) (apicontracts.IpamAPIResponse, error) { // Get OS Environment Variable for IPAM API envVar := IPAMApiUrl ipamApiUrl := os.Getenv(envVar) if ipamApiUrl == "" { - return apicontracts.IpamApiResponse{}, fmt.Errorf("environment variable for IPAM-API %s was not found", envVar) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("environment variable for IPAM-API %s was not found", envVar) } // Update request object with prefix and correct ip-family if strings.Contains(request.Address, ".") { if !strings.Contains(request.Address, "/32") { request.Address = request.Address + "/32" - request.IpFamily = IPv4Family + request.IPFamily = IPv4Family } } if strings.Contains(request.Address, ":") { if !strings.Contains(request.Address, "/128") { request.Address = request.Address + "/128" - request.IpFamily = IPv6Family + request.IPFamily = IPv6Family } } // Marshal the struct to JSON jsonData, err := json.Marshal(request) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("fail to struct request to Json: %v", err) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("fail to struct request to Json: %v", err) } // Make the HTTP POST request req, err := http.NewRequest("POST", ipamApiUrl+"/address", bytes.NewBuffer(jsonData)) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("fail to create new http request: %v", err) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("fail to create new http request: %v", err) } req.Header.Set("Content-Type", "application/json") @@ -61,7 +61,7 @@ func RequestIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiRespons resp, err := client.Do(req) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("fail to send request to: %v , error: %v", ipamApiUrl, err) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("fail to send request to: %v , error: %v", ipamApiUrl, err) } defer func() { @@ -71,10 +71,10 @@ func RequestIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiRespons }() // Decode the response (optional) - var responseData apicontracts.IpamApiResponse + var responseData apicontracts.IpamAPIResponse err = json.NewDecoder(resp.Body).Decode(&responseData) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("fail to decode response %v", err) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("fail to decode response %v", err) } if resp.StatusCode != 200 && resp.StatusCode != 201 { @@ -85,39 +85,39 @@ func RequestIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiRespons } -func DeleteIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiResponse, error) { +func DeleteIP(request apicontracts.IpamAPIRequest) (apicontracts.IpamAPIResponse, error) { // Get OS Environment Variable for IPAM API envVar := IPAMApiUrl ipamApiUrl := os.Getenv(envVar) if ipamApiUrl == "" { - return apicontracts.IpamApiResponse{}, fmt.Errorf("environment variable %s was not found", envVar) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("environment variable %s was not found", envVar) } // Update request object with prefix and ip-family if missing if strings.Contains(request.Address, ".") { if !strings.Contains(request.Address, "/32") { request.Address = request.Address + "/32" - request.IpFamily = IPv4Family + request.IPFamily = IPv4Family } } if strings.Contains(request.Address, ":") { if !strings.Contains(request.Address, "/128") { request.Address = request.Address + "/128" - request.IpFamily = IPv6Family + request.IPFamily = IPv6Family } } // Marshal the struct to JSON jsonData, err := json.Marshal(request) if err != nil { - return apicontracts.IpamApiResponse{}, err + return apicontracts.IpamAPIResponse{}, err } // Make the HTTP POST request req, err := http.NewRequest("DELETE", ipamApiUrl+"/service", bytes.NewBuffer(jsonData)) if err != nil { - return apicontracts.IpamApiResponse{}, err + return apicontracts.IpamAPIResponse{}, err } req.Header.Set("Content-Type", "application/json") @@ -126,7 +126,7 @@ func DeleteIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiResponse resp, err := client.Do(req) if err != nil { - return apicontracts.IpamApiResponse{}, err + return apicontracts.IpamAPIResponse{}, err } defer func() { @@ -136,10 +136,10 @@ func DeleteIP(request apicontracts.IpamApiRequest) (apicontracts.IpamApiResponse }() // Decode the response (optional) - var responseData apicontracts.IpamApiResponse + var responseData apicontracts.IpamAPIResponse err = json.NewDecoder(resp.Body).Decode(&responseData) if err != nil { - return apicontracts.IpamApiResponse{}, err + return apicontracts.IpamAPIResponse{}, err } if resp.StatusCode != 200 && resp.StatusCode != 201 { diff --git a/internal/webhook/v1/get_address_ipam-api.go b/internal/webhook/v1/get_address_ipam-api.go index 2fedc91..98dfbd1 100644 --- a/internal/webhook/v1/get_address_ipam-api.go +++ b/internal/webhook/v1/get_address_ipam-api.go @@ -10,41 +10,41 @@ import ( corev1 "k8s.io/api/core/v1" ) -func getAddressIpamAPI(ipFamily string, annotations map[string]string, service *corev1.Service, secret *corev1.Secret, clusterId string, namespaceId string) (apicontracts.IpamApiResponse, error) { +func getAddressIpamAPI(ipFamily string, annotations map[string]string, service *corev1.Service, secret *corev1.Secret, clusterId string, namespaceId string) (apicontracts.IpamAPIResponse, error) { // Convert retentionPeriodDays from string to int retentionPeriodDays := annotations["ipam.vitistack.io/retention-period-days"] retentionPeriodDaysToInt, err := strconv.Atoi(retentionPeriodDays) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("not able to convert byte retentionPeriodDays to Integer") + return apicontracts.IpamAPIResponse{}, fmt.Errorf("not able to convert byte retentionPeriodDays to Integer") } // Convert denyExternalCleanup from string to bool denyExternalCleanup := annotations["ipam.vitistack.io/deny-external-cleanup"] denyExternalCleanupToBool, err := strconv.ParseBool(denyExternalCleanup) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("not able to convert string denyExternalCleanup to Bool for Service %s", service.GetName()) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("not able to convert string denyExternalCleanup to Bool for Service %s", service.GetName()) } // Create request object for IPAM API - requestAddrObject := apicontracts.IpamApiRequest{ + requestAddrObject := apicontracts.IpamAPIRequest{ Secret: string(secret.Data["secret"]), Zone: annotations["ipam.vitistack.io/zone"], - IpFamily: ipFamily, + IPFamily: ipFamily, Service: apicontracts.Service{ ServiceName: service.GetName(), - NamespaceId: namespaceId, - ClusterId: clusterId, + NamespaceID: namespaceId, + ClusterID: clusterId, RetentionPeriodDays: retentionPeriodDaysToInt, DenyExternalCleanup: denyExternalCleanupToBool, }, } // Request IP from IPAM API - var responseAddrObject apicontracts.IpamApiResponse + var responseAddrObject apicontracts.IpamAPIResponse responseAddrObject, err = utils.RequestIP(requestAddrObject) if err != nil { - return apicontracts.IpamApiResponse{}, fmt.Errorf("failed to request IP for address-family %s for Service %s: %w", ipFamily, service.GetName(), err) + return apicontracts.IpamAPIResponse{}, fmt.Errorf("failed to request IP for address-family %s for Service %s: %w", ipFamily, service.GetName(), err) } return responseAddrObject, nil diff --git a/internal/webhook/v1/remove_address_ipam-api.go b/internal/webhook/v1/remove_address_ipam-api.go index 1fd5123..6bf1aa5 100644 --- a/internal/webhook/v1/remove_address_ipam-api.go +++ b/internal/webhook/v1/remove_address_ipam-api.go @@ -37,15 +37,15 @@ func removeAddressIpamAPI(ipAddress string, annotations map[string]string, servi } // Create remove object for IPAM API - requestAddrObject := apicontracts.IpamApiRequest{ + requestAddrObject := apicontracts.IpamAPIRequest{ Secret: string(secret.Data["secret"]), Zone: annotations["ipam.vitistack.io/zone"], - IpFamily: ipFamily, + IPFamily: ipFamily, Address: ipAddress, Service: apicontracts.Service{ ServiceName: service.GetName(), - NamespaceId: namespaceId, - ClusterId: clusterId, + NamespaceID: namespaceId, + ClusterID: clusterId, RetentionPeriodDays: retentionPeriodDaysToInt, DenyExternalCleanup: denyExternalCleanupToBool, }, diff --git a/internal/webhook/v1/service_webhook.go b/internal/webhook/v1/service_webhook.go index cd90858..857b545 100644 --- a/internal/webhook/v1/service_webhook.go +++ b/internal/webhook/v1/service_webhook.go @@ -21,7 +21,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) // nolint:unused @@ -30,12 +30,24 @@ var servicelog = logf.Log.WithName("ipam-operator") // SetupServiceWebhookWithManager registers the webhook for Service in the manager. func SetupServiceWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr).For(&corev1.Service{}). - WithValidator(&ServiceCustomValidator{Client: mgr.GetClient()}). - WithDefaulter(&ServiceCustomDefaulter{Client: mgr.GetClient()}). + return ctrl.NewWebhookManagedBy(mgr, &corev1.Service{}). + WithValidator(&serviceValidatorAdapter{validator: &ServiceCustomValidator{Client: mgr.GetClient()}}). + WithDefaulter(&serviceDefaulterAdapter{defaulter: &ServiceCustomDefaulter{Client: mgr.GetClient()}}). Complete() } +type serviceValidatorAdapter struct { + validator *ServiceCustomValidator +} + +var _ admission.Defaulter[*corev1.Service] = &serviceDefaulterAdapter{} + +var _ admission.Validator[*corev1.Service] = &serviceValidatorAdapter{} + +type serviceDefaulterAdapter struct { + defaulter *ServiceCustomDefaulter +} + // TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // +kubebuilder:webhook:path=/mutate--v1-service,mutating=true,failurePolicy=Ignore,sideEffects=NoneOnDryRun,groups="",resources=services,verbs=create;update,versions=v1,name=mservice-v1.kb.io,admissionReviewVersions=v1 @@ -51,8 +63,6 @@ type ServiceCustomDefaulter struct { Client client.Client } -var _ webhook.CustomDefaulter = &ServiceCustomDefaulter{} - // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. // NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here. // Modifying the path for an invalid path can cause API server errors; failing to locate the webhook. @@ -67,5 +77,3 @@ type ServiceCustomValidator struct { // TODO(user): Add more fields as needed for validation Client client.Client } - -var _ webhook.CustomValidator = &ServiceCustomValidator{} diff --git a/internal/webhook/v1/service_webhook_mutation.go b/internal/webhook/v1/service_webhook_mutation.go index dc9a5ad..20ad7cf 100644 --- a/internal/webhook/v1/service_webhook_mutation.go +++ b/internal/webhook/v1/service_webhook_mutation.go @@ -18,11 +18,9 @@ package v1 import ( "context" - "fmt" "strings" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" utils "github.com/vitistack/ipam-operator/internal/utils" @@ -31,14 +29,9 @@ import ( ) // Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind Service. -func (d *ServiceCustomDefaulter) Default(ctx context.Context, obj runtime.Object) error { +func (d *serviceDefaulterAdapter) Default(ctx context.Context, obj *corev1.Service) error { - // Check if the object is of type Service - service, ok := obj.(*corev1.Service) - - if !ok { - return fmt.Errorf("mutation: expected an Service object but got %T", obj) - } + service := obj // Get the admission request from the context! req, _ := admission.RequestFromContext(ctx) @@ -63,26 +56,26 @@ func (d *ServiceCustomDefaulter) Default(ctx context.Context, obj runtime.Object // DryRun the object to check if it pass dry run validation. servicelog.Info("Mutation: Dry run .spec Started:", "name", service.GetName()) - if err := validateServiceSpec(ctx, d.Client, service, string(req.Operation)); err != nil { + if err := validateServiceSpec(ctx, d.defaulter.Client, service, string(req.Operation)); err != nil { servicelog.Info("Mutation: Dry run .spec Failed:", "name", service.GetName(), "error", err) return err } // Check if Metallb Controller is actually running - if err := validateMetallbOperator(ctx, d.Client); err != nil { + if err := validateMetallbOperator(ctx, d.defaulter.Client); err != nil { servicelog.Info("Mutation: Metallb operator is not available. Please make sure Metallb is installed and ready.") return err } // Get kube-system namespace uid for cluster identification - clusterId, err := getClusterID(d.Client) + clusterId, err := getClusterID(d.defaulter.Client) if err != nil { servicelog.Info("Mutation: Failed to get cluster ID") return err } // Get namespace uid for Service namespace identification - namespaceId, err := getNameSpaceID(d.Client, service) + namespaceId, err := getNameSpaceID(d.defaulter.Client, service) if err != nil { servicelog.Info("Mutation: Failed to get namespace ID") return err @@ -112,7 +105,7 @@ func (d *ServiceCustomDefaulter) Default(ctx context.Context, obj runtime.Object } // Get Secret - secret, err := getSecret(annotations, service, d.Client) + secret, err := getSecret(annotations, service, d.defaulter.Client) if err != nil { servicelog.Info("Mutation: Failed to get secret", "error", err) return err @@ -120,7 +113,7 @@ func (d *ServiceCustomDefaulter) Default(ctx context.Context, obj runtime.Object // Request Addresses from IPAM API ipFamily := annotations["ipam.vitistack.io/ip-family"] - var retrievedIPv4Address, retrievedIPv6Address apicontracts.IpamApiResponse + var retrievedIPv4Address, retrievedIPv6Address apicontracts.IpamAPIResponse if !strings.Contains(annotations["ipam.vitistack.io/addresses"], ".") && (ipFamily == IPv4Family || ipFamily == DualFamily) { retrievedIPv4Address, err = getAddressIpamAPI(IPv4Family, annotations, service, secret, clusterId, namespaceId) diff --git a/internal/webhook/v1/service_webhook_validate_create.go b/internal/webhook/v1/service_webhook_validate_create.go index b660270..af64f3d 100644 --- a/internal/webhook/v1/service_webhook_validate_create.go +++ b/internal/webhook/v1/service_webhook_validate_create.go @@ -22,22 +22,18 @@ import ( "strings" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" utils "github.com/vitistack/ipam-operator/internal/utils" ) // ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type Service. -func (v *ServiceCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { +func (v *serviceValidatorAdapter) ValidateCreate(ctx context.Context, obj *corev1.Service) (admission.Warnings, error) { // Initialize Error Object var err error - service, ok := obj.(*corev1.Service) - if !ok { - return nil, fmt.Errorf("expected a Service object but got %T", obj) - } + service := obj // Get the admission request from the context! req, _ := admission.RequestFromContext(ctx) @@ -57,14 +53,14 @@ func (v *ServiceCustomValidator) ValidateCreate(ctx context.Context, obj runtime } // Get kube-system namespace uid for cluster identification - clusterId, err := getClusterID(v.Client) + clusterId, err := getClusterID(v.validator.Client) if err != nil { servicelog.Info("Validate Create: Failed to get cluster ID") return nil, err } // Get namespace uid for Service namespace identification - namespaceId, err := getNameSpaceID(v.Client, service) + namespaceId, err := getNameSpaceID(v.validator.Client, service) if err != nil { servicelog.Info("Validate Create: Failed to get namespace ID") return nil, err @@ -74,7 +70,7 @@ func (v *ServiceCustomValidator) ValidateCreate(ctx context.Context, obj runtime annotations := service.GetAnnotations() // Get Secret - secret, err := getSecret(annotations, service, v.Client) + secret, err := getSecret(annotations, service, v.validator.Client) if err != nil { servicelog.Info("Validate Crate: Failed to get secret", "error", err) return nil, err @@ -104,7 +100,7 @@ func (v *ServiceCustomValidator) ValidateCreate(ctx context.Context, obj runtime return nil, fmt.Errorf("validation create failed for service %s, Please verify f.ex secret", service.GetName()) } - if err := utils.AddIpAddressesToPool(v.Client, annotations, addrSlice); err != nil { + if err := utils.AddIpAddressesToPool(v.validator.Client, annotations, addrSlice); err != nil { servicelog.Info("Unable to add IP-addresses to pool", "name", service.GetName(), "pool", annotations["ipam.vitistack.io/zone"], "Error", err) return nil, err } diff --git a/internal/webhook/v1/service_webhook_validate_delete.go b/internal/webhook/v1/service_webhook_validate_delete.go index cac24f8..dcb166c 100644 --- a/internal/webhook/v1/service_webhook_validate_delete.go +++ b/internal/webhook/v1/service_webhook_validate_delete.go @@ -22,18 +22,14 @@ import ( "strings" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" utils "github.com/vitistack/ipam-operator/internal/utils" ) // ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type Service. -func (v *ServiceCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - service, ok := obj.(*corev1.Service) - if !ok { - return nil, fmt.Errorf("expected a Service object but got %T", obj) - } +func (v *serviceValidatorAdapter) ValidateDelete(ctx context.Context, obj *corev1.Service) (admission.Warnings, error) { + service := obj // Do not Validate if the service type is not LoadBalancer. if service.Spec.Type != LoadBalancer { @@ -42,20 +38,20 @@ func (v *ServiceCustomValidator) ValidateDelete(ctx context.Context, obj runtime } // Check if Metallb Controller is actually running - if err := validateMetallbOperator(ctx, v.Client); err != nil { + if err := validateMetallbOperator(ctx, v.validator.Client); err != nil { servicelog.Info("Validate Delete: Metallb operator is not available. Please make sure Metallb is installed and ready.") return nil, err } // Get kube-system namespace uid for cluster identification - clusterId, err := getClusterID(v.Client) + clusterId, err := getClusterID(v.validator.Client) if err != nil { servicelog.Info("Validate Delete: Failed to get cluster ID") return nil, err } // Get namespace uid for Service namespace identification - namespaceId, err := getNameSpaceID(v.Client, service) + namespaceId, err := getNameSpaceID(v.validator.Client, service) if err != nil { servicelog.Info("Validate Delete: Failed to get namespace ID") return nil, err @@ -65,7 +61,7 @@ func (v *ServiceCustomValidator) ValidateDelete(ctx context.Context, obj runtime annotations := service.GetAnnotations() // Get Secret - secret, err := getSecret(annotations, service, v.Client) + secret, err := getSecret(annotations, service, v.validator.Client) if err != nil { servicelog.Info("Validate Crate: Failed to get secret", "error", err) return nil, err @@ -90,7 +86,7 @@ func (v *ServiceCustomValidator) ValidateDelete(ctx context.Context, obj runtime } // Remove Metallb Addresses from IPAddressPool - if err := utils.RemoveIPAddressesFromPool(v.Client, annotations, addresses); err != nil { + if err := utils.RemoveIPAddressesFromPool(v.validator.Client, annotations, addresses); err != nil { for _, addr := range addresses { if err := updateAddressIpamAPI(addr, annotations, service, secret, clusterId, namespaceId); err != nil { servicelog.Info("Validate Delete: Failed to rollback ip-address", "service", service.GetName(), "ip", addresses[0], "Error", err) diff --git a/internal/webhook/v1/service_webhook_validate_update.go b/internal/webhook/v1/service_webhook_validate_update.go index abed4d2..4de8b35 100644 --- a/internal/webhook/v1/service_webhook_validate_update.go +++ b/internal/webhook/v1/service_webhook_validate_update.go @@ -22,7 +22,6 @@ import ( "strings" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "reflect" @@ -31,16 +30,10 @@ import ( ) // ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type Service. -func (v *ServiceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - newService, ok := newObj.(*corev1.Service) - if !ok { - return nil, fmt.Errorf("expected a Service object for the newObj but got %T", newObj) - } +func (v *serviceValidatorAdapter) ValidateUpdate(ctx context.Context, oldObj, newObj *corev1.Service) (admission.Warnings, error) { + newService := newObj - oldService, ok := oldObj.(*corev1.Service) - if !ok { - return nil, fmt.Errorf("expected a Service object for the oldObj but got %T", oldObj) - } + oldService := oldObj // Get the admission request from the context! req, _ := admission.RequestFromContext(ctx) @@ -71,14 +64,14 @@ func (v *ServiceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, new } // Get kube-system namespace uid for cluster identification - clusterId, err := getClusterID(v.Client) + clusterId, err := getClusterID(v.validator.Client) if err != nil { servicelog.Info("Validate Update: Failed to get cluster ID") return nil, err } // Get namespace uid for Service namespace identification - namespaceId, err := getNameSpaceID(v.Client, oldService) + namespaceId, err := getNameSpaceID(v.validator.Client, oldService) if err != nil { servicelog.Info("Validate Update: Failed to get namespace ID") return nil, err @@ -104,13 +97,13 @@ func (v *ServiceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, new // Get Secrets - oldSecret, err := getSecret(oldAnnotations, oldService, v.Client) + oldSecret, err := getSecret(oldAnnotations, oldService, v.validator.Client) if err != nil { servicelog.Info("Validate Update: Failed to get old secret", "error", err) return nil, err } - newSecret, err := getSecret(newAnnotations, newService, v.Client) + newSecret, err := getSecret(newAnnotations, newService, v.validator.Client) if err != nil { servicelog.Info("Validate Update: Failed to get new secret", "error", err) return nil, err @@ -160,13 +153,13 @@ func (v *ServiceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, new // Update Metallb AddressPool if len(newPrefixes) > 0 { servicelog.Info("Validate Update: Add prefixes to Metallb Addresspool", "name", newService.GetName(), "pool", oldAnnotations["ipam.vitistack.io/zone"]) - if err := utils.AddIpAddressesToPool(v.Client, newAnnotations, newPrefixes); err != nil { + if err := utils.AddIpAddressesToPool(v.validator.Client, newAnnotations, newPrefixes); err != nil { servicelog.Info("Validate Update: Unable to add new IP-addresses to pool", "name", newService.GetName(), "pool", newAnnotations["ipam.vitistack.io/zone"], "Error", err) } } if len(removePrefixes) > 0 { servicelog.Info("Validate Update: Remove out-dated prefixes from Metallb Addresspool", "name", newService.GetName(), "pool", oldAnnotations["ipam.vitistack.io/zone"]) - if err := utils.RemoveIPAddressesFromPool(v.Client, oldAnnotations, removePrefixes); err != nil { + if err := utils.RemoveIPAddressesFromPool(v.validator.Client, oldAnnotations, removePrefixes); err != nil { servicelog.Info("Validate Update: Unable to remove old IP-addresses from pool", "name", newService.GetName(), "pool", oldAnnotations["ipam.vitistack.io/zone"], "Error", err) } } diff --git a/internal/webhook/v1/update_address_ipam-api.go b/internal/webhook/v1/update_address_ipam-api.go index 648e99c..378f621 100644 --- a/internal/webhook/v1/update_address_ipam-api.go +++ b/internal/webhook/v1/update_address_ipam-api.go @@ -37,15 +37,15 @@ func updateAddressIpamAPI(ipAddress string, annotations map[string]string, servi } // Create validate object for IPAM API - requestAddrObject := apicontracts.IpamApiRequest{ + requestAddrObject := apicontracts.IpamAPIRequest{ Secret: string(secret.Data["secret"]), Zone: annotations["ipam.vitistack.io/zone"], - IpFamily: ipFamily, + IPFamily: ipFamily, Address: ipAddress, Service: apicontracts.Service{ ServiceName: service.GetName(), - NamespaceId: namespaceId, - ClusterId: clusterId, + NamespaceID: namespaceId, + ClusterID: clusterId, RetentionPeriodDays: retentionPeriodDaysToInt, DenyExternalCleanup: denyExternalCleanupToBool, }, diff --git a/internal/webhook/v1/update_secret.go b/internal/webhook/v1/update_secret.go index 54e8fb4..14e1525 100644 --- a/internal/webhook/v1/update_secret.go +++ b/internal/webhook/v1/update_secret.go @@ -58,16 +58,16 @@ func updateSecretIpamAPI(ipAddress string, annotations map[string]string, servic } // Create validate object for IPAM API - requestAddrObject := apicontracts.IpamApiRequest{ + requestAddrObject := apicontracts.IpamAPIRequest{ Secret: string(oldSecret.Data["secret"]), NewSecret: string(newSecret.Data["secret"]), Zone: annotations["ipam.vitistack.io/zone"], - IpFamily: ipFamily, + IPFamily: ipFamily, Address: ipAddress, Service: apicontracts.Service{ ServiceName: service.GetName(), - NamespaceId: namespaceId, - ClusterId: clusterId, + NamespaceID: namespaceId, + ClusterID: clusterId, RetentionPeriodDays: retentionPeriodDaysToInt, DenyExternalCleanup: denyExternalCleanupToBool, },