diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d8e6d4..2e7f480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v0.15.1] - 2024-09-06 +### Added +- [#58] Use new config interface (configmaps instead of the etcd is now used) to request global configuration. +- [#56] Use new registry interface (configmaps instead of the etcd is now used) to request and watch dogu jsons. +- [#53] New configuration (`/config/_global/block_warpmenu_support_category`) for completely blocking the support entries in the warp menu +- [#53] New configuration (`/config/_global/allowed_warpmenu_support_entries`) for explicitly allowing support entries in the warp menu + +### Fixed +- [#53] Create warp menu directly at startup to prevent an empty warp menu + ## [v0.15.0] - 2023-12-08 ### Added - [#49] Patch-template for mirroring this component and its images into airgapped environments. diff --git a/Dockerfile b/Dockerfile index eeb2925..bd8078a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21 AS builder +FROM golang:1.22 AS builder WORKDIR /workspace @@ -31,7 +31,7 @@ RUN make compile-generic FROM gcr.io/distroless/static:nonroot LABEL maintainer="hello@cloudogu.com" \ NAME="k8s-service-discovery" \ - VERSION="0.15.0" + VERSION="0.15.1" WORKDIR / diff --git a/Jenkinsfile b/Jenkinsfile index 9f850f7..26db0dc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -12,7 +12,7 @@ github = new GitHub(this, git) changelog = new Changelog(this) Docker docker = new Docker(this) gpg = new Gpg(this, docker) -goVersion = "1.21" +goVersion = "1.22" makefile = new Makefile(this) // Configuration of repository @@ -98,6 +98,10 @@ node('docker') { } } + stage('create global configmap') { + k3d.kubectl("--namespace default create configmap global-config --from-literal=config.yaml='key: value'") + } + stage('Deploy Manager') { k3d.helm("install ${repositoryName} ${helmChartDir}") } diff --git a/Makefile b/Makefile index 5271094..a0e45a2 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,10 @@ # Set these to the desired values ARTIFACT_ID=k8s-service-discovery -VERSION=0.15.0 +VERSION=0.15.1 IMAGE=cloudogu/${ARTIFACT_ID}:${VERSION} -GOTAG?=1.21 -MAKEFILES_VERSION=9.0.1 -LINT_VERSION?=v1.52.1 +GOTAG?=1.22 +MAKEFILES_VERSION=9.1.0 ADDITIONAL_CLEAN=dist-clean @@ -26,14 +25,11 @@ include build/make/clean.mk include build/make/digital-signature.mk include build/make/mocks.mk -K8S_RUN_PRE_TARGETS=setup-etcd-port-forward - K8S_COMPONENT_SOURCE_VALUES = ${HELM_SOURCE_DIR}/values.yaml K8S_COMPONENT_TARGET_VALUES = ${HELM_TARGET_DIR}/values.yaml PRE_COMPILE=generate-deepcopy -HELM_PRE_APPLY_TARGETS=template-stage template-log-level template-image-pull-policy HELM_PRE_GENERATE_TARGETS = helm-values-update-image-version -HELM_POST_GENERATE_TARGETS = helm-values-replace-image-repo +HELM_POST_GENERATE_TARGETS = helm-values-replace-image-repo template-stage template-log-level template-image-pull-policy CHECK_VAR_TARGETS=check-all-vars IMAGE_IMPORT_TARGET=image-import @@ -72,8 +68,3 @@ template-image-pull-policy: $(BINARY_YQ) $(BINARY_YQ) -i e ".manager.imagePullPolicy=\"Always\"" "${K8S_COMPONENT_TARGET_VALUES}" ; \ fi -## Local Development - -.PHONY: setup-etcd-port-forward -setup-etcd-port-forward: - kubectl port-forward etcd-0 4001:2379 & diff --git a/build/make/build.mk b/build/make/build.mk index b102149..857c11d 100644 --- a/build/make/build.mk +++ b/build/make/build.mk @@ -3,7 +3,7 @@ ADDITIONAL_LDFLAGS?=-extldflags -static LDFLAGS?=-ldflags "$(ADDITIONAL_LDFLAGS) -X main.Version=$(VERSION) -X main.CommitID=$(COMMIT_ID)" GOIMAGE?=golang -GOTAG?=1.14.13 +GOTAG?=1.22 GOOS?=linux GOARCH?=amd64 PRE_COMPILE?= diff --git a/build/make/k8s-component.mk b/build/make/k8s-component.mk index 9d29183..6c1f6c4 100644 --- a/build/make/k8s-component.mk +++ b/build/make/k8s-component.mk @@ -2,7 +2,9 @@ COMPONENT_DEV_VERSION?=${VERSION}-dev include ${BUILD_DIR}/make/k8s.mk -BINARY_HELM_ADDITIONAL_PUSH_ARGS?=--plain-http +ifeq (${RUNTIME_ENV}, local) + BINARY_HELM_ADDITIONAL_PUSH_ARGS?=--plain-http +endif BINARY_HELM_ADDITIONAL_PACK_ARGS?= BINARY_HELM_ADDITIONAL_UNINST_ARGS?= BINARY_HELM_ADDITIONAL_UPGR_ARGS?= @@ -12,6 +14,9 @@ HELM_SOURCE_DIR ?= k8s/helm HELM_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${VERSION}.tgz HELM_DEV_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${COMPONENT_DEV_VERSION}.tgz HELM_ARTIFACT_NAMESPACE?=k8s +ifeq (${RUNTIME_ENV}, remote) + HELM_ARTIFACT_NAMESPACE?=testing/k8s +endif K8S_RESOURCE_COMPONENT ?= "${K8S_RESOURCE_TEMP_FOLDER}/component-${ARTIFACT_ID}-${VERSION}.yaml" K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML ?= $(BUILD_DIR)/make/k8s-component.tpl @@ -75,12 +80,12 @@ helm-update-dependencies: ${BINARY_HELM} ## Update Helm chart dependencies .PHONY: helm-apply helm-apply: ${BINARY_HELM} check-k8s-namespace-env-var ${IMAGE_IMPORT_TARGET} helm-generate ${HELM_PRE_APPLY_TARGETS} ## Generates and installs the Helm chart. @echo "Apply generated helm chart" - @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${HELM_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} + @${BINARY_HELM} --kube-context="${KUBE_CONTEXT_NAME}" upgrade -i ${ARTIFACT_ID} ${HELM_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} .PHONY: helm-delete helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the current Helm chart. @echo "Uninstall helm chart" - @${BINARY_HELM} uninstall ${ARTIFACT_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true + @${BINARY_HELM} --kube-context="${KUBE_CONTEXT_NAME}" uninstall ${ARTIFACT_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true .PHONY: helm-reinstall helm-reinstall: helm-delete helm-apply ## Uninstalls the current helm chart and reinstalls it. @@ -88,11 +93,11 @@ helm-reinstall: helm-delete helm-apply ## Uninstalls the current helm chart and .PHONY: helm-chart-import helm-chart-import: ${CHECK_VAR_TARGETS} helm-generate helm-package ${IMAGE_IMPORT_TARGET} ## Imports the currently available chart into the cluster-local registry. @if [[ ${STAGE} == "development" ]]; then \ - echo "Import ${HELM_DEV_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${HELM_DEV_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + ${BINARY_HELM} push ${HELM_DEV_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ else \ - echo "Import ${HELM_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${HELM_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + ${BINARY_HELM} push ${HELM_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ fi @echo "Done." @@ -115,7 +120,7 @@ ${HELM_RELEASE_TGZ}: ${BINARY_HELM} ${HELM_TARGET_DIR}/Chart.yaml ${HELM_POST_GE .PHONY: helm-delete-existing-tgz helm-delete-existing-tgz: ## Remove an existing Helm package from the target directory. @echo "Delete ${HELM_RELEASE_TGZ}*" - @rm -f ${HELM_RELEASE_TGZ}* + @rm -f ${HELM_TARGET_DIR}/${ARTIFACT_ID}-*.tgz ##@ K8s - Helm lint targets @@ -138,12 +143,12 @@ ${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}: ${K8S_RESOURCE_TEMP_FOLDER} .PHONY: component-apply component-apply: check-k8s-namespace-env-var ${COMPONENT_PRE_APPLY_TARGETS} ${IMAGE_IMPORT_TARGET} helm-generate helm-chart-import component-generate ## Applies the component yaml resource to the actual defined context. - @kubectl apply -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" + @kubectl apply -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" @echo "Done." .PHONY: component-delete component-delete: check-k8s-namespace-env-var component-generate $(K8S_POST_GENERATE_TARGETS) ## Deletes the component yaml resource from the actual defined context. - @kubectl delete -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" || true + @kubectl delete -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" || true @echo "Done." .PHONY: component-reinstall diff --git a/build/make/k8s-crd.mk b/build/make/k8s-crd.mk index 4cbcd88..090b029 100644 --- a/build/make/k8s-crd.mk +++ b/build/make/k8s-crd.mk @@ -62,19 +62,19 @@ validate-crd-chart: .PHONY: crd-helm-apply crd-helm-apply: ${BINARY_HELM} check-k8s-namespace-env-var crd-helm-generate ## Generates and installs the Helm CRD chart. @echo "Apply generated Helm CRD chart" - @${BINARY_HELM} upgrade -i ${ARTIFACT_CRD_ID} ${HELM_CRD_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} + @${BINARY_HELM} --kube-context="${KUBE_CONTEXT_NAME}" upgrade -i ${ARTIFACT_CRD_ID} ${HELM_CRD_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} .PHONY: crd-helm-delete crd-helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the current Helm CRD chart. @echo "Uninstall Helm CRD chart" - @${BINARY_HELM} uninstall ${ARTIFACT_CRD_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true + @${BINARY_HELM} --kube-context="${KUBE_CONTEXT_NAME}" uninstall ${ARTIFACT_CRD_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true .PHONY: crd-helm-package crd-helm-package: crd-helm-delete-existing-tgz ${HELM_CRD_RELEASE_TGZ} ## Generates and packages the Helm CRD chart. .PHONY: crd-helm-delete-existing-tgz crd-helm-delete-existing-tgz: ## Remove an existing Helm CRD package. - @rm -f ${HELM_CRD_RELEASE_TGZ}* + @rm -f ${HELM_CRD_TARGET_DIR}/${ARTIFACT_CRD_ID}-*.tgz ${HELM_CRD_RELEASE_TGZ}: ${BINARY_HELM} crd-helm-generate ## Generates and packages the Helm CRD chart. @echo "Package generated helm crd-chart" @@ -83,11 +83,11 @@ ${HELM_CRD_RELEASE_TGZ}: ${BINARY_HELM} crd-helm-generate ## Generates and packa .PHONY: crd-helm-chart-import crd-helm-chart-import: ${CHECK_VAR_TARGETS} check-k8s-artifact-id crd-helm-generate crd-helm-package ## Imports the currently available Helm CRD chart into the cluster-local registry. @if [[ ${STAGE} == "development" ]]; then \ - echo "Import ${HELM_CRD_DEV_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${HELM_CRD_DEV_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_CRD_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + ${BINARY_HELM} push ${HELM_CRD_DEV_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ else \ - echo "Import ${HELM_CRD_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${HELM_CRD_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_CRD_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + ${BINARY_HELM} push ${HELM_CRD_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ fi @echo "Done." @@ -106,10 +106,10 @@ crd-component-generate: ${K8S_RESOURCE_TEMP_FOLDER} ## Generate the CRD componen .PHONY: crd-component-apply crd-component-apply: check-k8s-namespace-env-var crd-helm-chart-import crd-component-generate ## Applies the CRD component YAML resource to the actual defined context. - @kubectl apply -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" + @kubectl apply -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" @echo "Done." .PHONY: crd-component-delete crd-component-delete: check-k8s-namespace-env-var crd-component-generate ## Deletes the CRD component YAML resource from the actual defined context. - @kubectl delete -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" || true + @kubectl delete -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" || true @echo "Done." diff --git a/build/make/k8s-dogu.mk b/build/make/k8s-dogu.mk index 9c244a3..e656b17 100644 --- a/build/make/k8s-dogu.mk +++ b/build/make/k8s-dogu.mk @@ -3,15 +3,13 @@ DOGU_JSON_FILE=${WORKDIR}/dogu.json DOGU_JSON_DEV_FILE=${WORKDIR}/${TARGET_DIR}/dogu.json # Name of the dogu is extracted from the dogu.json -ARTIFACT_ID=$(shell $(BINARY_YQ) -e ".Name" $(DOGU_JSON_FILE) | sed "s|.*/||g") +ARTIFACT_ID=$(shell $(BINARY_YQ) -oy -e ".Name" $(DOGU_JSON_FILE) | sed "s|.*/||g") # Namespace of the dogu is extracted from the dogu.json -ARTIFACT_NAMESPACE=$(shell $(BINARY_YQ) -e ".Name" $(DOGU_JSON_FILE) | sed "s|/.*||g") +ARTIFACT_NAMESPACE=$(shell $(BINARY_YQ) -oy -e ".Name" $(DOGU_JSON_FILE) | sed "s|/.*||g") # Version of the dogu is extracted from the dogu.json -VERSION=$(shell $(BINARY_YQ) -e ".Version" $(DOGU_JSON_FILE)) +VERSION=$(shell $(BINARY_YQ) -oy -e ".Version" $(DOGU_JSON_FILE)) # Image of the dogu is extracted from the dogu.json -IMAGE=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE)):$(VERSION) -IMAGE_DEV_WITHOUT_TAG=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE) | sed "s|registry\.cloudogu\.com\(.\+\)|${K3CES_REGISTRY_URL_PREFIX}\1|g") -IMAGE_DEV=${IMAGE_DEV_WITHOUT_TAG}:${VERSION} +IMAGE=$(shell $(BINARY_YQ) -oy -e ".Image" $(DOGU_JSON_FILE)):$(VERSION) include $(BUILD_DIR)/make/k8s.mk @@ -37,13 +35,13 @@ create-dogu-resource: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) .PHONY: apply-dogu-resource apply-dogu-resource: - @kubectl apply -f "$(K8S_RESOURCE_DOGU)" + @kubectl --context="${KUBE_CONTEXT_NAME}" --namespace=${NAMESPACE} apply -f "$(K8S_RESOURCE_DOGU)" ##@ K8s - Dogu .PHONY: install-dogu-descriptor install-dogu-descriptor: ${BINARY_YQ} $(TARGET_DIR) ## Installs a configmap with current dogu.json into the cluster. @echo "Generate configmap from dogu.json..." - @$(BINARY_YQ) ".Image=\"${IMAGE_DEV_WITHOUT_TAG}\"" ${DOGU_JSON_FILE} > ${DOGU_JSON_DEV_FILE} - @kubectl create configmap "$(ARTIFACT_ID)-descriptor" --from-file=$(DOGU_JSON_DEV_FILE) --dry-run=client -o yaml | kubectl apply -f - --namespace=${NAMESPACE} + @$(BINARY_YQ) -oj ".Image=\"${IMAGE_DEV}\" | .Version=\"${VERSION}\"" ${DOGU_JSON_FILE} > ${DOGU_JSON_DEV_FILE} + @kubectl --context="${KUBE_CONTEXT_NAME}" create configmap "$(ARTIFACT_ID)-descriptor" --from-file=$(DOGU_JSON_DEV_FILE) --dry-run=client -o yaml | kubectl --context="${KUBE_CONTEXT_NAME}" --namespace=${NAMESPACE} apply -f - @echo "Done." diff --git a/build/make/k8s.mk b/build/make/k8s.mk index 0f9fe02..9f798f4 100644 --- a/build/make/k8s.mk +++ b/build/make/k8s.mk @@ -11,7 +11,7 @@ BINARY_YQ_4_VERSION?=v4.40.3 BINARY_HELM = $(UTILITY_BIN_PATH)/helm BINARY_HELM_VERSION?=v3.13.0 CONTROLLER_GEN = $(UTILITY_BIN_PATH)/controller-gen -CONTROLLER_GEN_VERSION?=v0.13.0 +CONTROLLER_GEN_VERSION?=v0.14.0 # Setting SHELL to bash allows bash commands to be executed by recipes. # Options are set to exit when a recipe line exits non-zero or a piped command fails. @@ -22,14 +22,48 @@ SHELL = /usr/bin/env bash -o pipefail IMAGE ?= # Set production as default stage. Use "development" as stage in your .env file to generate artifacts -# with development images pointing to K3S_CLUSTER_FQDN. +# with development images pointing to CES_REGISTRY_URL_PREFIX. STAGE?=production + +# Set the "local" as runtime-environment, to push images to the container-registry of the local cluster and to apply resources to the local cluster. +# Use "remote" as runtime-environment in your .env file to push images to the container-registry at "registry.cloudogu.com/testing" and to apply resources to the configured kubernetes-context in KUBE_CONTEXT_NAME. +RUNTIME_ENV?=local +$(info RUNTIME_ENV=$(RUNTIME_ENV)) + +# The host and port of the local cluster K3S_CLUSTER_FQDN?=k3ces.local K3S_LOCAL_REGISTRY_PORT?=30099 -K3CES_REGISTRY_URL_PREFIX="${K3S_CLUSTER_FQDN}:${K3S_LOCAL_REGISTRY_PORT}" + +# The URL of the container-registry to use. Defaults to the registry of the local-cluster. +# If RUNTIME_ENV is "remote" it is "registry.cloudogu.com/testing" +CES_REGISTRY_HOST?="${K3S_CLUSTER_FQDN}:${K3S_LOCAL_REGISTRY_PORT}" +CES_REGISTRY_NAMESPACE ?= +ifeq (${RUNTIME_ENV}, remote) + CES_REGISTRY_HOST="registry.cloudogu.com" + CES_REGISTRY_NAMESPACE="/testing" +endif +$(info CES_REGISTRY_HOST=$(CES_REGISTRY_HOST)) + +# The name of the kube-context to use for applying resources. +# If KUBE_CONTEXT_NAME is empty and RUNTIME_ENV is "remote" the currently configured kube-context is used. +# If KUBE_CONTEXT_NAME is empty and RUNTIME_ENV is not "remote" the "k3ces.local" is used as kube-context. +ifeq (${KUBE_CONTEXT_NAME}, ) + ifeq (${RUNTIME_ENV}, remote) + KUBE_CONTEXT_NAME = $(shell kubectl config current-context) + else + KUBE_CONTEXT_NAME = k3ces.local + endif +endif +$(info KUBE_CONTEXT_NAME=$(KUBE_CONTEXT_NAME)) + +# The git branch-name in lowercase, shortened to 63 bytes, and with everything except 0-9 and a-z replaced with -. No leading / trailing -. +GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$$//g' | cut -c1-63) +# The short git commit-hash +GIT_HASH := $(shell git rev-parse --short HEAD) + ## Image URL to use all building/pushing image targets -IMAGE_DEV?=${K3CES_REGISTRY_URL_PREFIX}/${ARTIFACT_ID} -IMAGE_DEV_VERSION=${IMAGE_DEV}:${VERSION} +IMAGE_DEV?=$(CES_REGISTRY_HOST)$(CES_REGISTRY_NAMESPACE)/$(ARTIFACT_ID)/$(GIT_BRANCH) +IMAGE_DEV_VERSION=$(IMAGE_DEV):$(VERSION) # Variables for the temporary yaml files. These are used as template to generate a development resource containing # the current namespace and the dev image. @@ -64,13 +98,36 @@ check-k8s-artifact-id: .PHONY: check-etc-hosts check-etc-hosts: - @grep -E "^.+\s+${K3S_CLUSTER_FQDN}\$$" /etc/hosts > /dev/null || \ - (echo "Missing /etc/hosts entry for ${K3S_CLUSTER_FQDN}" && exit 1) + @if [[ ${RUNTIME_ENV} == "local" ]]; then \ + grep -E "^.+\s+${K3S_CLUSTER_FQDN}\$$" /etc/hosts > /dev/null || \ + (echo "Missing /etc/hosts entry for ${K3S_CLUSTER_FQDN}" && exit 1) \ + fi .PHONY: check-insecure-cluster-registry check-insecure-cluster-registry: - @grep "${K3CES_REGISTRY_URL_PREFIX}" /etc/docker/daemon.json > /dev/null || \ - (echo "Missing /etc/docker/daemon.json for ${K3CES_REGISTRY_URL_PREFIX}" && exit 1) + @if [[ ${RUNTIME_ENV} == "local" ]]; then \ + grep "${CES_REGISTRY_HOST}" /etc/docker/daemon.json > /dev/null || \ + (echo "Missing /etc/docker/daemon.json for ${CES_REGISTRY_HOST}" && exit 1) \ + fi + +# If the RUNTIME_ENV is "remote" checks if the current docker-client has credentials for CES_REGISTRY_HOST +# If no credentials could be found, the credentials are queried and docker-login is performed +check-docker-credentials: + @if [[ "$(RUNTIME_ENV)" == "remote" ]]; then \ + if ! grep -q $(CES_REGISTRY_HOST) ~/.docker/config.json ; then \ + echo "Error: Docker is not logged in to $(CES_REGISTRY_HOST)"; \ + read -p "Enter Docker Username for $(CES_REGISTRY_HOST): " username; \ + read -sp "Enter Docker Password for $(CES_REGISTRY_HOST): " password; \ + echo ""; \ + echo "$$password" | docker login -u "$$username" --password-stdin $(CES_REGISTRY_HOST); \ + if [ $$? -eq 0 ]; then \ + echo "Docker login to $(CES_REGISTRY_HOST) successful"; \ + else \ + echo "Docker login to $(CES_REGISTRY_HOST) failed"; \ + exit 1; \ + fi \ + fi \ + fi ##@ K8s - Resources @@ -81,7 +138,7 @@ ${K8S_RESOURCE_TEMP_FOLDER}: ##@ K8s - Docker .PHONY: docker-build -docker-build: check-k8s-image-env-var ## Builds the docker image of the K8s app. +docker-build: check-docker-credentials check-k8s-image-env-var ## Builds the docker image of the K8s app. @echo "Building docker image $(IMAGE)..." @DOCKER_BUILDKIT=1 docker build . -t $(IMAGE) @@ -93,13 +150,13 @@ docker-dev-tag: check-k8s-image-dev-var docker-build ## Tags a Docker image for .PHONY: check-k8s-image-dev-var check-k8s-image-dev-var: ifeq (${IMAGE_DEV},) - @echo "Missing make variable IMAGE_DEV detected. It should look like \$${K3CES_REGISTRY_URL_PREFIX}/docker-image:tag" + @echo "Missing make variable IMAGE_DEV detected. It should look like \$${CES_REGISTRY_HOST}/docker-image:tag" @exit 19 endif .PHONY: image-import -image-import: check-all-vars check-k8s-artifact-id docker-dev-tag ## Imports the currently available image into the cluster-local registry. - @echo "Import $(IMAGE_DEV_VERSION) into K8s cluster ${K3S_CLUSTER_FQDN}..." +image-import: check-all-vars check-k8s-artifact-id docker-dev-tag ## Imports the currently available image into the configured ces-registry. + @echo "Import $(IMAGE_DEV_VERSION) into K8s cluster ${KUBE_CONTEXT_NAME}..." @docker push $(IMAGE_DEV_VERSION) @echo "Done." @@ -145,4 +202,4 @@ ENVTEST = $(UTILITY_BIN_PATH)/setup-envtest envtest: ${ENVTEST} ## Download envtest-setup locally if necessary. ${ENVTEST}: - $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) \ No newline at end of file + $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) diff --git a/build/make/mocks.mk b/build/make/mocks.mk index e313369..4c9697f 100644 --- a/build/make/mocks.mk +++ b/build/make/mocks.mk @@ -1,7 +1,7 @@ ##@ Mocking MOCKERY_BIN=${UTILITY_BIN_PATH}/mockery -MOCKERY_VERSION=v2.20.0 +MOCKERY_VERSION?=v2.42.1 MOCKERY_YAML=${WORKDIR}/.mockery.yaml ${MOCKERY_BIN}: ${UTILITY_BIN_PATH} diff --git a/build/make/static-analysis.mk b/build/make/static-analysis.mk index 70e6468..0ed0de3 100644 --- a/build/make/static-analysis.mk +++ b/build/make/static-analysis.mk @@ -2,14 +2,14 @@ STATIC_ANALYSIS_DIR=$(TARGET_DIR)/static-analysis GOIMAGE?=golang -GOTAG?=1.18 +GOTAG?=1.22 CUSTOM_GO_MOUNT?=-v /tmp:/tmp REVIEW_DOG=$(TMP_DIR)/bin/reviewdog LINT=$(TMP_DIR)/bin/golangci-lint -LINT_VERSION?=v1.49.0 +LINT_VERSION?=v1.58.2 # ignore tests and mocks -LINTFLAGS=--tests=false --skip-files="^.*_mock.go$$" --skip-files="^.*/mock.*.go$$" --timeout 10m --issues-exit-code 0 +LINTFLAGS=--tests=false --exclude-files="^.*_mock.go$$" --exclude-files="^.*/mock.*.go$$" --timeout 10m --issues-exit-code 0 ADDITIONAL_LINTER=-E bodyclose -E containedctx -E contextcheck -E decorder -E dupl -E errname -E forcetypeassert -E funlen -E unparam .PHONY: static-analysis diff --git a/controllers/cesregistry/registry.go b/controllers/cesregistry/registry.go deleted file mode 100644 index 35913ec..0000000 --- a/controllers/cesregistry/registry.go +++ /dev/null @@ -1,18 +0,0 @@ -package cesregistry - -import ( - "fmt" - - "github.com/cloudogu/cesapp-lib/core" - "github.com/cloudogu/cesapp-lib/registry" -) - -// Create creates a new local CES registry. -func Create(namespace string) (registry.Registry, error) { - r, err := registry.New(core.Registry{ - Type: "etcd", - Endpoints: []string{fmt.Sprintf("http://etcd.%s.svc.cluster.local:4001", namespace)}, - }) - - return r, err -} diff --git a/controllers/cesregistry/registry_test.go b/controllers/cesregistry/registry_test.go deleted file mode 100644 index b67b403..0000000 --- a/controllers/cesregistry/registry_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package cesregistry - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestCreate(t *testing.T) { - t.Run("successfully create a CES-registry", func(t *testing.T) { - result, err := Create("my-namespace") - - assert.NoError(t, err) - assert.NotNil(t, result) - }) -} diff --git a/controllers/config/config.go b/controllers/config/config.go index 400488e..1a5f437 100644 --- a/controllers/config/config.go +++ b/controllers/config/config.go @@ -29,7 +29,7 @@ type Configuration struct { Support []SupportSource } -// Source in etcd +// Source in global config type Source struct { Path string Type string diff --git a/controllers/config/testdata/config.yaml b/controllers/config/testdata/config.yaml index 20bd3ea..b7c1c5a 100644 --- a/controllers/config/testdata/config.yaml +++ b/controllers/config/testdata/config.yaml @@ -2,10 +2,8 @@ sources: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -16,6 +14,6 @@ support: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com diff --git a/controllers/config/testdata/invalid_config.yaml b/controllers/config/testdata/invalid_config.yaml index 49a2f36..cdda1de 100644 --- a/controllers/config/testdata/invalid_config.yaml +++ b/controllers/config/testdata/invalid_config.yaml @@ -2,10 +2,8 @@ sources: - pathdsf: /dogu type: dogus tag: warp - - patsdfh: /config/nginx/externals + - patsdfh: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - typsdfe: disabled_support_entries tardddddget: /var/www/html/warp/menu.json order: Development Apps: 100 diff --git a/controllers/config/testdata/invalid_k8s_config.yaml b/controllers/config/testdata/invalid_k8s_config.yaml index ba0c9a2..0f2cad9 100644 --- a/controllers/config/testdata/invalid_k8s_config.yaml +++ b/controllers/config/testdata/invalid_k8s_config.yaml @@ -14,10 +14,8 @@ data: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 diff --git a/controllers/config/testdata/k8s_config.yaml b/controllers/config/testdata/k8s_config.yaml index 044d957..710901b 100644 --- a/controllers/config/testdata/k8s_config.yaml +++ b/controllers/config/testdata/k8s_config.yaml @@ -14,10 +14,8 @@ data: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -28,6 +26,6 @@ data: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com diff --git a/controllers/deploymentController.go b/controllers/deploymentController.go index aedb63c..9a6c1e7 100644 --- a/controllers/deploymentController.go +++ b/controllers/deploymentController.go @@ -4,13 +4,11 @@ import ( "context" "fmt" + k8sv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - k8sv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" ) const legacyDoguLabel = "dogu" @@ -36,7 +34,7 @@ func NewDeploymentReconciler(client client.Client, updater IngressUpdater) *depl // The deploymentReconciler is responsible to regenerate ingress objects for respective dogus containing the ces service // discovery annotation when their state switches between ready <-> not ready. func (r *deploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) + logger := ctrl.LoggerFrom(ctx) deployment, err := r.getDeployment(ctx, req) if err != nil { diff --git a/controllers/ingressClassCreator.go b/controllers/ingressClassCreator.go index 462e0a4..5a9d4a4 100644 --- a/controllers/ingressClassCreator.go +++ b/controllers/ingressClassCreator.go @@ -7,10 +7,10 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/log" "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" networking "k8s.io/api/networking/v1" @@ -48,7 +48,7 @@ func NewIngressClassCreator(client client.Client, className string, namespace st // CreateIngressClass check whether the ingress class for the generator exists. If not it will be created. func (icc ingressClassCreator) CreateIngressClass(ctx context.Context) error { - log.FromContext(ctx).Info(fmt.Sprintf("checking for existing ingress class [%s]", icc.className)) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("checking for existing ingress class [%s]", icc.className)) ok, err := icc.isIngressClassAvailable(ctx) if err != nil { return fmt.Errorf("failed to check if ingress class [%s] exists: %w", icc.className, err) @@ -62,7 +62,7 @@ func (icc ingressClassCreator) CreateIngressClass(ctx context.Context) error { if ok { icc.eventRecorder.Eventf(deployment, corev1.EventTypeNormal, ingressClassCreationEventReason, "Ingress class [%s] already exists.", icc.className) - log.FromContext(ctx).Info(fmt.Sprintf("ingress class [%s] already exists -> skip creation", icc.className)) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("ingress class [%s] already exists -> skip creation", icc.className)) return nil } diff --git a/controllers/ingressUpdater.go b/controllers/ingressUpdater.go index 99595f6..a38fe0c 100644 --- a/controllers/ingressUpdater.go +++ b/controllers/ingressUpdater.go @@ -4,7 +4,10 @@ import ( "context" "encoding/json" "fmt" - + doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" + "github.com/cloudogu/k8s-dogu-operator/controllers/annotation" + "github.com/cloudogu/k8s-service-discovery/controllers/dogustart" + "github.com/cloudogu/k8s-service-discovery/controllers/util" corev1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -12,12 +15,6 @@ import ( "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/cloudogu/cesapp-lib/registry" - doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" - "github.com/cloudogu/k8s-dogu-operator/controllers/annotation" - "github.com/cloudogu/k8s-service-discovery/controllers/dogustart" ) const ( @@ -75,8 +72,8 @@ func (sr *serviceRewrite) generateConfig() string { type ingressUpdater struct { // client used to communicate with k8s. client client.Client - // globalConfig is used to read the global config from the etcd. - globalConfig configurationContext + // globalConfig is used to read the global configuration. + globalConfigRepo GlobalConfigRepository // Namespace defines the target namespace for the ingress objects. namespace string // IngressClassName defines the ingress class for the ces services. @@ -92,12 +89,8 @@ type DeploymentReadyChecker interface { IsReady(ctx context.Context, deploymentName string) (bool, error) } -type configurationContext interface { - registry.ConfigurationContext -} - // NewIngressUpdater creates a new instance responsible for updating ingress objects. -func NewIngressUpdater(client client.Client, globalConfig configurationContext, namespace string, ingressClassName string, recorder eventRecorder) (*ingressUpdater, error) { +func NewIngressUpdater(client client.Client, globalConfigRepo GlobalConfigRepository, namespace string, ingressClassName string, recorder eventRecorder) (*ingressUpdater, error) { restConfig, err := ctrl.GetConfig() if err != nil { return nil, fmt.Errorf("failed to find cluster config: %w", err) @@ -111,7 +104,7 @@ func NewIngressUpdater(client client.Client, globalConfig configurationContext, deploymentReadyChecker := dogustart.NewDeploymentReadyChecker(clientSet, namespace) return &ingressUpdater{ client: client, - globalConfig: globalConfig, + globalConfigRepo: globalConfigRepo, namespace: namespace, ingressClassName: ingressClassName, deploymentReadyChecker: deploymentReadyChecker, @@ -121,7 +114,7 @@ func NewIngressUpdater(client client.Client, globalConfig configurationContext, // UpsertIngressForService creates or updates the ingress object of the given service. func (i *ingressUpdater) UpsertIngressForService(ctx context.Context, service *corev1.Service) error { - isMaintenanceMode, err := isMaintenanceModeActive(i.globalConfig) + isMaintenanceMode, err := isMaintenanceModeActive(ctx, i.globalConfigRepo) if err != nil { return err } @@ -132,7 +125,7 @@ func (i *ingressUpdater) UpsertIngressForService(ctx context.Context, service *c } if !ok { - log.FromContext(ctx).Info(fmt.Sprintf("service [%s] has no ports or ces services -> skipping ingress creation", service.Name)) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("service [%s] has no ports or ces services -> skipping ingress creation", service.Name)) return nil } @@ -211,7 +204,7 @@ func getAdditionalIngressAnnotations(doguService *corev1.Service) (doguv1.Ingres } func (i *ingressUpdater) upsertMaintenanceModeIngressObject(ctx context.Context, cesService CesService, service *corev1.Service, dogu *doguv1.Dogu) error { - log.FromContext(ctx).Info(fmt.Sprintf("system is in maintenance mode -> create maintenance ingress object for service [%s]", service.GetName())) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("system is in maintenance mode -> create maintenance ingress object for service [%s]", service.GetName())) annotations := map[string]string{ingressRewriteTargetAnnotation: staticContentBackendRewrite} err := i.upsertIngressObject(ctx, service, cesService, staticContentBackendName, staticContentBackendPort, annotations) @@ -224,7 +217,7 @@ func (i *ingressUpdater) upsertMaintenanceModeIngressObject(ctx context.Context, } func (i *ingressUpdater) upsertDoguIsStartingIngressObject(ctx context.Context, cesService CesService, service *corev1.Service) error { - log.FromContext(ctx).Info(fmt.Sprintf("dogu is still starting -> create dogu is starting ingress object for service [%s]", service.GetName())) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("dogu is still starting -> create dogu is starting ingress object for service [%s]", service.GetName())) annotations := map[string]string{ingressRewriteTargetAnnotation: staticContentDoguIsStartingRewrite} err := i.upsertIngressObject(ctx, service, cesService, staticContentBackendName, staticContentBackendPort, annotations) @@ -236,7 +229,7 @@ func (i *ingressUpdater) upsertDoguIsStartingIngressObject(ctx context.Context, } func (i *ingressUpdater) upsertDoguIngressObject(ctx context.Context, cesService CesService, service *corev1.Service) error { - log.FromContext(ctx).Info(fmt.Sprintf("dogu is ready -> update ces service ingress object for service [%s]", service.GetName())) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("dogu is ready -> update ces service ingress object for service [%s]", service.GetName())) serviceRewrite, err := cesService.generateRewriteConfig() if err != nil { return err @@ -324,12 +317,15 @@ func (i *ingressUpdater) upsertIngressObject( return nil } -func isMaintenanceModeActive(g configurationContext) (bool, error) { - _, err := g.Get(maintenanceModeGlobalKey) - if registry.IsKeyNotFoundError(err) { +func isMaintenanceModeActive(ctx context.Context, globalConfigRepo GlobalConfigRepository) (bool, error) { + globalConfig, err := globalConfigRepo.Get(ctx) + if err != nil { + return false, fmt.Errorf("failed to get global config for maintenance mode: %w", err) + } + + get, ok := globalConfig.Get(maintenanceModeGlobalKey) + if !ok || !util.ContainsChars(get.String()) { return false, nil - } else if err != nil { - return false, fmt.Errorf("failed to read the maintenance mode from the registry: %w", err) } return true, nil diff --git a/controllers/ingressUpdater_test.go b/controllers/ingressUpdater_test.go index d22e92b..131a291 100644 --- a/controllers/ingressUpdater_test.go +++ b/controllers/ingressUpdater_test.go @@ -5,10 +5,10 @@ import ( "encoding/json" v1 "github.com/cloudogu/k8s-dogu-operator/api/v1" "github.com/cloudogu/k8s-dogu-operator/controllers/annotation" + registryconfig "github.com/cloudogu/k8s-registry-lib/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v2" corev1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,16 +21,24 @@ import ( "time" ) -func getGlobalConfigMockWithMaintenance(t *testing.T, maintenanceMode bool) configurationContext { - globalContextMock := newMockConfigurationContext(t) - expect := globalContextMock.EXPECT() +func getGlobalConfigRepoMockWithMaintenance(t *testing.T, maintenanceMode bool) GlobalConfigRepository { + var entries registryconfig.Entries + if maintenanceMode { - expect.Get(maintenanceModeGlobalKey).Return("active", nil) + entries = registryconfig.Entries{ + "maintenance": "maintenance", + } } else { - expect.Get(maintenanceModeGlobalKey).Return("", etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound}) + entries = registryconfig.Entries{} + } + + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(entries), } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) - return globalContextMock + return globalConfigRepoMock } func TestNewIngressUpdater(t *testing.T) { @@ -95,8 +103,9 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { service := corev1.Service{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, } + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, true), myNamespace, myIngressClass, newMockEventRecorder(t)) require.NoError(t, creationError) // when @@ -113,8 +122,9 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { {Name: "testPort", Port: 55}, }}, } + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) require.NoError(t, creationError) // when @@ -137,7 +147,7 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { }}, } clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) require.NoError(t, creationError) // when @@ -173,7 +183,7 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { }}, } clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects().Build() - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) require.NoError(t, creationError) // when @@ -210,7 +220,7 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { } dogu := &v1.Dogu{ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: myNamespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(dogu).Build() - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, false), myNamespace, myIngressClass, newMockEventRecorder(t)) require.NoError(t, creationError) deploymentReadyChecker := NewMockDeploymentReadyChecker(t) @@ -253,7 +263,7 @@ func Test_ingressUpdater_UpdateIngressOfService(t *testing.T) { clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(dogu).Build() recorderMock := newMockEventRecorder(t) recorderMock.EXPECT().Eventf(mock.IsType(&v1.Dogu{}), "Normal", "IngressCreation", "Created regular ingress for service [%s].", "test") - creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigMockWithMaintenance(t, false), myNamespace, myIngressClass, recorderMock) + creator, creationError := NewIngressUpdater(clientMock, getGlobalConfigRepoMockWithMaintenance(t, false), myNamespace, myIngressClass, recorderMock) require.NoError(t, creationError) deploymentReadyChecker := NewMockDeploymentReadyChecker(t) diff --git a/controllers/interfaces.go b/controllers/interfaces.go new file mode 100644 index 0000000..ecb0fa3 --- /dev/null +++ b/controllers/interfaces.go @@ -0,0 +1,13 @@ +package controllers + +import ( + "context" + libconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" +) + +type GlobalConfigRepository interface { + Get(context.Context) (libconfig.GlobalConfig, error) + Watch(context.Context, ...libconfig.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) + Update(ctx context.Context, globalConfig libconfig.GlobalConfig) (libconfig.GlobalConfig, error) +} diff --git a/controllers/logging/mock_logSink_test.go b/controllers/logging/mock_logSink_test.go index bb8eab1..906832b 100644 --- a/controllers/logging/mock_logSink_test.go +++ b/controllers/logging/mock_logSink_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package logging @@ -24,6 +24,10 @@ func (_m *mockLogSink) EXPECT() *mockLogSink_Expecter { func (_m *mockLogSink) Enabled(level int) bool { ret := _m.Called(level) + if len(ret) == 0 { + panic("no return value specified for Enabled") + } + var r0 bool if rf, ok := ret.Get(0).(func(int) bool); ok { r0 = rf(level) @@ -189,6 +193,10 @@ func (_c *mockLogSink_Init_Call) RunAndReturn(run func(logr.RuntimeInfo)) *mockL func (_m *mockLogSink) WithName(name string) logr.LogSink { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for WithName") + } + var r0 logr.LogSink if rf, ok := ret.Get(0).(func(string) logr.LogSink); ok { r0 = rf(name) @@ -235,6 +243,10 @@ func (_m *mockLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { _ca = append(_ca, keysAndValues...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for WithValues") + } + var r0 logr.LogSink if rf, ok := ret.Get(0).(func(...interface{}) logr.LogSink); ok { r0 = rf(keysAndValues...) @@ -282,13 +294,12 @@ func (_c *mockLogSink_WithValues_Call) RunAndReturn(run func(...interface{}) log return _c } -type mockConstructorTestingTnewMockLogSink interface { +// newMockLogSink creates a new instance of mockLogSink. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockLogSink(t interface { mock.TestingT Cleanup(func()) -} - -// newMockLogSink creates a new instance of mockLogSink. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockLogSink(t mockConstructorTestingTnewMockLogSink) *mockLogSink { +}) *mockLogSink { mock := &mockLogSink{} mock.Mock.Test(t) diff --git a/controllers/maintenanceModeUpdater.go b/controllers/maintenanceModeUpdater.go index fb91524..f42c718 100644 --- a/controllers/maintenanceModeUpdater.go +++ b/controllers/maintenanceModeUpdater.go @@ -3,10 +3,12 @@ package controllers import ( "context" "fmt" + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" "strings" + k8sv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" "github.com/hashicorp/go-multierror" - etcdclient "go.etcd.io/etcd/client/v2" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" @@ -14,16 +16,9 @@ import ( "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/cloudogu/cesapp-lib/registry" - k8sv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" - - "github.com/cloudogu/k8s-service-discovery/controllers/cesregistry" ) const ( - maintenanceModeWatchKey = "/config/_global/maintenance" maintenanceModeGlobalKey = "maintenance" ) @@ -43,113 +38,120 @@ type k8sClient interface { client.Client } -type maintenanceWatchConfigurationContext interface { - registry.WatchConfigurationContext -} - // maintenanceModeUpdater is responsible to update all ingress objects according to the desired maintenance mode. type maintenanceModeUpdater struct { - client k8sClient - namespace string - registry cesRegistry - ingressUpdater IngressUpdater - eventRecorder eventRecorder - serviceRewriter serviceRewriter + client k8sClient + namespace string + ingressUpdater IngressUpdater + eventRecorder eventRecorder + serviceRewriter serviceRewriter + globalConfigRepo GlobalConfigRepository } // NewMaintenanceModeUpdater creates a new maintenance mode updater. -func NewMaintenanceModeUpdater(client k8sClient, namespace string, ingressUpdater IngressUpdater, recorder eventRecorder) (*maintenanceModeUpdater, error) { - reg, err := cesregistry.Create(namespace) - if err != nil { - return nil, err - } - +func NewMaintenanceModeUpdater(client k8sClient, namespace string, ingressUpdater IngressUpdater, recorder eventRecorder, globalConfigRepo GlobalConfigRepository) (*maintenanceModeUpdater, error) { rewriter := &defaultServiceRewriter{client: client, eventRecorder: recorder, namespace: namespace} return &maintenanceModeUpdater{ - client: client, - namespace: namespace, - registry: reg, - ingressUpdater: ingressUpdater, - eventRecorder: recorder, - serviceRewriter: rewriter, + client: client, + namespace: namespace, + ingressUpdater: ingressUpdater, + eventRecorder: recorder, + serviceRewriter: rewriter, + globalConfigRepo: globalConfigRepo, }, nil } // Start starts the update process. This update process runs indefinitely and is designed to be started as goroutine. -func (scu maintenanceModeUpdater) Start(ctx context.Context) error { - log.FromContext(ctx).Info("Starting maintenance mode watcher...") - return scu.startEtcdWatch(ctx, scu.registry.RootConfig()) +func (mmu *maintenanceModeUpdater) Start(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Starting maintenance mode watcher...") + return mmu.startGlobalConfigWatch(ctx) } -func (scu *maintenanceModeUpdater) startEtcdWatch(ctx context.Context, reg maintenanceWatchConfigurationContext) error { - log.FromContext(ctx).Info("Start etcd watcher on maintenance key") +func (mmu *maintenanceModeUpdater) startGlobalConfigWatch(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Start global config watcher on maintenance key") + + maintenanceWatchChannel, err := mmu.globalConfigRepo.Watch(ctx, config.KeyFilter(maintenanceModeGlobalKey)) + if err != nil { + return fmt.Errorf("failed to start maintenance watch: %w", err) + } - warpChannel := make(chan *etcdclient.Response) go func() { - log.FromContext(ctx).Info("Start etcd watcher for maintenance key") - reg.Watch(ctx, maintenanceModeWatchKey, true, warpChannel) - log.FromContext(ctx).Info("Stop etcd watcher for maintenance key") + mmu.startMaintenanceWatch(ctx, maintenanceWatchChannel) }() + return nil +} + +func (mmu *maintenanceModeUpdater) startMaintenanceWatch(ctx context.Context, maintenanceWatchChannel <-chan repository.GlobalConfigWatchResult) { for { select { case <-ctx.Done(): - return nil - case <-warpChannel: - err := scu.handleMaintenanceModeUpdate(ctx) + ctrl.LoggerFrom(ctx).Info("context done - stop global config watcher for maintenance") + return + case result, open := <-maintenanceWatchChannel: + if !open { + ctrl.LoggerFrom(ctx).Info("maintenance watch channel canceled - stop watch") + return + } + if result.Err != nil { + ctrl.LoggerFrom(ctx).Error(result.Err, "maintenance watch channel error") + continue + } + + err := mmu.handleMaintenanceModeUpdate(ctx) if err != nil { - return err + ctrl.LoggerFrom(ctx).Error(err, "failed to handle maintenance update") } } } } -func (scu *maintenanceModeUpdater) handleMaintenanceModeUpdate(ctx context.Context) error { - log.FromContext(ctx).Info("Maintenance mode key changed in registry. Refresh ingress objects accordingly...") +func (mmu *maintenanceModeUpdater) handleMaintenanceModeUpdate(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Maintenance mode key changed in registry. Refresh ingress objects accordingly...") - isActive, err := isMaintenanceModeActive(scu.registry.GlobalConfig()) + isActive, err := isMaintenanceModeActive(ctx, mmu.globalConfigRepo) if err != nil { return err } if isActive { - err := scu.activateMaintenanceMode(ctx) + err := mmu.activateMaintenanceMode(ctx) if err != nil { return err } } else { - err := scu.deactivateMaintenanceMode(ctx) + err := mmu.deactivateMaintenanceMode(ctx) if err != nil { return err } } - err = scu.restartStaticNginxPod(ctx) + err = mmu.restartStaticNginxPod(ctx) if err != nil { return err } deployment := &appsv1.Deployment{} - err = scu.client.Get(ctx, types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: scu.namespace}, deployment) + err = mmu.client.Get(ctx, types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: mmu.namespace}, deployment) if err != nil { return fmt.Errorf("maintenance mode: failed to get deployment [%s]: %w", "k8s-service-discovery-controller-manager", err) } - scu.eventRecorder.Eventf(deployment, v1.EventTypeNormal, maintenanceChangeEventReason, "Maintenance mode changed to %t.", isActive) + mmu.eventRecorder.Eventf(deployment, v1.EventTypeNormal, maintenanceChangeEventReason, "Maintenance mode changed to %t.", isActive) return nil } -func (scu *maintenanceModeUpdater) restartStaticNginxPod(ctx context.Context) error { +func (mmu *maintenanceModeUpdater) restartStaticNginxPod(ctx context.Context) error { podList := &v1.PodList{} staticNginxRequirement, _ := labels.NewRequirement(k8sv1.DoguLabelName, selection.Equals, []string{"nginx-static"}) - err := scu.client.List(ctx, podList, &client.ListOptions{Namespace: scu.namespace, LabelSelector: labels.NewSelector().Add(*staticNginxRequirement)}) + err := mmu.client.List(ctx, podList, &client.ListOptions{Namespace: mmu.namespace, LabelSelector: labels.NewSelector().Add(*staticNginxRequirement)}) if err != nil { return fmt.Errorf("failed to list [%s] pods: %w", "nginx-static", err) } for _, pod := range podList.Items { - err := scu.client.Delete(ctx, &pod) + err := mmu.client.Delete(ctx, &pod) if err != nil { return fmt.Errorf("failed to delete pod [%s]: %w", pod.Name, err) } @@ -158,11 +160,11 @@ func (scu *maintenanceModeUpdater) restartStaticNginxPod(ctx context.Context) er return nil } -func (scu *maintenanceModeUpdater) getAllServices(ctx context.Context) (v1ServiceList, error) { +func (mmu *maintenanceModeUpdater) getAllServices(ctx context.Context) (v1ServiceList, error) { serviceList := &v1.ServiceList{} - err := scu.client.List(ctx, serviceList, &client.ListOptions{Namespace: scu.namespace}) + err := mmu.client.List(ctx, serviceList, &client.ListOptions{Namespace: mmu.namespace}) if err != nil { - return nil, fmt.Errorf("failed to get list of all services in namespace [%s]: %w", scu.namespace, err) + return nil, fmt.Errorf("failed to get list of all services in namespace [%s]: %w", mmu.namespace, err) } var modifiableServiceList v1ServiceList @@ -174,23 +176,23 @@ func (scu *maintenanceModeUpdater) getAllServices(ctx context.Context) (v1Servic return modifiableServiceList, nil } -func (scu *maintenanceModeUpdater) deactivateMaintenanceMode(ctx context.Context) error { - log.FromContext(ctx).Info("Deactivate maintenance mode...") +func (mmu *maintenanceModeUpdater) deactivateMaintenanceMode(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Deactivate maintenance mode...") - serviceList, err := scu.getAllServices(ctx) + serviceList, err := mmu.getAllServices(ctx) if err != nil { return fmt.Errorf("failed to deactivate maintenance mode: %w", err) } for _, service := range serviceList { - log.FromContext(ctx).Info(fmt.Sprintf("Updating ingress object [%s]", service.Name)) - err := scu.ingressUpdater.UpsertIngressForService(ctx, service) + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("Updating ingress object [%s]", service.Name)) + err := mmu.ingressUpdater.UpsertIngressForService(ctx, service) if err != nil { return err } } - err = scu.serviceRewriter.rewrite(ctx, serviceList, false) + err = mmu.serviceRewriter.rewrite(ctx, serviceList, false) if err != nil { return fmt.Errorf("failed to rewrite services during maintenance mode deactivation: %w", err) } @@ -198,23 +200,23 @@ func (scu *maintenanceModeUpdater) deactivateMaintenanceMode(ctx context.Context return nil } -func (scu *maintenanceModeUpdater) activateMaintenanceMode(ctx context.Context) error { - log.FromContext(ctx).Info("Activating maintenance mode...") +func (mmu *maintenanceModeUpdater) activateMaintenanceMode(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Activating maintenance mode...") - serviceList, err := scu.getAllServices(ctx) + serviceList, err := mmu.getAllServices(ctx) if err != nil { return fmt.Errorf("failed to activate maintenance mode: %w", err) } for _, service := range serviceList { ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("Updating ingress object [%s]", service.Name)) - err := scu.ingressUpdater.UpsertIngressForService(ctx, service) + err := mmu.ingressUpdater.UpsertIngressForService(ctx, service) if err != nil { return err } } - err = scu.serviceRewriter.rewrite(ctx, serviceList, true) + err = mmu.serviceRewriter.rewrite(ctx, serviceList, true) if err != nil { return fmt.Errorf("failed to rewrite services during maintenance mode activation: %w", err) } diff --git a/controllers/maintenanceModeUpdater_test.go b/controllers/maintenanceModeUpdater_test.go index 6ae8aa9..607dc44 100644 --- a/controllers/maintenanceModeUpdater_test.go +++ b/controllers/maintenanceModeUpdater_test.go @@ -2,174 +2,73 @@ package controllers import ( "context" - "sigs.k8s.io/controller-runtime/pkg/client" - "testing" - "time" - + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v2" - v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" testclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/log" + "testing" + "time" ) var testCtx = context.Background() func TestNewMaintenanceModeUpdater(t *testing.T) { - t.Run("failed to create registry", func(t *testing.T) { - clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() - creator, err := NewMaintenanceModeUpdater(clientMock, "%!%*Ä'%'!%'", NewMockIngressUpdater(t), newMockEventRecorder(t)) - - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to create etcd client") - require.Nil(t, creator) - }) - t.Run("successfully create updater", func(t *testing.T) { clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() - creator, err := NewMaintenanceModeUpdater(clientMock, "test", NewMockIngressUpdater(t), newMockEventRecorder(t)) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + creator, err := NewMaintenanceModeUpdater(clientMock, "test", NewMockIngressUpdater(t), newMockEventRecorder(t), globalConfigRepoMock) require.NoError(t, err) require.NotNil(t, creator) }) } -func Test_maintenanceModeUpdater_Start(t *testing.T) { - t.Run("error on maintenance update", func(t *testing.T) { - // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfig(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/maintenance", true, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - - globalConfigMock := newMockConfigurationContext(t) - globalConfigMock.EXPECT().Get("maintenance").Return("", assert.AnError) - regMock.EXPECT().RootConfig().Return(watchContextMock) - regMock.EXPECT().GlobalConfig().Return(globalConfigMock) - - ingressUpdater := NewMockIngressUpdater(t) - - namespace := "myTestNamespace" - clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects().Build() - svcRewriter := newMockServiceRewriter(t) - - maintenanceUpdater := &maintenanceModeUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - ingressUpdater: ingressUpdater, - serviceRewriter: svcRewriter, - } - - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*100) - - // when - err := maintenanceUpdater.Start(ctx) - cancelFunc() - - // then - require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) - }) - - t.Run("fail to get deployment", func(t *testing.T) { - // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/maintenance", true, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - - globalConfigMock := newMockConfigurationContext(t) - globalConfigMock.EXPECT().Get("maintenance").Return("false", nil) - regMock.EXPECT().RootConfig().Return(watchContextMock) - regMock.EXPECT().GlobalConfig().Return(globalConfigMock) - - ingressUpdater := NewMockIngressUpdater(t) - - namespace := "myTestNamespace" - clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects().Build() - svcRewriter := newMockServiceRewriter(t) - svcRewriter.EXPECT().rewrite(mock.Anything, mock.Anything, true).Return(nil) - - maintenanceUpdater := &maintenanceModeUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - ingressUpdater: ingressUpdater, - serviceRewriter: svcRewriter, - } - - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*100) - - // when - err := maintenanceUpdater.Start(ctx) - cancelFunc() - - // then - require.Error(t, err) - assert.ErrorContains(t, err, "maintenance mode: failed to get deployment [k8s-service-discovery-controller-manager]") - }) - - t.Run("run and terminate without any problems", func(t *testing.T) { +func Test_maintenanceModeUpdater_handleMaintenanceModeUpdate(t *testing.T) { + t.Run("activate maintenance mode with error", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/maintenance", true, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - - globalConfigMock := newMockConfigurationContext(t) - globalConfigMock.EXPECT().Get("maintenance").Return("false", nil) - regMock.EXPECT().RootConfig().Return(watchContextMock) - regMock.EXPECT().GlobalConfig().Return(globalConfigMock) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "maintenance": "{\"title\": \"titel\", \"text\":\"text\"}", + }) + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) ingressUpdater := NewMockIngressUpdater(t) + ingressUpdater.EXPECT().UpsertIngressForService(mock.Anything, mock.Anything).Return(assert.AnError) namespace := "myTestNamespace" - deployment := &v1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} - clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() - - eventRecorderMock := newMockEventRecorder(t) - eventRecorderMock.EXPECT().Eventf(mock.IsType(deployment), "Normal", "Maintenance", "Maintenance mode changed to %t.", true) - svcRewriter := newMockServiceRewriter(t) - svcRewriter.EXPECT().rewrite(mock.Anything, mock.Anything, true).Return(nil) + testService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "testService", Namespace: namespace}} + serviceList := &corev1.ServiceList{Items: []corev1.Service{*testService}} + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithLists(serviceList).Build() maintenanceUpdater := &maintenanceModeUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - ingressUpdater: ingressUpdater, - eventRecorder: eventRecorderMock, - serviceRewriter: svcRewriter, + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + ingressUpdater: ingressUpdater, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*100) - // when - err := maintenanceUpdater.Start(ctx) - cancelFunc() + err := maintenanceUpdater.handleMaintenanceModeUpdate(context.Background()) // then - require.NoError(t, err) + require.ErrorIs(t, err, assert.AnError) }) -} -func Test_maintenanceModeUpdater_handleMaintenanceModeUpdate(t *testing.T) { - t.Run("activate maintenance mode with error", func(t *testing.T) { + t.Run("deactivate maintenance mode with error", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := newMockConfigurationContext(t) - globalConfigMock.EXPECT().Get("maintenance").Return("true", nil) - regMock.EXPECT().GlobalConfig().Return(globalConfigMock) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{}) + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) ingressUpdater := NewMockIngressUpdater(t) ingressUpdater.EXPECT().UpsertIngressForService(mock.Anything, mock.Anything).Return(assert.AnError) @@ -180,10 +79,10 @@ func Test_maintenanceModeUpdater_handleMaintenanceModeUpdate(t *testing.T) { clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithLists(serviceList).Build() maintenanceUpdater := &maintenanceModeUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - ingressUpdater: ingressUpdater, + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + ingressUpdater: ingressUpdater, } // when @@ -193,28 +92,14 @@ func Test_maintenanceModeUpdater_handleMaintenanceModeUpdate(t *testing.T) { require.ErrorIs(t, err, assert.AnError) }) - t.Run("deactivate maintenance mode with error", func(t *testing.T) { + t.Run("should return error on get maintenance mode error", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := newMockConfigurationContext(t) - - keyNotFoundErr := etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound} - globalConfigMock.EXPECT().Get("maintenance").Return("", keyNotFoundErr) - regMock.EXPECT().GlobalConfig().Return(globalConfigMock) - - ingressUpdater := NewMockIngressUpdater(t) - ingressUpdater.EXPECT().UpsertIngressForService(mock.Anything, mock.Anything).Return(assert.AnError) - - namespace := "myTestNamespace" - testService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "testService", Namespace: namespace}} - serviceList := &corev1.ServiceList{Items: []corev1.Service{*testService}} - clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithLists(serviceList).Build() + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{}) + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, assert.AnError) maintenanceUpdater := &maintenanceModeUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - ingressUpdater: ingressUpdater, + globalConfigRepo: globalConfigRepoMock, } // when @@ -222,9 +107,9 @@ func Test_maintenanceModeUpdater_handleMaintenanceModeUpdate(t *testing.T) { // then require.ErrorIs(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to get global config for maintenance mode") }) } - func Test_isServiceNginxRelated(t *testing.T) { t.Run("should return true for nginx-prefixed dogu service", func(t *testing.T) { svc := &corev1.Service{Spec: corev1.ServiceSpec{ @@ -241,7 +126,6 @@ func Test_isServiceNginxRelated(t *testing.T) { assert.False(t, isServiceNginxRelated(svc)) }) } - func Test_rewriteNonSimpleServiceRoute(t *testing.T) { testNS := "test-namespace" @@ -407,7 +291,6 @@ func Test_rewriteNonSimpleServiceRoute(t *testing.T) { require.NoError(t, err) }) } - func Test_defaultServiceRewriter_rewrite(t *testing.T) { t.Run("should error during maintenance deactivation", func(t *testing.T) { // given @@ -468,7 +351,6 @@ func Test_defaultServiceRewriter_rewrite(t *testing.T) { assert.ErrorContains(t, err, "could not rewrite service nexus") }) } - func Test_maintenanceModeUpdater_getAllServices(t *testing.T) { t.Run("should return error from the API", func(t *testing.T) { // given @@ -515,7 +397,6 @@ func Test_maintenanceModeUpdater_getAllServices(t *testing.T) { assert.NotEqual(t, result[0].Name, result[1].Name) }) } - func Test_maintenanceModeUpdater_deactivateMaintenanceMode(t *testing.T) { t.Run("should error on listing services", func(t *testing.T) { // given @@ -567,7 +448,6 @@ func Test_maintenanceModeUpdater_deactivateMaintenanceMode(t *testing.T) { assert.ErrorContains(t, err, "failed to rewrite services during maintenance mode deactivation") }) } - func Test_maintenanceModeUpdater_activateMaintenanceMode(t *testing.T) { t.Run("should error on listing services", func(t *testing.T) { // given @@ -619,3 +499,215 @@ func Test_maintenanceModeUpdater_activateMaintenanceMode(t *testing.T) { assert.ErrorContains(t, err, "failed to rewrite services during maintenance mode activation") }) } + +func Test_maintenanceModeUpdater_Start(t *testing.T) { + t.Run("success with inactive maintenance mode", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + globalConfigMock := NewMockGlobalConfigRepository(t) + channel := make(chan repository.GlobalConfigWatchResult) + globalConfigMock.EXPECT().Watch(cancelCtx, mock.Anything).Return(channel, nil) + globalConfigMock.EXPECT().Get(cancelCtx).Return(config.GlobalConfig{}, nil) + + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().List(cancelCtx, mock.Anything, mock.Anything).Return(nil).Times(1) + k8sClientMock.EXPECT().List(cancelCtx, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, list client.ObjectList, option ...client.ListOption) error { + list.(*corev1.PodList).Items = []corev1.Pod{{ObjectMeta: metav1.ObjectMeta{Name: "nginx-static", Namespace: testNamespace}}} + return nil + }).Times(1) + k8sClientMock.EXPECT().Delete(cancelCtx, mock.Anything).Return(nil).Times(1) + k8sClientMock.EXPECT().Get(cancelCtx, types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + + eventRecorderMock := newMockEventRecorder(t) + eventRecorderMock.EXPECT().Eventf(mock.Anything, corev1.EventTypeNormal, "Maintenance", "Maintenance mode changed to %t.", false).Run(func(object runtime.Object, eventtype string, reason string, messageFmt string, args ...interface{}) { + cancelFunc() + }) + + serviceRewriterMock := newMockServiceRewriter(t) + serviceRewriterMock.EXPECT().rewrite(cancelCtx, mock.Anything, mock.Anything).Return(nil) + + sut := maintenanceModeUpdater{ + namespace: testNamespace, + globalConfigRepo: globalConfigMock, + client: k8sClientMock, + eventRecorder: eventRecorderMock, + serviceRewriter: serviceRewriterMock, + } + + // when + err := sut.Start(cancelCtx) + channel <- repository.GlobalConfigWatchResult{} + + // then + require.NoError(t, err) + <-cancelCtx.Done() + }) + + t.Run("success with active maintenance mode", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + globalConfigMock := NewMockGlobalConfigRepository(t) + channel := make(chan repository.GlobalConfigWatchResult) + globalConfigMock.EXPECT().Watch(cancelCtx, mock.Anything).Return(channel, nil) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "maintenance": "{\"title\": \"titel\", \"text\":\"text\"}", + }) + globalConfigMock.EXPECT().Get(cancelCtx).Return(globalConfig, nil) + + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().List(cancelCtx, mock.Anything, mock.Anything).Return(nil).Times(1) + k8sClientMock.EXPECT().List(cancelCtx, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, list client.ObjectList, option ...client.ListOption) error { + list.(*corev1.PodList).Items = []corev1.Pod{{ObjectMeta: metav1.ObjectMeta{Name: "nginx-static", Namespace: testNamespace}}} + return nil + }).Times(1) + k8sClientMock.EXPECT().Delete(cancelCtx, mock.Anything).Return(nil).Times(1) + k8sClientMock.EXPECT().Get(cancelCtx, types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + + eventRecorderMock := newMockEventRecorder(t) + eventRecorderMock.EXPECT().Eventf(mock.Anything, corev1.EventTypeNormal, "Maintenance", "Maintenance mode changed to %t.", true).Run(func(object runtime.Object, eventtype string, reason string, messageFmt string, args ...interface{}) { + cancelFunc() + }) + + serviceRewriterMock := newMockServiceRewriter(t) + serviceRewriterMock.EXPECT().rewrite(cancelCtx, mock.Anything, mock.Anything).Return(nil) + + sut := maintenanceModeUpdater{ + namespace: testNamespace, + globalConfigRepo: globalConfigMock, + client: k8sClientMock, + eventRecorder: eventRecorderMock, + serviceRewriter: serviceRewriterMock, + } + + // when + err := sut.Start(cancelCtx) + channel <- repository.GlobalConfigWatchResult{} + + // then + require.NoError(t, err) + <-cancelCtx.Done() + }) + + t.Run("should return error on get watch error", func(t *testing.T) { + // given + globalConfigMock := NewMockGlobalConfigRepository(t) + globalConfigMock.EXPECT().Watch(testCtx, mock.Anything).Return(nil, assert.AnError) + + sut := maintenanceModeUpdater{ + namespace: testNamespace, + globalConfigRepo: globalConfigMock, + } + + // when + err := sut.Start(testCtx) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "failed to start maintenance watch") + }) +} + +func Test_maintenanceModeUpdater_startMaintenanceWatch(t *testing.T) { + t.Run("should return and log if the channel will be closed", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + controllerruntime.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + controllerruntime.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "maintenance watch channel canceled - stop watch").Run(func(level int, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + sut := maintenanceModeUpdater{} + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.startMaintenanceWatch(cancelCtx, channel) + }() + close(channel) + <-cancelCtx.Done() + }) + + t.Run("should continue and log error on watch result error", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + controllerruntime.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + controllerruntime.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "context done - stop global config watcher for maintenance") + mockLogSink.EXPECT().Error(assert.AnError, "maintenance watch channel error").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + sut := maintenanceModeUpdater{} + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.startMaintenanceWatch(cancelCtx, channel) + }() + channel <- repository.GlobalConfigWatchResult{Err: assert.AnError} + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C + }) + + t.Run("should return error on error executing global config update on watch event", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfigRepoMock.EXPECT().Get(cancelCtx).Return(config.GlobalConfig{}, assert.AnError) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + controllerruntime.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + controllerruntime.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + // One update log gets send initially without updating anything + mockLogSink.EXPECT().Info(0, "Maintenance mode key changed in registry. Refresh ingress objects accordingly...") + mockLogSink.EXPECT().Info(0, "context done - stop global config watcher for maintenance") + mockLogSink.EXPECT().Error(mock.Anything, "failed to handle maintenance update").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + sut := maintenanceModeUpdater{ + namespace: testNamespace, + globalConfigRepo: globalConfigRepoMock, + } + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.startMaintenanceWatch(cancelCtx, channel) + }() + channel <- repository.GlobalConfigWatchResult{} + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C + }) +} diff --git a/controllers/mock_DeploymentReadyChecker_test.go b/controllers/mock_DeploymentReadyChecker_test.go index fb3a695..bd35712 100644 --- a/controllers/mock_DeploymentReadyChecker_test.go +++ b/controllers/mock_DeploymentReadyChecker_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers @@ -25,6 +25,10 @@ func (_m *MockDeploymentReadyChecker) EXPECT() *MockDeploymentReadyChecker_Expec func (_m *MockDeploymentReadyChecker) IsReady(ctx context.Context, deploymentName string) (bool, error) { ret := _m.Called(ctx, deploymentName) + if len(ret) == 0 { + panic("no return value specified for IsReady") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok { @@ -74,13 +78,12 @@ func (_c *MockDeploymentReadyChecker_IsReady_Call) RunAndReturn(run func(context return _c } -type mockConstructorTestingTNewMockDeploymentReadyChecker interface { +// NewMockDeploymentReadyChecker creates a new instance of MockDeploymentReadyChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDeploymentReadyChecker(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockDeploymentReadyChecker creates a new instance of MockDeploymentReadyChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockDeploymentReadyChecker(t mockConstructorTestingTNewMockDeploymentReadyChecker) *MockDeploymentReadyChecker { +}) *MockDeploymentReadyChecker { mock := &MockDeploymentReadyChecker{} mock.Mock.Test(t) diff --git a/controllers/mock_GlobalConfigRepository_test.go b/controllers/mock_GlobalConfigRepository_test.go new file mode 100644 index 0000000..15750be --- /dev/null +++ b/controllers/mock_GlobalConfigRepository_test.go @@ -0,0 +1,226 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package controllers + +import ( + context "context" + + config "github.com/cloudogu/k8s-registry-lib/config" + + mock "github.com/stretchr/testify/mock" + + repository "github.com/cloudogu/k8s-registry-lib/repository" +) + +// MockGlobalConfigRepository is an autogenerated mock type for the GlobalConfigRepository type +type MockGlobalConfigRepository struct { + mock.Mock +} + +type MockGlobalConfigRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGlobalConfigRepository) EXPECT() *MockGlobalConfigRepository_Expecter { + return &MockGlobalConfigRepository_Expecter{mock: &_m.Mock} +} + +// Get provides a mock function with given fields: _a0 +func (_m *MockGlobalConfigRepository) Get(_a0 context.Context) (config.GlobalConfig, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 config.GlobalConfig + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (config.GlobalConfig, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) config.GlobalConfig); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(config.GlobalConfig) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockGlobalConfigRepository_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockGlobalConfigRepository_Expecter) Get(_a0 interface{}) *MockGlobalConfigRepository_Get_Call { + return &MockGlobalConfigRepository_Get_Call{Call: _e.mock.On("Get", _a0)} +} + +func (_c *MockGlobalConfigRepository_Get_Call) Run(run func(_a0 context.Context)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) Return(_a0 config.GlobalConfig, _a1 error) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) RunAndReturn(run func(context.Context) (config.GlobalConfig, error)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, globalConfig +func (_m *MockGlobalConfigRepository) Update(ctx context.Context, globalConfig config.GlobalConfig) (config.GlobalConfig, error) { + ret := _m.Called(ctx, globalConfig) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 config.GlobalConfig + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, config.GlobalConfig) (config.GlobalConfig, error)); ok { + return rf(ctx, globalConfig) + } + if rf, ok := ret.Get(0).(func(context.Context, config.GlobalConfig) config.GlobalConfig); ok { + r0 = rf(ctx, globalConfig) + } else { + r0 = ret.Get(0).(config.GlobalConfig) + } + + if rf, ok := ret.Get(1).(func(context.Context, config.GlobalConfig) error); ok { + r1 = rf(ctx, globalConfig) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockGlobalConfigRepository_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - globalConfig config.GlobalConfig +func (_e *MockGlobalConfigRepository_Expecter) Update(ctx interface{}, globalConfig interface{}) *MockGlobalConfigRepository_Update_Call { + return &MockGlobalConfigRepository_Update_Call{Call: _e.mock.On("Update", ctx, globalConfig)} +} + +func (_c *MockGlobalConfigRepository_Update_Call) Run(run func(ctx context.Context, globalConfig config.GlobalConfig)) *MockGlobalConfigRepository_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(config.GlobalConfig)) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Update_Call) Return(_a0 config.GlobalConfig, _a1 error) *MockGlobalConfigRepository_Update_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Update_Call) RunAndReturn(run func(context.Context, config.GlobalConfig) (config.GlobalConfig, error)) *MockGlobalConfigRepository_Update_Call { + _c.Call.Return(run) + return _c +} + +// Watch provides a mock function with given fields: _a0, _a1 +func (_m *MockGlobalConfigRepository) Watch(_a0 context.Context, _a1 ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) { + _va := make([]interface{}, len(_a1)) + for _i := range _a1 { + _va[_i] = _a1[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Watch") + } + + var r0 <-chan repository.GlobalConfigWatchResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)); ok { + return rf(_a0, _a1...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) <-chan repository.GlobalConfigWatchResult); ok { + r0 = rf(_a0, _a1...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan repository.GlobalConfigWatchResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...config.WatchFilter) error); ok { + r1 = rf(_a0, _a1...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' +type MockGlobalConfigRepository_Watch_Call struct { + *mock.Call +} + +// Watch is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 ...config.WatchFilter +func (_e *MockGlobalConfigRepository_Expecter) Watch(_a0 interface{}, _a1 ...interface{}) *MockGlobalConfigRepository_Watch_Call { + return &MockGlobalConfigRepository_Watch_Call{Call: _e.mock.On("Watch", + append([]interface{}{_a0}, _a1...)...)} +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Run(run func(_a0 context.Context, _a1 ...config.WatchFilter)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]config.WatchFilter, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(config.WatchFilter) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Return(_a0 <-chan repository.GlobalConfigWatchResult, _a1 error) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) RunAndReturn(run func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(run) + return _c +} + +// NewMockGlobalConfigRepository creates a new instance of MockGlobalConfigRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockGlobalConfigRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGlobalConfigRepository { + mock := &MockGlobalConfigRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/mock_IngressUpdater_test.go b/controllers/mock_IngressUpdater_test.go index 9ba3150..64105bb 100644 --- a/controllers/mock_IngressUpdater_test.go +++ b/controllers/mock_IngressUpdater_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers @@ -26,6 +26,10 @@ func (_m *MockIngressUpdater) EXPECT() *MockIngressUpdater_Expecter { func (_m *MockIngressUpdater) UpsertIngressForService(ctx context.Context, service *v1.Service) error { ret := _m.Called(ctx, service) + if len(ret) == 0 { + panic("no return value specified for UpsertIngressForService") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *v1.Service) error); ok { r0 = rf(ctx, service) @@ -65,13 +69,12 @@ func (_c *MockIngressUpdater_UpsertIngressForService_Call) RunAndReturn(run func return _c } -type mockConstructorTestingTNewMockIngressUpdater interface { +// NewMockIngressUpdater creates a new instance of MockIngressUpdater. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockIngressUpdater(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockIngressUpdater creates a new instance of MockIngressUpdater. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockIngressUpdater(t mockConstructorTestingTNewMockIngressUpdater) *MockIngressUpdater { +}) *MockIngressUpdater { mock := &MockIngressUpdater{} mock.Mock.Test(t) diff --git a/controllers/mock_cesRegistry_test.go b/controllers/mock_cesRegistry_test.go deleted file mode 100644 index 8298158..0000000 --- a/controllers/mock_cesRegistry_test.go +++ /dev/null @@ -1,391 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package controllers - -import ( - registry "github.com/cloudogu/cesapp-lib/registry" - mock "github.com/stretchr/testify/mock" -) - -// mockCesRegistry is an autogenerated mock type for the cesRegistry type -type mockCesRegistry struct { - mock.Mock -} - -type mockCesRegistry_Expecter struct { - mock *mock.Mock -} - -func (_m *mockCesRegistry) EXPECT() *mockCesRegistry_Expecter { - return &mockCesRegistry_Expecter{mock: &_m.Mock} -} - -// BlueprintRegistry provides a mock function with given fields: -func (_m *mockCesRegistry) BlueprintRegistry() registry.ConfigurationContext { - ret := _m.Called() - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func() registry.ConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_BlueprintRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlueprintRegistry' -type mockCesRegistry_BlueprintRegistry_Call struct { - *mock.Call -} - -// BlueprintRegistry is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) BlueprintRegistry() *mockCesRegistry_BlueprintRegistry_Call { - return &mockCesRegistry_BlueprintRegistry_Call{Call: _e.mock.On("BlueprintRegistry")} -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) Run(run func()) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) RunAndReturn(run func() registry.ConfigurationContext) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Return(run) - return _c -} - -// DoguConfig provides a mock function with given fields: dogu -func (_m *mockCesRegistry) DoguConfig(dogu string) registry.ConfigurationContext { - ret := _m.Called(dogu) - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func(string) registry.ConfigurationContext); ok { - r0 = rf(dogu) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_DoguConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoguConfig' -type mockCesRegistry_DoguConfig_Call struct { - *mock.Call -} - -// DoguConfig is a helper method to define mock.On call -// - dogu string -func (_e *mockCesRegistry_Expecter) DoguConfig(dogu interface{}) *mockCesRegistry_DoguConfig_Call { - return &mockCesRegistry_DoguConfig_Call{Call: _e.mock.On("DoguConfig", dogu)} -} - -func (_c *mockCesRegistry_DoguConfig_Call) Run(run func(dogu string)) *mockCesRegistry_DoguConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_DoguConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_DoguConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_DoguConfig_Call) RunAndReturn(run func(string) registry.ConfigurationContext) *mockCesRegistry_DoguConfig_Call { - _c.Call.Return(run) - return _c -} - -// DoguRegistry provides a mock function with given fields: -func (_m *mockCesRegistry) DoguRegistry() registry.DoguRegistry { - ret := _m.Called() - - var r0 registry.DoguRegistry - if rf, ok := ret.Get(0).(func() registry.DoguRegistry); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.DoguRegistry) - } - } - - return r0 -} - -// mockCesRegistry_DoguRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoguRegistry' -type mockCesRegistry_DoguRegistry_Call struct { - *mock.Call -} - -// DoguRegistry is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) DoguRegistry() *mockCesRegistry_DoguRegistry_Call { - return &mockCesRegistry_DoguRegistry_Call{Call: _e.mock.On("DoguRegistry")} -} - -func (_c *mockCesRegistry_DoguRegistry_Call) Run(run func()) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_DoguRegistry_Call) Return(_a0 registry.DoguRegistry) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_DoguRegistry_Call) RunAndReturn(run func() registry.DoguRegistry) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Return(run) - return _c -} - -// GetNode provides a mock function with given fields: -func (_m *mockCesRegistry) GetNode() (registry.Node, error) { - ret := _m.Called() - - var r0 registry.Node - var r1 error - if rf, ok := ret.Get(0).(func() (registry.Node, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() registry.Node); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(registry.Node) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockCesRegistry_GetNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNode' -type mockCesRegistry_GetNode_Call struct { - *mock.Call -} - -// GetNode is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) GetNode() *mockCesRegistry_GetNode_Call { - return &mockCesRegistry_GetNode_Call{Call: _e.mock.On("GetNode")} -} - -func (_c *mockCesRegistry_GetNode_Call) Run(run func()) *mockCesRegistry_GetNode_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_GetNode_Call) Return(_a0 registry.Node, _a1 error) *mockCesRegistry_GetNode_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockCesRegistry_GetNode_Call) RunAndReturn(run func() (registry.Node, error)) *mockCesRegistry_GetNode_Call { - _c.Call.Return(run) - return _c -} - -// GlobalConfig provides a mock function with given fields: -func (_m *mockCesRegistry) GlobalConfig() registry.ConfigurationContext { - ret := _m.Called() - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func() registry.ConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_GlobalConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GlobalConfig' -type mockCesRegistry_GlobalConfig_Call struct { - *mock.Call -} - -// GlobalConfig is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) GlobalConfig() *mockCesRegistry_GlobalConfig_Call { - return &mockCesRegistry_GlobalConfig_Call{Call: _e.mock.On("GlobalConfig")} -} - -func (_c *mockCesRegistry_GlobalConfig_Call) Run(run func()) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_GlobalConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_GlobalConfig_Call) RunAndReturn(run func() registry.ConfigurationContext) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Return(run) - return _c -} - -// HostConfig provides a mock function with given fields: hostService -func (_m *mockCesRegistry) HostConfig(hostService string) registry.ConfigurationContext { - ret := _m.Called(hostService) - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func(string) registry.ConfigurationContext); ok { - r0 = rf(hostService) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_HostConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HostConfig' -type mockCesRegistry_HostConfig_Call struct { - *mock.Call -} - -// HostConfig is a helper method to define mock.On call -// - hostService string -func (_e *mockCesRegistry_Expecter) HostConfig(hostService interface{}) *mockCesRegistry_HostConfig_Call { - return &mockCesRegistry_HostConfig_Call{Call: _e.mock.On("HostConfig", hostService)} -} - -func (_c *mockCesRegistry_HostConfig_Call) Run(run func(hostService string)) *mockCesRegistry_HostConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_HostConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_HostConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_HostConfig_Call) RunAndReturn(run func(string) registry.ConfigurationContext) *mockCesRegistry_HostConfig_Call { - _c.Call.Return(run) - return _c -} - -// RootConfig provides a mock function with given fields: -func (_m *mockCesRegistry) RootConfig() registry.WatchConfigurationContext { - ret := _m.Called() - - var r0 registry.WatchConfigurationContext - if rf, ok := ret.Get(0).(func() registry.WatchConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.WatchConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_RootConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RootConfig' -type mockCesRegistry_RootConfig_Call struct { - *mock.Call -} - -// RootConfig is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) RootConfig() *mockCesRegistry_RootConfig_Call { - return &mockCesRegistry_RootConfig_Call{Call: _e.mock.On("RootConfig")} -} - -func (_c *mockCesRegistry_RootConfig_Call) Run(run func()) *mockCesRegistry_RootConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_RootConfig_Call) Return(_a0 registry.WatchConfigurationContext) *mockCesRegistry_RootConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_RootConfig_Call) RunAndReturn(run func() registry.WatchConfigurationContext) *mockCesRegistry_RootConfig_Call { - _c.Call.Return(run) - return _c -} - -// State provides a mock function with given fields: dogu -func (_m *mockCesRegistry) State(dogu string) registry.State { - ret := _m.Called(dogu) - - var r0 registry.State - if rf, ok := ret.Get(0).(func(string) registry.State); ok { - r0 = rf(dogu) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.State) - } - } - - return r0 -} - -// mockCesRegistry_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State' -type mockCesRegistry_State_Call struct { - *mock.Call -} - -// State is a helper method to define mock.On call -// - dogu string -func (_e *mockCesRegistry_Expecter) State(dogu interface{}) *mockCesRegistry_State_Call { - return &mockCesRegistry_State_Call{Call: _e.mock.On("State", dogu)} -} - -func (_c *mockCesRegistry_State_Call) Run(run func(dogu string)) *mockCesRegistry_State_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_State_Call) Return(_a0 registry.State) *mockCesRegistry_State_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_State_Call) RunAndReturn(run func(string) registry.State) *mockCesRegistry_State_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockCesRegistry interface { - mock.TestingT - Cleanup(func()) -} - -// newMockCesRegistry creates a new instance of mockCesRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockCesRegistry(t mockConstructorTestingTnewMockCesRegistry) *mockCesRegistry { - mock := &mockCesRegistry{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/mock_configurationContext_test.go b/controllers/mock_configurationContext_test.go deleted file mode 100644 index aed634b..0000000 --- a/controllers/mock_configurationContext_test.go +++ /dev/null @@ -1,504 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package controllers - -import mock "github.com/stretchr/testify/mock" - -// mockConfigurationContext is an autogenerated mock type for the configurationContext type -type mockConfigurationContext struct { - mock.Mock -} - -type mockConfigurationContext_Expecter struct { - mock *mock.Mock -} - -func (_m *mockConfigurationContext) EXPECT() *mockConfigurationContext_Expecter { - return &mockConfigurationContext_Expecter{mock: &_m.Mock} -} - -// Delete provides a mock function with given fields: key -func (_m *mockConfigurationContext) Delete(key string) error { - ret := _m.Called(key) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type mockConfigurationContext_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -// - key string -func (_e *mockConfigurationContext_Expecter) Delete(key interface{}) *mockConfigurationContext_Delete_Call { - return &mockConfigurationContext_Delete_Call{Call: _e.mock.On("Delete", key)} -} - -func (_c *mockConfigurationContext_Delete_Call) Run(run func(key string)) *mockConfigurationContext_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_Delete_Call) Return(_a0 error) *mockConfigurationContext_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_Delete_Call) RunAndReturn(run func(string) error) *mockConfigurationContext_Delete_Call { - _c.Call.Return(run) - return _c -} - -// DeleteRecursive provides a mock function with given fields: key -func (_m *mockConfigurationContext) DeleteRecursive(key string) error { - ret := _m.Called(key) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_DeleteRecursive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteRecursive' -type mockConfigurationContext_DeleteRecursive_Call struct { - *mock.Call -} - -// DeleteRecursive is a helper method to define mock.On call -// - key string -func (_e *mockConfigurationContext_Expecter) DeleteRecursive(key interface{}) *mockConfigurationContext_DeleteRecursive_Call { - return &mockConfigurationContext_DeleteRecursive_Call{Call: _e.mock.On("DeleteRecursive", key)} -} - -func (_c *mockConfigurationContext_DeleteRecursive_Call) Run(run func(key string)) *mockConfigurationContext_DeleteRecursive_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_DeleteRecursive_Call) Return(_a0 error) *mockConfigurationContext_DeleteRecursive_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_DeleteRecursive_Call) RunAndReturn(run func(string) error) *mockConfigurationContext_DeleteRecursive_Call { - _c.Call.Return(run) - return _c -} - -// Exists provides a mock function with given fields: key -func (_m *mockConfigurationContext) Exists(key string) (bool, error) { - ret := _m.Called(key) - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockConfigurationContext_Exists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exists' -type mockConfigurationContext_Exists_Call struct { - *mock.Call -} - -// Exists is a helper method to define mock.On call -// - key string -func (_e *mockConfigurationContext_Expecter) Exists(key interface{}) *mockConfigurationContext_Exists_Call { - return &mockConfigurationContext_Exists_Call{Call: _e.mock.On("Exists", key)} -} - -func (_c *mockConfigurationContext_Exists_Call) Run(run func(key string)) *mockConfigurationContext_Exists_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_Exists_Call) Return(_a0 bool, _a1 error) *mockConfigurationContext_Exists_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockConfigurationContext_Exists_Call) RunAndReturn(run func(string) (bool, error)) *mockConfigurationContext_Exists_Call { - _c.Call.Return(run) - return _c -} - -// Get provides a mock function with given fields: key -func (_m *mockConfigurationContext) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockConfigurationContext_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockConfigurationContext_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockConfigurationContext_Expecter) Get(key interface{}) *mockConfigurationContext_Get_Call { - return &mockConfigurationContext_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockConfigurationContext_Get_Call) Run(run func(key string)) *mockConfigurationContext_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_Get_Call) Return(_a0 string, _a1 error) *mockConfigurationContext_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockConfigurationContext_Get_Call) RunAndReturn(run func(string) (string, error)) *mockConfigurationContext_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetAll provides a mock function with given fields: -func (_m *mockConfigurationContext) GetAll() (map[string]string, error) { - ret := _m.Called() - - var r0 map[string]string - var r1 error - if rf, ok := ret.Get(0).(func() (map[string]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() map[string]string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockConfigurationContext_GetAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAll' -type mockConfigurationContext_GetAll_Call struct { - *mock.Call -} - -// GetAll is a helper method to define mock.On call -func (_e *mockConfigurationContext_Expecter) GetAll() *mockConfigurationContext_GetAll_Call { - return &mockConfigurationContext_GetAll_Call{Call: _e.mock.On("GetAll")} -} - -func (_c *mockConfigurationContext_GetAll_Call) Run(run func()) *mockConfigurationContext_GetAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockConfigurationContext_GetAll_Call) Return(_a0 map[string]string, _a1 error) *mockConfigurationContext_GetAll_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockConfigurationContext_GetAll_Call) RunAndReturn(run func() (map[string]string, error)) *mockConfigurationContext_GetAll_Call { - _c.Call.Return(run) - return _c -} - -// GetOrFalse provides a mock function with given fields: key -func (_m *mockConfigurationContext) GetOrFalse(key string) (bool, string, error) { - ret := _m.Called(key) - - var r0 bool - var r1 string - var r2 error - if rf, ok := ret.Get(0).(func(string) (bool, string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(string) string); ok { - r1 = rf(key) - } else { - r1 = ret.Get(1).(string) - } - - if rf, ok := ret.Get(2).(func(string) error); ok { - r2 = rf(key) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// mockConfigurationContext_GetOrFalse_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrFalse' -type mockConfigurationContext_GetOrFalse_Call struct { - *mock.Call -} - -// GetOrFalse is a helper method to define mock.On call -// - key string -func (_e *mockConfigurationContext_Expecter) GetOrFalse(key interface{}) *mockConfigurationContext_GetOrFalse_Call { - return &mockConfigurationContext_GetOrFalse_Call{Call: _e.mock.On("GetOrFalse", key)} -} - -func (_c *mockConfigurationContext_GetOrFalse_Call) Run(run func(key string)) *mockConfigurationContext_GetOrFalse_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_GetOrFalse_Call) Return(_a0 bool, _a1 string, _a2 error) *mockConfigurationContext_GetOrFalse_Call { - _c.Call.Return(_a0, _a1, _a2) - return _c -} - -func (_c *mockConfigurationContext_GetOrFalse_Call) RunAndReturn(run func(string) (bool, string, error)) *mockConfigurationContext_GetOrFalse_Call { - _c.Call.Return(run) - return _c -} - -// Refresh provides a mock function with given fields: key, timeToLiveInSeconds -func (_m *mockConfigurationContext) Refresh(key string, timeToLiveInSeconds int) error { - ret := _m.Called(key, timeToLiveInSeconds) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int) error); ok { - r0 = rf(key, timeToLiveInSeconds) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_Refresh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Refresh' -type mockConfigurationContext_Refresh_Call struct { - *mock.Call -} - -// Refresh is a helper method to define mock.On call -// - key string -// - timeToLiveInSeconds int -func (_e *mockConfigurationContext_Expecter) Refresh(key interface{}, timeToLiveInSeconds interface{}) *mockConfigurationContext_Refresh_Call { - return &mockConfigurationContext_Refresh_Call{Call: _e.mock.On("Refresh", key, timeToLiveInSeconds)} -} - -func (_c *mockConfigurationContext_Refresh_Call) Run(run func(key string, timeToLiveInSeconds int)) *mockConfigurationContext_Refresh_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(int)) - }) - return _c -} - -func (_c *mockConfigurationContext_Refresh_Call) Return(_a0 error) *mockConfigurationContext_Refresh_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_Refresh_Call) RunAndReturn(run func(string, int) error) *mockConfigurationContext_Refresh_Call { - _c.Call.Return(run) - return _c -} - -// RemoveAll provides a mock function with given fields: -func (_m *mockConfigurationContext) RemoveAll() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_RemoveAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAll' -type mockConfigurationContext_RemoveAll_Call struct { - *mock.Call -} - -// RemoveAll is a helper method to define mock.On call -func (_e *mockConfigurationContext_Expecter) RemoveAll() *mockConfigurationContext_RemoveAll_Call { - return &mockConfigurationContext_RemoveAll_Call{Call: _e.mock.On("RemoveAll")} -} - -func (_c *mockConfigurationContext_RemoveAll_Call) Run(run func()) *mockConfigurationContext_RemoveAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockConfigurationContext_RemoveAll_Call) Return(_a0 error) *mockConfigurationContext_RemoveAll_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_RemoveAll_Call) RunAndReturn(run func() error) *mockConfigurationContext_RemoveAll_Call { - _c.Call.Return(run) - return _c -} - -// Set provides a mock function with given fields: key, value -func (_m *mockConfigurationContext) Set(key string, value string) error { - ret := _m.Called(key, value) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(key, value) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' -type mockConfigurationContext_Set_Call struct { - *mock.Call -} - -// Set is a helper method to define mock.On call -// - key string -// - value string -func (_e *mockConfigurationContext_Expecter) Set(key interface{}, value interface{}) *mockConfigurationContext_Set_Call { - return &mockConfigurationContext_Set_Call{Call: _e.mock.On("Set", key, value)} -} - -func (_c *mockConfigurationContext_Set_Call) Run(run func(key string, value string)) *mockConfigurationContext_Set_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *mockConfigurationContext_Set_Call) Return(_a0 error) *mockConfigurationContext_Set_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_Set_Call) RunAndReturn(run func(string, string) error) *mockConfigurationContext_Set_Call { - _c.Call.Return(run) - return _c -} - -// SetWithLifetime provides a mock function with given fields: key, value, timeToLiveInSeconds -func (_m *mockConfigurationContext) SetWithLifetime(key string, value string, timeToLiveInSeconds int) error { - ret := _m.Called(key, value, timeToLiveInSeconds) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, int) error); ok { - r0 = rf(key, value, timeToLiveInSeconds) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockConfigurationContext_SetWithLifetime_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWithLifetime' -type mockConfigurationContext_SetWithLifetime_Call struct { - *mock.Call -} - -// SetWithLifetime is a helper method to define mock.On call -// - key string -// - value string -// - timeToLiveInSeconds int -func (_e *mockConfigurationContext_Expecter) SetWithLifetime(key interface{}, value interface{}, timeToLiveInSeconds interface{}) *mockConfigurationContext_SetWithLifetime_Call { - return &mockConfigurationContext_SetWithLifetime_Call{Call: _e.mock.On("SetWithLifetime", key, value, timeToLiveInSeconds)} -} - -func (_c *mockConfigurationContext_SetWithLifetime_Call) Run(run func(key string, value string, timeToLiveInSeconds int)) *mockConfigurationContext_SetWithLifetime_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(int)) - }) - return _c -} - -func (_c *mockConfigurationContext_SetWithLifetime_Call) Return(_a0 error) *mockConfigurationContext_SetWithLifetime_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockConfigurationContext_SetWithLifetime_Call) RunAndReturn(run func(string, string, int) error) *mockConfigurationContext_SetWithLifetime_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockConfigurationContext interface { - mock.TestingT - Cleanup(func()) -} - -// newMockConfigurationContext creates a new instance of mockConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockConfigurationContext(t mockConstructorTestingTnewMockConfigurationContext) *mockConfigurationContext { - mock := &mockConfigurationContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/mock_eventRecorder_test.go b/controllers/mock_eventRecorder_test.go index cd6de49..fdc2727 100644 --- a/controllers/mock_eventRecorder_test.go +++ b/controllers/mock_eventRecorder_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers @@ -151,13 +151,12 @@ func (_c *mockEventRecorder_Eventf_Call) RunAndReturn(run func(runtime.Object, s return _c } -type mockConstructorTestingTnewMockEventRecorder interface { +// newMockEventRecorder creates a new instance of mockEventRecorder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockEventRecorder(t interface { mock.TestingT Cleanup(func()) -} - -// newMockEventRecorder creates a new instance of mockEventRecorder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockEventRecorder(t mockConstructorTestingTnewMockEventRecorder) *mockEventRecorder { +}) *mockEventRecorder { mock := &mockEventRecorder{} mock.Mock.Test(t) diff --git a/controllers/mock_k8sClient_test.go b/controllers/mock_k8sClient_test.go index c77ebd0..cafc376 100644 --- a/controllers/mock_k8sClient_test.go +++ b/controllers/mock_k8sClient_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers @@ -42,6 +42,10 @@ func (_m *mockK8sClient) Create(ctx context.Context, obj client.Object, opts ... _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.CreateOption) error); ok { r0 = rf(ctx, obj, opts...) @@ -100,6 +104,10 @@ func (_m *mockK8sClient) Delete(ctx context.Context, obj client.Object, opts ... _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteOption) error); ok { r0 = rf(ctx, obj, opts...) @@ -158,6 +166,10 @@ func (_m *mockK8sClient) DeleteAllOf(ctx context.Context, obj client.Object, opt _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteAllOf") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteAllOfOption) error); ok { r0 = rf(ctx, obj, opts...) @@ -216,6 +228,10 @@ func (_m *mockK8sClient) Get(ctx context.Context, key types.NamespacedName, obj _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error); ok { r0 = rf(ctx, key, obj, opts...) @@ -268,6 +284,10 @@ func (_c *mockK8sClient_Get_Call) RunAndReturn(run func(context.Context, types.N func (_m *mockK8sClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { ret := _m.Called(obj) + if len(ret) == 0 { + panic("no return value specified for GroupVersionKindFor") + } + var r0 schema.GroupVersionKind var r1 error if rf, ok := ret.Get(0).(func(runtime.Object) (schema.GroupVersionKind, error)); ok { @@ -320,6 +340,10 @@ func (_c *mockK8sClient_GroupVersionKindFor_Call) RunAndReturn(run func(runtime. func (_m *mockK8sClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { ret := _m.Called(obj) + if len(ret) == 0 { + panic("no return value specified for IsObjectNamespaced") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(runtime.Object) (bool, error)); ok { @@ -379,6 +403,10 @@ func (_m *mockK8sClient) List(ctx context.Context, list client.ObjectList, opts _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.ObjectList, ...client.ListOption) error); ok { r0 = rf(ctx, list, opts...) @@ -437,6 +465,10 @@ func (_m *mockK8sClient) Patch(ctx context.Context, obj client.Object, patch cli _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Patch") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.Object, client.Patch, ...client.PatchOption) error); ok { r0 = rf(ctx, obj, patch, opts...) @@ -489,6 +521,10 @@ func (_c *mockK8sClient_Patch_Call) RunAndReturn(run func(context.Context, clien func (_m *mockK8sClient) RESTMapper() meta.RESTMapper { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RESTMapper") + } + var r0 meta.RESTMapper if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { r0 = rf() @@ -532,6 +568,10 @@ func (_c *mockK8sClient_RESTMapper_Call) RunAndReturn(run func() meta.RESTMapper func (_m *mockK8sClient) Scheme() *runtime.Scheme { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Scheme") + } + var r0 *runtime.Scheme if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { r0 = rf() @@ -575,6 +615,10 @@ func (_c *mockK8sClient_Scheme_Call) RunAndReturn(run func() *runtime.Scheme) *m func (_m *mockK8sClient) Status() client.SubResourceWriter { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Status") + } + var r0 client.SubResourceWriter if rf, ok := ret.Get(0).(func() client.SubResourceWriter); ok { r0 = rf() @@ -618,6 +662,10 @@ func (_c *mockK8sClient_Status_Call) RunAndReturn(run func() client.SubResourceW func (_m *mockK8sClient) SubResource(subResource string) client.SubResourceClient { ret := _m.Called(subResource) + if len(ret) == 0 { + panic("no return value specified for SubResource") + } + var r0 client.SubResourceClient if rf, ok := ret.Get(0).(func(string) client.SubResourceClient); ok { r0 = rf(subResource) @@ -669,6 +717,10 @@ func (_m *mockK8sClient) Update(ctx context.Context, obj client.Object, opts ... _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.UpdateOption) error); ok { r0 = rf(ctx, obj, opts...) @@ -716,13 +768,12 @@ func (_c *mockK8sClient_Update_Call) RunAndReturn(run func(context.Context, clie return _c } -type mockConstructorTestingTnewMockK8sClient interface { +// newMockK8sClient creates a new instance of mockK8sClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockK8sClient(t interface { mock.TestingT Cleanup(func()) -} - -// newMockK8sClient creates a new instance of mockK8sClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockK8sClient(t mockConstructorTestingTnewMockK8sClient) *mockK8sClient { +}) *mockK8sClient { mock := &mockK8sClient{} mock.Mock.Test(t) diff --git a/controllers/mock_LogSink_test.go b/controllers/mock_logSink_test.go similarity index 100% rename from controllers/mock_LogSink_test.go rename to controllers/mock_logSink_test.go diff --git a/controllers/mock_maintenanceWatchConfigurationContext_test.go b/controllers/mock_maintenanceWatchConfigurationContext_test.go deleted file mode 100644 index 5710e79..0000000 --- a/controllers/mock_maintenanceWatchConfigurationContext_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package controllers - -import ( - context "context" - - client "go.etcd.io/etcd/client/v2" - - mock "github.com/stretchr/testify/mock" -) - -// mockMaintenanceWatchConfigurationContext is an autogenerated mock type for the maintenanceWatchConfigurationContext type -type mockMaintenanceWatchConfigurationContext struct { - mock.Mock -} - -type mockMaintenanceWatchConfigurationContext_Expecter struct { - mock *mock.Mock -} - -func (_m *mockMaintenanceWatchConfigurationContext) EXPECT() *mockMaintenanceWatchConfigurationContext_Expecter { - return &mockMaintenanceWatchConfigurationContext_Expecter{mock: &_m.Mock} -} - -// Get provides a mock function with given fields: key -func (_m *mockMaintenanceWatchConfigurationContext) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockMaintenanceWatchConfigurationContext_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockMaintenanceWatchConfigurationContext_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockMaintenanceWatchConfigurationContext_Expecter) Get(key interface{}) *mockMaintenanceWatchConfigurationContext_Get_Call { - return &mockMaintenanceWatchConfigurationContext_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockMaintenanceWatchConfigurationContext_Get_Call) Run(run func(key string)) *mockMaintenanceWatchConfigurationContext_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_Get_Call) Return(_a0 string, _a1 error) *mockMaintenanceWatchConfigurationContext_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_Get_Call) RunAndReturn(run func(string) (string, error)) *mockMaintenanceWatchConfigurationContext_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetChildrenPaths provides a mock function with given fields: key -func (_m *mockMaintenanceWatchConfigurationContext) GetChildrenPaths(key string) ([]string, error) { - ret := _m.Called(key) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) []string); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChildrenPaths' -type mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call struct { - *mock.Call -} - -// GetChildrenPaths is a helper method to define mock.On call -// - key string -func (_e *mockMaintenanceWatchConfigurationContext_Expecter) GetChildrenPaths(key interface{}) *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call { - return &mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call{Call: _e.mock.On("GetChildrenPaths", key)} -} - -func (_c *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call) Run(run func(key string)) *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call) Return(_a0 []string, _a1 error) *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call) RunAndReturn(run func(string) ([]string, error)) *mockMaintenanceWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(run) - return _c -} - -// Watch provides a mock function with given fields: ctx, key, recursive, eventChannel -func (_m *mockMaintenanceWatchConfigurationContext) Watch(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response) { - _m.Called(ctx, key, recursive, eventChannel) -} - -// mockMaintenanceWatchConfigurationContext_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' -type mockMaintenanceWatchConfigurationContext_Watch_Call struct { - *mock.Call -} - -// Watch is a helper method to define mock.On call -// - ctx context.Context -// - key string -// - recursive bool -// - eventChannel chan *client.Response -func (_e *mockMaintenanceWatchConfigurationContext_Expecter) Watch(ctx interface{}, key interface{}, recursive interface{}, eventChannel interface{}) *mockMaintenanceWatchConfigurationContext_Watch_Call { - return &mockMaintenanceWatchConfigurationContext_Watch_Call{Call: _e.mock.On("Watch", ctx, key, recursive, eventChannel)} -} - -func (_c *mockMaintenanceWatchConfigurationContext_Watch_Call) Run(run func(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response)) *mockMaintenanceWatchConfigurationContext_Watch_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(bool), args[3].(chan *client.Response)) - }) - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_Watch_Call) Return() *mockMaintenanceWatchConfigurationContext_Watch_Call { - _c.Call.Return() - return _c -} - -func (_c *mockMaintenanceWatchConfigurationContext_Watch_Call) RunAndReturn(run func(context.Context, string, bool, chan *client.Response)) *mockMaintenanceWatchConfigurationContext_Watch_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockMaintenanceWatchConfigurationContext interface { - mock.TestingT - Cleanup(func()) -} - -// newMockMaintenanceWatchConfigurationContext creates a new instance of mockMaintenanceWatchConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockMaintenanceWatchConfigurationContext(t mockConstructorTestingTnewMockMaintenanceWatchConfigurationContext) *mockMaintenanceWatchConfigurationContext { - mock := &mockMaintenanceWatchConfigurationContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/mock_selfSignedCertificateCreator_test.go b/controllers/mock_selfSignedCertificateCreator_test.go index be61c67..f57b62c 100644 --- a/controllers/mock_selfSignedCertificateCreator_test.go +++ b/controllers/mock_selfSignedCertificateCreator_test.go @@ -1,8 +1,12 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers -import mock "github.com/stretchr/testify/mock" +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) // mockSelfSignedCertificateCreator is an autogenerated mock type for the selfSignedCertificateCreator type type mockSelfSignedCertificateCreator struct { @@ -17,13 +21,17 @@ func (_m *mockSelfSignedCertificateCreator) EXPECT() *mockSelfSignedCertificateC return &mockSelfSignedCertificateCreator_Expecter{mock: &_m.Mock} } -// CreateAndSafeCertificate provides a mock function with given fields: certExpireDays, country, province, locality, altDNSNames -func (_m *mockSelfSignedCertificateCreator) CreateAndSafeCertificate(certExpireDays int, country string, province string, locality string, altDNSNames []string) error { - ret := _m.Called(certExpireDays, country, province, locality, altDNSNames) +// CreateAndSafeCertificate provides a mock function with given fields: ctx, certExpireDays, country, province, locality, altDNSNames +func (_m *mockSelfSignedCertificateCreator) CreateAndSafeCertificate(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string) error { + ret := _m.Called(ctx, certExpireDays, country, province, locality, altDNSNames) + + if len(ret) == 0 { + panic("no return value specified for CreateAndSafeCertificate") + } var r0 error - if rf, ok := ret.Get(0).(func(int, string, string, string, []string) error); ok { - r0 = rf(certExpireDays, country, province, locality, altDNSNames) + if rf, ok := ret.Get(0).(func(context.Context, int, string, string, string, []string) error); ok { + r0 = rf(ctx, certExpireDays, country, province, locality, altDNSNames) } else { r0 = ret.Error(0) } @@ -37,18 +45,19 @@ type mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call struct { } // CreateAndSafeCertificate is a helper method to define mock.On call +// - ctx context.Context // - certExpireDays int // - country string // - province string // - locality string // - altDNSNames []string -func (_e *mockSelfSignedCertificateCreator_Expecter) CreateAndSafeCertificate(certExpireDays interface{}, country interface{}, province interface{}, locality interface{}, altDNSNames interface{}) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { - return &mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call{Call: _e.mock.On("CreateAndSafeCertificate", certExpireDays, country, province, locality, altDNSNames)} +func (_e *mockSelfSignedCertificateCreator_Expecter) CreateAndSafeCertificate(ctx interface{}, certExpireDays interface{}, country interface{}, province interface{}, locality interface{}, altDNSNames interface{}) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { + return &mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call{Call: _e.mock.On("CreateAndSafeCertificate", ctx, certExpireDays, country, province, locality, altDNSNames)} } -func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Run(run func(certExpireDays int, country string, province string, locality string, altDNSNames []string)) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { +func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Run(run func(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string)) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(string), args[2].(string), args[3].(string), args[4].([]string)) + run(args[0].(context.Context), args[1].(int), args[2].(string), args[3].(string), args[4].(string), args[5].([]string)) }) return _c } @@ -58,18 +67,17 @@ func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Return return _c } -func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) RunAndReturn(run func(int, string, string, string, []string) error) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { +func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) RunAndReturn(run func(context.Context, int, string, string, string, []string) error) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTnewMockSelfSignedCertificateCreator interface { +// newMockSelfSignedCertificateCreator creates a new instance of mockSelfSignedCertificateCreator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockSelfSignedCertificateCreator(t interface { mock.TestingT Cleanup(func()) -} - -// newMockSelfSignedCertificateCreator creates a new instance of mockSelfSignedCertificateCreator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockSelfSignedCertificateCreator(t mockConstructorTestingTnewMockSelfSignedCertificateCreator) *mockSelfSignedCertificateCreator { +}) *mockSelfSignedCertificateCreator { mock := &mockSelfSignedCertificateCreator{} mock.Mock.Test(t) diff --git a/controllers/mock_serviceRewriter_test.go b/controllers/mock_serviceRewriter_test.go index 8446a09..90efd2b 100644 --- a/controllers/mock_serviceRewriter_test.go +++ b/controllers/mock_serviceRewriter_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package controllers @@ -25,6 +25,10 @@ func (_m *mockServiceRewriter) EXPECT() *mockServiceRewriter_Expecter { func (_m *mockServiceRewriter) rewrite(ctx context.Context, serviceList v1ServiceList, activateMaintenanceMode bool) error { ret := _m.Called(ctx, serviceList, activateMaintenanceMode) + if len(ret) == 0 { + panic("no return value specified for rewrite") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, v1ServiceList, bool) error); ok { r0 = rf(ctx, serviceList, activateMaintenanceMode) @@ -65,13 +69,12 @@ func (_c *mockServiceRewriter_rewrite_Call) RunAndReturn(run func(context.Contex return _c } -type mockConstructorTestingTnewMockServiceRewriter interface { +// newMockServiceRewriter creates a new instance of mockServiceRewriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockServiceRewriter(t interface { mock.TestingT Cleanup(func()) -} - -// newMockServiceRewriter creates a new instance of mockServiceRewriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockServiceRewriter(t mockConstructorTestingTnewMockServiceRewriter) *mockServiceRewriter { +}) *mockServiceRewriter { mock := &mockServiceRewriter{} mock.Mock.Test(t) diff --git a/controllers/mock_watchConfig_test.go b/controllers/mock_watchConfig_test.go deleted file mode 100644 index ea70dbc..0000000 --- a/controllers/mock_watchConfig_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package controllers - -import ( - context "context" - - client "go.etcd.io/etcd/client/v2" - - mock "github.com/stretchr/testify/mock" -) - -// mockWatchConfig is an autogenerated mock type for the watchConfig type -type mockWatchConfig struct { - mock.Mock -} - -type mockWatchConfig_Expecter struct { - mock *mock.Mock -} - -func (_m *mockWatchConfig) EXPECT() *mockWatchConfig_Expecter { - return &mockWatchConfig_Expecter{mock: &_m.Mock} -} - -// Get provides a mock function with given fields: key -func (_m *mockWatchConfig) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfig_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockWatchConfig_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfig_Expecter) Get(key interface{}) *mockWatchConfig_Get_Call { - return &mockWatchConfig_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockWatchConfig_Get_Call) Run(run func(key string)) *mockWatchConfig_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfig_Get_Call) Return(_a0 string, _a1 error) *mockWatchConfig_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfig_Get_Call) RunAndReturn(run func(string) (string, error)) *mockWatchConfig_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetChildrenPaths provides a mock function with given fields: key -func (_m *mockWatchConfig) GetChildrenPaths(key string) ([]string, error) { - ret := _m.Called(key) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) []string); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfig_GetChildrenPaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChildrenPaths' -type mockWatchConfig_GetChildrenPaths_Call struct { - *mock.Call -} - -// GetChildrenPaths is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfig_Expecter) GetChildrenPaths(key interface{}) *mockWatchConfig_GetChildrenPaths_Call { - return &mockWatchConfig_GetChildrenPaths_Call{Call: _e.mock.On("GetChildrenPaths", key)} -} - -func (_c *mockWatchConfig_GetChildrenPaths_Call) Run(run func(key string)) *mockWatchConfig_GetChildrenPaths_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfig_GetChildrenPaths_Call) Return(_a0 []string, _a1 error) *mockWatchConfig_GetChildrenPaths_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfig_GetChildrenPaths_Call) RunAndReturn(run func(string) ([]string, error)) *mockWatchConfig_GetChildrenPaths_Call { - _c.Call.Return(run) - return _c -} - -// Watch provides a mock function with given fields: ctx, key, recursive, eventChannel -func (_m *mockWatchConfig) Watch(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response) { - _m.Called(ctx, key, recursive, eventChannel) -} - -// mockWatchConfig_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' -type mockWatchConfig_Watch_Call struct { - *mock.Call -} - -// Watch is a helper method to define mock.On call -// - ctx context.Context -// - key string -// - recursive bool -// - eventChannel chan *client.Response -func (_e *mockWatchConfig_Expecter) Watch(ctx interface{}, key interface{}, recursive interface{}, eventChannel interface{}) *mockWatchConfig_Watch_Call { - return &mockWatchConfig_Watch_Call{Call: _e.mock.On("Watch", ctx, key, recursive, eventChannel)} -} - -func (_c *mockWatchConfig_Watch_Call) Run(run func(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response)) *mockWatchConfig_Watch_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(bool), args[3].(chan *client.Response)) - }) - return _c -} - -func (_c *mockWatchConfig_Watch_Call) Return() *mockWatchConfig_Watch_Call { - _c.Call.Return() - return _c -} - -func (_c *mockWatchConfig_Watch_Call) RunAndReturn(run func(context.Context, string, bool, chan *client.Response)) *mockWatchConfig_Watch_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockWatchConfig interface { - mock.TestingT - Cleanup(func()) -} - -// newMockWatchConfig creates a new instance of mockWatchConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockWatchConfig(t mockConstructorTestingTnewMockWatchConfig) *mockWatchConfig { - mock := &mockWatchConfig{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/mock_watchConfigurationContext_test.go b/controllers/mock_watchConfigurationContext_test.go deleted file mode 100644 index eefc1fb..0000000 --- a/controllers/mock_watchConfigurationContext_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package controllers - -import ( - context "context" - - client "go.etcd.io/etcd/client/v2" - - mock "github.com/stretchr/testify/mock" -) - -// mockWatchConfigurationContext is an autogenerated mock type for the watchConfigurationContext type -type mockWatchConfigurationContext struct { - mock.Mock -} - -type mockWatchConfigurationContext_Expecter struct { - mock *mock.Mock -} - -func (_m *mockWatchConfigurationContext) EXPECT() *mockWatchConfigurationContext_Expecter { - return &mockWatchConfigurationContext_Expecter{mock: &_m.Mock} -} - -// Get provides a mock function with given fields: key -func (_m *mockWatchConfigurationContext) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfigurationContext_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockWatchConfigurationContext_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfigurationContext_Expecter) Get(key interface{}) *mockWatchConfigurationContext_Get_Call { - return &mockWatchConfigurationContext_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockWatchConfigurationContext_Get_Call) Run(run func(key string)) *mockWatchConfigurationContext_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_Get_Call) Return(_a0 string, _a1 error) *mockWatchConfigurationContext_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfigurationContext_Get_Call) RunAndReturn(run func(string) (string, error)) *mockWatchConfigurationContext_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetChildrenPaths provides a mock function with given fields: key -func (_m *mockWatchConfigurationContext) GetChildrenPaths(key string) ([]string, error) { - ret := _m.Called(key) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) []string); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfigurationContext_GetChildrenPaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChildrenPaths' -type mockWatchConfigurationContext_GetChildrenPaths_Call struct { - *mock.Call -} - -// GetChildrenPaths is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfigurationContext_Expecter) GetChildrenPaths(key interface{}) *mockWatchConfigurationContext_GetChildrenPaths_Call { - return &mockWatchConfigurationContext_GetChildrenPaths_Call{Call: _e.mock.On("GetChildrenPaths", key)} -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) Run(run func(key string)) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) Return(_a0 []string, _a1 error) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) RunAndReturn(run func(string) ([]string, error)) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(run) - return _c -} - -// Watch provides a mock function with given fields: ctx, key, recursive, eventChannel -func (_m *mockWatchConfigurationContext) Watch(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response) { - _m.Called(ctx, key, recursive, eventChannel) -} - -// mockWatchConfigurationContext_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' -type mockWatchConfigurationContext_Watch_Call struct { - *mock.Call -} - -// Watch is a helper method to define mock.On call -// - ctx context.Context -// - key string -// - recursive bool -// - eventChannel chan *client.Response -func (_e *mockWatchConfigurationContext_Expecter) Watch(ctx interface{}, key interface{}, recursive interface{}, eventChannel interface{}) *mockWatchConfigurationContext_Watch_Call { - return &mockWatchConfigurationContext_Watch_Call{Call: _e.mock.On("Watch", ctx, key, recursive, eventChannel)} -} - -func (_c *mockWatchConfigurationContext_Watch_Call) Run(run func(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response)) *mockWatchConfigurationContext_Watch_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(bool), args[3].(chan *client.Response)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_Watch_Call) Return() *mockWatchConfigurationContext_Watch_Call { - _c.Call.Return() - return _c -} - -func (_c *mockWatchConfigurationContext_Watch_Call) RunAndReturn(run func(context.Context, string, bool, chan *client.Response)) *mockWatchConfigurationContext_Watch_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockWatchConfigurationContext interface { - mock.TestingT - Cleanup(func()) -} - -// newMockWatchConfigurationContext creates a new instance of mockWatchConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockWatchConfigurationContext(t mockConstructorTestingTnewMockWatchConfigurationContext) *mockWatchConfigurationContext { - mock := &mockWatchConfigurationContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/selfsignedCertificateUpdater.go b/controllers/selfsignedCertificateUpdater.go index 0afbab3..3d091ad 100644 --- a/controllers/selfsignedCertificateUpdater.go +++ b/controllers/selfsignedCertificateUpdater.go @@ -6,8 +6,10 @@ import ( "encoding/pem" "fmt" sslLib "github.com/cloudogu/cesapp-lib/ssl" + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" "github.com/cloudogu/k8s-service-discovery/controllers/ssl" - etcdclient "go.etcd.io/etcd/client/v2" + "github.com/cloudogu/k8s-service-discovery/controllers/util" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -16,7 +18,7 @@ import ( ) const ( - fqdnPath = "/config/_global/fqdn" + globalFqdnPath = "fqdn" serverCertificateTypePath = "certificate/type" selfsignedCertificateType = "selfsigned" ) @@ -29,24 +31,24 @@ const ( type selfsignedCertificateUpdater struct { client client.Client namespace string - registry cesRegistry + globalConfigRepo GlobalConfigRepository eventRecorder eventRecorder certificateCreator selfSignedCertificateCreator } type selfSignedCertificateCreator interface { - CreateAndSafeCertificate(certExpireDays int, country string, + CreateAndSafeCertificate(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string) error } // NewSelfsignedCertificateUpdater creates a new updater. -func NewSelfsignedCertificateUpdater(client client.Client, namespace string, cesRegistry cesRegistry, recorder eventRecorder) *selfsignedCertificateUpdater { +func NewSelfsignedCertificateUpdater(client client.Client, namespace string, globalConfigRepo GlobalConfigRepository, recorder eventRecorder) *selfsignedCertificateUpdater { return &selfsignedCertificateUpdater{ client: client, namespace: namespace, - registry: cesRegistry, + globalConfigRepo: globalConfigRepo, eventRecorder: recorder, - certificateCreator: ssl.NewCreator(cesRegistry.GlobalConfig()), + certificateCreator: ssl.NewCreator(globalConfigRepo), } } @@ -54,28 +56,42 @@ func NewSelfsignedCertificateUpdater(client client.Client, namespace string, ces func (scu *selfsignedCertificateUpdater) Start(ctx context.Context) error { logger := ctrl.LoggerFrom(ctx) logger.Info("Starting selfsigned certificate updater...") - return scu.startEtcdWatch(ctx, scu.registry.RootConfig()) + return scu.startGlobalConfigWatch(ctx) } -func (scu *selfsignedCertificateUpdater) startEtcdWatch(ctx context.Context, reg watchConfigurationContext) error { - ctrl.LoggerFrom(ctx).Info("Start etcd watcher on fqdn") +func (scu *selfsignedCertificateUpdater) startGlobalConfigWatch(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("start global config watcher for ssl certificates") + fqdnChannel, err := scu.globalConfigRepo.Watch(ctx, config.KeyFilter(globalFqdnPath)) + if err != nil { + return fmt.Errorf("failed to create fqdn watch: %w", err) + } - fqdnChannel := make(chan *etcdclient.Response) go func() { - ctrl.LoggerFrom(ctx).Info("start etcd watcher for fqdn changes") - reg.Watch(ctx, fqdnPath, false, fqdnChannel) - ctrl.LoggerFrom(ctx).Info("stop etcd watcher for fqdn changes") + scu.startFQDNWatch(ctx, fqdnChannel) }() + return nil +} + +func (scu *selfsignedCertificateUpdater) startFQDNWatch(ctx context.Context, fqdnWatchChannel <-chan repository.GlobalConfigWatchResult) { for { select { case <-ctx.Done(): - return nil - case <-fqdnChannel: - ctrl.Log.Info(fmt.Sprintf("Context: [%+v]", ctx)) + ctrl.LoggerFrom(ctx).Info("context done - stop global config watcher for fqdn changes") + return + case result, open := <-fqdnWatchChannel: + if !open { + ctrl.LoggerFrom(ctx).Info("fqdn watch channel was closed - stop watch") + return + } + if result.Err != nil { + ctrl.LoggerFrom(ctx).Error(result.Err, "fqdn watch channel error") + continue + } + err := scu.handleFqdnChange(ctx) if err != nil { - return err + ctrl.LoggerFrom(ctx).Error(err, "failed to handle fqdn update") } } } @@ -83,12 +99,17 @@ func (scu *selfsignedCertificateUpdater) startEtcdWatch(ctx context.Context, reg func (scu *selfsignedCertificateUpdater) handleFqdnChange(ctx context.Context) error { ctrl.LoggerFrom(ctx).Info("FQDN or domain changed in registry. Checking for selfsigned certificate...") - certificateType, err := scu.registry.GlobalConfig().Get(serverCertificateTypePath) + globalConfig, err := scu.globalConfigRepo.Get(ctx) if err != nil { - return fmt.Errorf("could get certificate type from registry: %w", err) + return fmt.Errorf("failed to get global config for ssl read: %w", err) } - if certificateType == selfsignedCertificateType { + certType, typeExists := globalConfig.Get(serverCertificateTypePath) + if !typeExists || !util.ContainsChars(certType.String()) { + return fmt.Errorf("%q is empty or doesn't exists: %w", serverCertificateTypePath, err) + } + + if certType == selfsignedCertificateType { ctrl.LoggerFrom(ctx).Info("Certificate is selfsigned. Regenerating certificate...") deployment := &appsv1.Deployment{} @@ -97,9 +118,9 @@ func (scu *selfsignedCertificateUpdater) handleFqdnChange(ctx context.Context) e return fmt.Errorf("selfsigned certificate handling: failed to get deployment [%s]: %w", "k8s-service-discovery-controller-manager", err) } - previousCertRaw, err := scu.registry.GlobalConfig().Get(serverCertificateID) - if err != nil { - return fmt.Errorf("failed to get previous certificate from global config: %w", err) + previousCertRaw, certExists := globalConfig.Get(serverCertificateID) + if !certExists || !util.ContainsChars(previousCertRaw.String()) { + return fmt.Errorf("%q is empty or doesn't exists", serverCertificateID) } block, _ := pem.Decode([]byte(previousCertRaw)) @@ -118,7 +139,7 @@ func (scu *selfsignedCertificateUpdater) handleFqdnChange(ctx context.Context) e locality := getFirstOrDefault(previousCert.Subject.Locality, sslLib.Locality) altDnsNames := previousCert.DNSNames - err = scu.certificateCreator.CreateAndSafeCertificate(int(expireDays), country, province, locality, altDnsNames) + err = scu.certificateCreator.CreateAndSafeCertificate(ctx, int(expireDays), country, province, locality, altDnsNames) if err != nil { return fmt.Errorf("failed to regenerate and safe selfsigned certificate: %w", err) } diff --git a/controllers/selfsignedCertificateUpdater_test.go b/controllers/selfsignedCertificateUpdater_test.go index 6b64369..639e3cf 100644 --- a/controllers/selfsignedCertificateUpdater_test.go +++ b/controllers/selfsignedCertificateUpdater_test.go @@ -4,14 +4,19 @@ import ( "context" _ "embed" "github.com/cloudogu/cesapp-lib/registry/mocks" + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v2" appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" testclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/log" "testing" "time" ) @@ -37,12 +42,102 @@ AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ== and some more` func Test_selfsignedCertificateUpdater_Start(t *testing.T) { + t.Run("should return error on error creating watch", func(t *testing.T) { + // given + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + mockGlobalConfigRepo.EXPECT().Watch(testCtx, mock.Anything).Return(nil, assert.AnError) + sut := &selfsignedCertificateUpdater{ + globalConfigRepo: mockGlobalConfigRepo, + } + + // when + err := sut.Start(testCtx) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "failed to create fqdn watch") + }) + + t.Run("should return and log message if channel is closed", func(t *testing.T) { + // given + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(testCtx, mock.Anything).Return(resultChannel, nil) + sut := &selfsignedCertificateUpdater{ + globalConfigRepo: mockGlobalConfigRepo, + } + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "Starting selfsigned certificate updater...") + mockLogSink.EXPECT().Info(0, "start global config watcher for ssl certificates") + mockLogSink.EXPECT().Info(0, "fqdn watch channel was closed - stop watch") + + // when + err := sut.Start(testCtx) + timer := time.NewTimer(time.Second) + <-timer.C + close(resultChannel) + timer = time.NewTimer(time.Second) + <-timer.C + + // then + require.NoError(t, err) + }) + + t.Run("should log error on error in result channel", func(t *testing.T) { + // given + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + sut := &selfsignedCertificateUpdater{ + globalConfigRepo: mockGlobalConfigRepo, + } + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "Starting selfsigned certificate updater...") + mockLogSink.EXPECT().Info(0, "start global config watcher for ssl certificates") + mockLogSink.EXPECT().Info(0, "context done - stop global config watcher for fqdn changes") + mockLogSink.EXPECT().Error(assert.AnError, "fqdn watch channel error").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + // when + err := sut.Start(ctx) + + resultChannel <- repository.GlobalConfigWatchResult{ + Err: assert.AnError, + } + + // then + require.NoError(t, err) + <-ctx.Done() + timer := time.NewTimer(time.Millisecond + 250) + <-timer.C + }) + t.Run("run start without change and send done to context", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - regMock.EXPECT().RootConfig().Return(watchContextMock) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Return() + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) recorderMock := newMockEventRecorder(t) @@ -50,14 +145,12 @@ func Test_selfsignedCertificateUpdater_Start(t *testing.T) { deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() sut := &selfsignedCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: recorderMock, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*50) - // when err := sut.Start(ctx) cancelFunc() @@ -68,320 +161,359 @@ func Test_selfsignedCertificateUpdater_Start(t *testing.T) { t.Run("should fail to get certificate type", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("", assert.AnError) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + ctx, cancelFunc := context.WithCancel(context.Background()) + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "Starting selfsigned certificate updater...") + mockLogSink.EXPECT().Info(0, "start global config watcher for ssl certificates") + mockLogSink.EXPECT().Info(0, "context done - stop global config watcher for fqdn changes") + mockLogSink.EXPECT().Info(0, "FQDN or domain changed in registry. Checking for selfsigned certificate...") + mockLogSink.EXPECT().Error(mock.Anything, "failed to handle fqdn update", mock.Anything).Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "", + }) + mockGlobalConfigRepo.EXPECT().Get(ctx).Return(globalConfig, nil) namespace := "myTestNamespace" sut := &selfsignedCertificateUpdater{ - client: nil, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + client: nil, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: nil, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when err := sut.Start(ctx) - cancelFunc() + resultChannel <- repository.GlobalConfigWatchResult{} // then - require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) - assert.ErrorContains(t, err, "could get certificate type from registry") + require.NoError(t, err) + <-ctx.Done() + // Wait for last log + timer := time.NewTimer(time.Second) + <-timer.C }) - t.Run("should succeed for not selfsigned certificate", func(t *testing.T) { + t.Run("should fail to getting global config", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("notselfsigned", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + ctx, cancelFunc := context.WithCancel(context.Background()) + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "Starting selfsigned certificate updater...") + mockLogSink.EXPECT().Info(0, "start global config watcher for ssl certificates") + mockLogSink.EXPECT().Info(0, "context done - stop global config watcher for fqdn changes") + mockLogSink.EXPECT().Info(0, "FQDN or domain changed in registry. Checking for selfsigned certificate...") + mockLogSink.EXPECT().Error(mock.Anything, "failed to handle fqdn update", mock.Anything).Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + mockGlobalConfigRepo.EXPECT().Get(ctx).Return(config.GlobalConfig{}, assert.AnError) namespace := "myTestNamespace" sut := &selfsignedCertificateUpdater{ - client: nil, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + client: nil, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: nil, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when err := sut.Start(ctx) - cancelFunc() + resultChannel <- repository.GlobalConfigWatchResult{} // then require.NoError(t, err) + <-ctx.Done() }) - t.Run("should fail to get server certificate", func(t *testing.T) { + t.Run("should succeed for not selfsigned certificate", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - globalConfigMock.On("Get", "certificate/server.crt").Return("", assert.AnError) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + ctx, cancelFunc := context.WithCancel(context.Background()) + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "Starting selfsigned certificate updater...") + mockLogSink.EXPECT().Info(0, "start global config watcher for ssl certificates") + mockLogSink.EXPECT().Info(0, "FQDN or domain changed in registry. Checking for selfsigned certificate...") + + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + mockGlobalConfigRepo.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "external", + }) + mockGlobalConfigRepo.EXPECT().Get(ctx).Return(globalConfig, nil) namespace := "myTestNamespace" - - k8sClientMock := newMockK8sClient(t) - k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). - Return(nil) - sut := &selfsignedCertificateUpdater{ - client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + client: nil, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: nil, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when err := sut.Start(ctx) - cancelFunc() + resultChannel <- repository.GlobalConfigWatchResult{} + timer := time.NewTimer(time.Second) + <-timer.C // then - require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) - assert.ErrorContains(t, err, "failed to get previous certificate from global config") + require.NoError(t, err) + cancelFunc() }) +} - t.Run("should fail to parse certificate block", func(t *testing.T) { +func Test_selfsignedCertificateUpdater_handleFqdnChange(t *testing.T) { + t.Run("should fail parsing the cert", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - globalConfigMock.On("Get", "certificate/server.crt").Return("unparsableCert", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) - - namespace := "myTestNamespace" - k8sClientMock := newMockK8sClient(t) k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": "unparsableCert", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) sut := &selfsignedCertificateUpdater{ - client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + client: k8sClientMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when - err := sut.Start(ctx) - cancelFunc() + err := sut.handleFqdnChange(testCtx) // then require.Error(t, err) assert.ErrorContains(t, err, "failed to parse certificate PEM of previous certificate") }) - t.Run("should fail to parse certificate", func(t *testing.T) { + t.Run("should fail parsing the cert block", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - globalConfigMock.On("Get", "certificate/server.crt").Return(pubPEMData, nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) - - namespace := "myTestNamespace" - k8sClientMock := newMockK8sClient(t) k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": config.Value(pubPEMData), + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) sut := &selfsignedCertificateUpdater{ - client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + client: k8sClientMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when - err := sut.Start(ctx) - cancelFunc() + err := sut.handleFqdnChange(testCtx) // then require.Error(t, err) - assert.ErrorContains(t, err, "failed to parse previous certificate: x509: malformed serial number") + assert.ErrorContains(t, err, "failed to parse previous certificate") }) t.Run("should fail to create and save certificate", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - globalConfigMock.On("Get", "certificate/server.crt").Return(serverCert, nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) - - creatorMock := newMockSelfSignedCertificateCreator(t) - creatorMock.EXPECT().CreateAndSafeCertificate(365, "DE", "Lower Saxony", "Brunswick", []string{"192.168.56.2", "local.cloudogu.com"}).Return(assert.AnError) - - namespace := "myTestNamespace" - k8sClientMock := newMockK8sClient(t) k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": config.Value(serverCert), + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + creatorMock := newMockSelfSignedCertificateCreator(t) + creatorMock.EXPECT().CreateAndSafeCertificate(testCtx, 365, "DE", "Lower Saxony", "Brunswick", []string{"192.168.56.2", "local.cloudogu.com"}).Return(assert.AnError) sut := &selfsignedCertificateUpdater{ client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: nil, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, certificateCreator: creatorMock, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when - err := sut.Start(ctx) - cancelFunc() + err := sut.handleFqdnChange(testCtx) // then require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) assert.ErrorContains(t, err, "failed to regenerate and safe selfsigned certificate") }) - t.Run("should fail to get deployment", func(t *testing.T) { + t.Run("should fail on error getting the deployment", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) - - namespace := "myTestNamespace" - k8sClientMock := newMockK8sClient(t) k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). Return(assert.AnError) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": config.Value(serverCert), + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) sut := &selfsignedCertificateUpdater{ - client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: nil, - certificateCreator: nil, + client: k8sClientMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when - err := sut.Start(ctx) - cancelFunc() + err := sut.handleFqdnChange(testCtx) // then require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) assert.ErrorContains(t, err, "selfsigned certificate handling: failed to get deployment [k8s-service-discovery-controller-manager]") }) - t.Run("should succeed", func(t *testing.T) { + t.Run("should fail because a non existent certificate", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/fqdn", false, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/type").Return("selfsigned", nil) - globalConfigMock.On("Get", "certificate/server.crt").Return(serverCert, nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().Get(mocks.Anything, + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). + Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) - creatorMock := newMockSelfSignedCertificateCreator(t) - creatorMock.EXPECT().CreateAndSafeCertificate(365, "DE", "Lower Saxony", "Brunswick", []string{"192.168.56.2", "local.cloudogu.com"}).Return(nil) + sut := &selfsignedCertificateUpdater{ + client: k8sClientMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, + } - namespace := "myTestNamespace" + // when + err := sut.handleFqdnChange(testCtx) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "\"certificate/server.crt\" is empty or doesn't exists") + }) + t.Run("should fail because an empty certificate", func(t *testing.T) { + // given k8sClientMock := newMockK8sClient(t) k8sClientMock.EXPECT().Get(mocks.Anything, - types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}, mocks.Anything). + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": "", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) - recorderMock := newMockEventRecorder(t) - recorderMock.EXPECT().Event(mock.IsType(&appsv1.Deployment{}), "Normal", "FQDNChange", "Selfsigned certificate regenerated.") + sut := &selfsignedCertificateUpdater{ + client: k8sClientMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, + } + + // when + err := sut.handleFqdnChange(testCtx) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "\"certificate/server.crt\" is empty or doesn't exists") + }) + + t.Run("successfully regenerate the certificate", func(t *testing.T) { + // given + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().Get(mocks.Anything, + types.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mocks.Anything). + Return(nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/type": "selfsigned", + "certificate/server.crt": config.Value(serverCert), + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + creatorMock := newMockSelfSignedCertificateCreator(t) + creatorMock.EXPECT().CreateAndSafeCertificate(testCtx, 365, "DE", "Lower Saxony", "Brunswick", []string{"192.168.56.2", "local.cloudogu.com"}).Return(nil) + + eventRecorderMock := newMockEventRecorder(t) + eventRecorderMock.EXPECT().Event(mock.Anything, v1.EventTypeNormal, "FQDNChange", "Selfsigned certificate regenerated.") sut := &selfsignedCertificateUpdater{ client: k8sClientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + globalConfigRepo: mockGlobalConfigRepo, + namespace: testNamespace, certificateCreator: creatorMock, + eventRecorder: eventRecorderMock, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when - err := sut.Start(ctx) - cancelFunc() + err := sut.handleFqdnChange(testCtx) // then require.NoError(t, err) }) } + +func TestNewSelfsignedCertificateUpdater(t *testing.T) { + t.Run("should return not nil", func(t *testing.T) { + // given + k8sClientMock := newMockK8sClient(t) + globalConfigRepo := NewMockGlobalConfigRepository(t) + eventRecordeMock := newMockEventRecorder(t) + + // when + sut := NewSelfsignedCertificateUpdater(k8sClientMock, testNamespace, globalConfigRepo, eventRecordeMock) + + // then + require.NotNil(t, sut) + assert.Equal(t, k8sClientMock, sut.client) + assert.Equal(t, globalConfigRepo, sut.globalConfigRepo) + assert.Equal(t, eventRecordeMock, sut.eventRecorder) + assert.Equal(t, testNamespace, sut.namespace) + }) +} diff --git a/controllers/serviceController.go b/controllers/serviceController.go index ae7b9ee..1e9c027 100644 --- a/controllers/serviceController.go +++ b/controllers/serviceController.go @@ -8,7 +8,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" ) @@ -41,7 +40,7 @@ type IngressUpdater interface { // The serviceReconciler is responsible to generate ingress objects for respective services containing the ces service // discovery annotation. func (r *serviceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) + logger := ctrl.LoggerFrom(ctx) service, err := r.getService(ctx, req) if err != nil { diff --git a/controllers/serviceController_int_test.go b/controllers/serviceController_int_test.go index 9eacb17..15c279c 100644 --- a/controllers/serviceController_int_test.go +++ b/controllers/serviceController_int_test.go @@ -8,8 +8,8 @@ import ( _ "embed" "fmt" doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" + "github.com/cloudogu/k8s-registry-lib/repository" "github.com/cloudogu/k8s-service-discovery/controllers/dogustart" - etcdclient "go.etcd.io/etcd/client/v2" "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -250,7 +250,7 @@ var _ = Describe("Creating ingress objects with the ingress generator", func() { createSelfDeployment(k8sApiClient) By("Trigger channel") - SSLChannel <- &etcdclient.Response{} + SSLChannel <- repository.GlobalConfigWatchResult{} By("Expect ssl secret") Eventually(func() bool { @@ -267,6 +267,7 @@ var _ = Describe("Creating ingress objects with the ingress generator", func() { return true }, timeoutInterval, pollingInterval).Should(BeTrue()) + close(SSLChannel) }) }) }) diff --git a/controllers/ssl/api.go b/controllers/ssl/api.go index b11e183..8b34f5b 100644 --- a/controllers/ssl/api.go +++ b/controllers/ssl/api.go @@ -1,6 +1,7 @@ package ssl import ( + "context" "github.com/cloudogu/cesapp-lib/ssl" "github.com/gin-gonic/gin" "net/http" @@ -14,7 +15,7 @@ var logger = ctrl.Log.WithName("k8s-service-discovery") type selfSignedCertificateCreator interface { // CreateAndSafeCertificate generates and writes the type, cert and key to the global config. - CreateAndSafeCertificate(certExpireDays int, country string, + CreateAndSafeCertificate(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string) error } @@ -23,11 +24,11 @@ type ginRouter interface { } // SetupAPI setups the REST API for ssl generation -func SetupAPI(router ginRouter, globalConfig globalConfig) { +func SetupAPI(router ginRouter, globalConfigRepo GlobalConfigRepository) { logger.Info("Register endpoint [%s][%s]", http.MethodPost, endpointPostGenerateSSL) router.POST(endpointPostGenerateSSL, func(ctx *gin.Context) { - handleSSLRequest(ctx, NewCreator(globalConfig)) + handleSSLRequest(ctx, NewCreator(globalConfigRepo)) }) } @@ -39,7 +40,7 @@ func handleSSLRequest(ctx *gin.Context, certificateCreator selfSignedCertificate return } - err = certificateCreator.CreateAndSafeCertificate(int(i), ssl.Country, ssl.Province, ssl.Locality, []string{}) + err = certificateCreator.CreateAndSafeCertificate(ctx, int(i), ssl.Country, ssl.Province, ssl.Locality, []string{}) if err != nil { handleError(ctx, http.StatusInternalServerError, err, "Failed to create and write certificate to global config") return diff --git a/controllers/ssl/api_test.go b/controllers/ssl/api_test.go index 56fdf18..48f58a4 100644 --- a/controllers/ssl/api_test.go +++ b/controllers/ssl/api_test.go @@ -1,6 +1,7 @@ package ssl import ( + "context" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -10,6 +11,8 @@ import ( "testing" ) +var testCtx = context.Background() + func Test_handleSSLRequest(t *testing.T) { t.Run("success", func(t *testing.T) { // given @@ -20,7 +23,7 @@ func Test_handleSSLRequest(t *testing.T) { ginCtx.Request = request creatorMock := newMockSelfSignedCertificateCreator(t) - creatorMock.EXPECT().CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}).Return(nil) + creatorMock.EXPECT().CreateAndSafeCertificate(ginCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}).Return(nil) // when handleSSLRequest(ginCtx, creatorMock) diff --git a/controllers/ssl/creator.go b/controllers/ssl/creator.go index f961f5a..82099a6 100644 --- a/controllers/ssl/creator.go +++ b/controllers/ssl/creator.go @@ -1,15 +1,12 @@ package ssl import ( + "context" "fmt" - "github.com/cloudogu/cesapp-lib/registry" "github.com/cloudogu/cesapp-lib/ssl" + "github.com/cloudogu/k8s-service-discovery/controllers/util" ) -type globalConfig interface { - registry.ConfigurationContext -} - type cesSelfSignedSSLGenerator interface { // GenerateSelfSignedCert generates a self-signed certificate for the ces and returns the certificate chain and the // private key as string. @@ -19,44 +16,48 @@ type cesSelfSignedSSLGenerator interface { type cesSSLWriter interface { // WriteCertificate writes the type, cert and key to the global config - WriteCertificate(certType string, cert string, key string) error + WriteCertificate(ctx context.Context, certType string, cert string, key string) error } type creator struct { - globalConfig globalConfig - sslGenerator cesSelfSignedSSLGenerator - sslWriter cesSSLWriter + globalConfigRepo GlobalConfigRepository + sslGenerator cesSelfSignedSSLGenerator + sslWriter cesSSLWriter } // NewCreator generates and writes selfsigned certificates to the ces registry. -func NewCreator(globalConfig globalConfig) *creator { +func NewCreator(globalConfigRepo GlobalConfigRepository) *creator { return &creator{ - globalConfig: globalConfig, - sslGenerator: ssl.NewSSLGenerator(), - sslWriter: NewSSLWriter(globalConfig), + globalConfigRepo: globalConfigRepo, + sslGenerator: ssl.NewSSLGenerator(), + sslWriter: NewSSLWriter(globalConfigRepo), } } // CreateAndSafeCertificate generates and writes the type, cert and key to the global config. -func (c *creator) CreateAndSafeCertificate(certExpireDays int, country string, +func (c *creator) CreateAndSafeCertificate(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string) error { - - fqdn, err := c.globalConfig.Get("fqdn") + globalConfig, err := c.globalConfigRepo.Get(ctx) if err != nil { - return fmt.Errorf("failed to get FQDN from global config: %w", err) + return fmt.Errorf("failed to get global config for ssl creation: %w", err) } - domain, err := c.globalConfig.Get("domain") - if err != nil { - return fmt.Errorf("failed to get DOMAIN from global config: %w", err) + fqdn, exists := globalConfig.Get("fqdn") + if !exists || !util.ContainsChars(fqdn.String()) { + return fmt.Errorf("fqdn is empty or doesn't exists") + } + + domain, exists := globalConfig.Get("domain") + if !exists || !util.ContainsChars(domain.String()) { + return fmt.Errorf("domain is empty or doesn't exists: %w", err) } - cert, key, err := c.sslGenerator.GenerateSelfSignedCert(fqdn, domain, certExpireDays, country, province, locality, altDNSNames) + cert, key, err := c.sslGenerator.GenerateSelfSignedCert(fqdn.String(), domain.String(), certExpireDays, country, province, locality, altDNSNames) if err != nil { return fmt.Errorf("failed to generate self-signed certificate and key: %w", err) } - err = c.sslWriter.WriteCertificate("selfsigned", cert, key) + err = c.sslWriter.WriteCertificate(ctx, "selfsigned", cert, key) if err != nil { return fmt.Errorf("failed to write certificate to global config: %w", err) } diff --git a/controllers/ssl/creator_test.go b/controllers/ssl/creator_test.go index 945a658..36e677f 100644 --- a/controllers/ssl/creator_test.go +++ b/controllers/ssl/creator_test.go @@ -1,72 +1,125 @@ package ssl import ( + registryconfig "github.com/cloudogu/k8s-registry-lib/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" ) func Test_creator_CreateAndSafeCertificate(t *testing.T) { - t.Run("should return an error if fqdn can not be queried", func(t *testing.T) { + t.Run("should return an error if fqdn is not set", func(t *testing.T) { // given - globalConfigMock := newMockGlobalConfig(t) - getExpect := globalConfigMock.EXPECT().Get - getExpect("fqdn").Return("", assert.AnError) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfigRepoMock.EXPECT().Get(testCtx).Return(registryconfig.GlobalConfig{}, nil) sut := &creator{ - globalConfig: globalConfigMock, - sslGenerator: nil, - sslWriter: nil, + globalConfigRepo: globalConfigRepoMock, + sslGenerator: nil, + sslWriter: nil, } // when - err := sut.CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}) + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) // then require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) - assert.ErrorContains(t, err, "failed to get FQDN from global config") + assert.ErrorContains(t, err, "fqdn is empty or doesn't exists") }) - t.Run("should return an error if domain can not be queried", func(t *testing.T) { + t.Run("should return an error if fqdn is empty", func(t *testing.T) { // given - globalConfigMock := newMockGlobalConfig(t) - getExpect := globalConfigMock.EXPECT().Get - getExpect("fqdn").Return("", nil) - getExpect("domain").Return("", assert.AnError) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) sut := &creator{ - globalConfig: globalConfigMock, - sslGenerator: nil, - sslWriter: nil, + globalConfigRepo: globalConfigRepoMock, + sslGenerator: nil, + sslWriter: nil, } // when - err := sut.CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}) + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) // then require.Error(t, err) - assert.ErrorIs(t, err, assert.AnError) - assert.ErrorContains(t, err, "failed to get DOMAIN from global config") + assert.ErrorContains(t, err, "fqdn is empty or doesn't exists") }) + t.Run("should return an error if domain is not set", func(t *testing.T) { + // given + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "192.168.56.2", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + + sut := &creator{ + globalConfigRepo: globalConfigRepoMock, + sslGenerator: nil, + sslWriter: nil, + } + + // when + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "domain is empty or doesn't exists") + }) + t.Run("should return an error if domain is empty", func(t *testing.T) { + // given + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "192.168.56.2", + "domain": "", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + + sut := &creator{ + globalConfigRepo: globalConfigRepoMock, + sslGenerator: nil, + sslWriter: nil, + } + + // when + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "domain is empty or doesn't exists") + }) + t.Run("should return an error if certificate can not be generated", func(t *testing.T) { // given - globalConfigMock := newMockGlobalConfig(t) - getExpect := globalConfigMock.EXPECT().Get - getExpect("fqdn").Return("1.2.3.4", nil) - getExpect("domain").Return("local.cloudogu.com", nil) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "192.168.56.2", + "domain": "ces.local", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) sslGeneratorMock := newMockCesSelfSignedSSLGenerator(t) - sslGeneratorMock.EXPECT().GenerateSelfSignedCert("1.2.3.4", "local.cloudogu.com", 1, + sslGeneratorMock.EXPECT().GenerateSelfSignedCert("192.168.56.2", "ces.local", 1, "DE", "Lower Saxony", "Brunswick", []string{}).Return("mycert", "mykey", assert.AnError) sut := &creator{ - globalConfig: globalConfigMock, - sslGenerator: sslGeneratorMock, - sslWriter: nil, + globalConfigRepo: globalConfigRepoMock, + sslGenerator: sslGeneratorMock, + sslWriter: nil, } // when - err := sut.CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}) + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) // then require.Error(t, err) @@ -75,26 +128,30 @@ func Test_creator_CreateAndSafeCertificate(t *testing.T) { }) t.Run("should return an error if certificate can not be written", func(t *testing.T) { // given - globalConfigMock := newMockGlobalConfig(t) - getExpect := globalConfigMock.EXPECT().Get - getExpect("fqdn").Return("1.2.3.4", nil) - getExpect("domain").Return("local.cloudogu.com", nil) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "192.168.56.2", + "domain": "ces.local", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) sslGeneratorMock := newMockCesSelfSignedSSLGenerator(t) - sslGeneratorMock.EXPECT().GenerateSelfSignedCert("1.2.3.4", "local.cloudogu.com", 1, + sslGeneratorMock.EXPECT().GenerateSelfSignedCert("192.168.56.2", "ces.local", 1, "DE", "Lower Saxony", "Brunswick", []string{}).Return("mycert", "mykey", nil) sslWriterMock := newMockCesSSLWriter(t) - sslWriterMock.EXPECT().WriteCertificate("selfsigned", "mycert", "mykey").Return(assert.AnError) + sslWriterMock.EXPECT().WriteCertificate(testCtx, "selfsigned", "mycert", "mykey").Return(assert.AnError) sut := &creator{ - globalConfig: globalConfigMock, - sslGenerator: sslGeneratorMock, - sslWriter: sslWriterMock, + globalConfigRepo: globalConfigRepoMock, + sslGenerator: sslGeneratorMock, + sslWriter: sslWriterMock, } // when - err := sut.CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}) + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) // then require.Error(t, err) @@ -103,26 +160,30 @@ func Test_creator_CreateAndSafeCertificate(t *testing.T) { }) t.Run("should succeed", func(t *testing.T) { // given - globalConfigMock := newMockGlobalConfig(t) - getExpect := globalConfigMock.EXPECT().Get - getExpect("fqdn").Return("1.2.3.4", nil) - getExpect("domain").Return("local.cloudogu.com", nil) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "fqdn": "192.168.56.2", + "domain": "ces.local", + }), + } + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) sslGeneratorMock := newMockCesSelfSignedSSLGenerator(t) - sslGeneratorMock.EXPECT().GenerateSelfSignedCert("1.2.3.4", "local.cloudogu.com", 1, + sslGeneratorMock.EXPECT().GenerateSelfSignedCert("192.168.56.2", "ces.local", 1, "DE", "Lower Saxony", "Brunswick", []string{}).Return("mycert", "mykey", nil) sslWriterMock := newMockCesSSLWriter(t) - sslWriterMock.EXPECT().WriteCertificate("selfsigned", "mycert", "mykey").Return(nil) + sslWriterMock.EXPECT().WriteCertificate(testCtx, "selfsigned", "mycert", "mykey").Return(nil) sut := &creator{ - globalConfig: globalConfigMock, - sslGenerator: sslGeneratorMock, - sslWriter: sslWriterMock, + globalConfigRepo: globalConfigRepoMock, + sslGenerator: sslGeneratorMock, + sslWriter: sslWriterMock, } // when - err := sut.CreateAndSafeCertificate(1, "DE", "Lower Saxony", "Brunswick", []string{}) + err := sut.CreateAndSafeCertificate(testCtx, 1, "DE", "Lower Saxony", "Brunswick", []string{}) // then require.NoError(t, err) diff --git a/controllers/ssl/interfaces.go b/controllers/ssl/interfaces.go new file mode 100644 index 0000000..723a847 --- /dev/null +++ b/controllers/ssl/interfaces.go @@ -0,0 +1,13 @@ +package ssl + +import ( + "context" + libconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" +) + +type GlobalConfigRepository interface { + Watch(context.Context, ...libconfig.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) + Get(context.Context) (libconfig.GlobalConfig, error) + Update(ctx context.Context, globalConfig libconfig.GlobalConfig) (libconfig.GlobalConfig, error) +} diff --git a/controllers/ssl/mock_GlobalConfigRepository_test.go b/controllers/ssl/mock_GlobalConfigRepository_test.go new file mode 100644 index 0000000..18c8a20 --- /dev/null +++ b/controllers/ssl/mock_GlobalConfigRepository_test.go @@ -0,0 +1,226 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package ssl + +import ( + context "context" + + config "github.com/cloudogu/k8s-registry-lib/config" + + mock "github.com/stretchr/testify/mock" + + repository "github.com/cloudogu/k8s-registry-lib/repository" +) + +// MockGlobalConfigRepository is an autogenerated mock type for the GlobalConfigRepository type +type MockGlobalConfigRepository struct { + mock.Mock +} + +type MockGlobalConfigRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGlobalConfigRepository) EXPECT() *MockGlobalConfigRepository_Expecter { + return &MockGlobalConfigRepository_Expecter{mock: &_m.Mock} +} + +// Get provides a mock function with given fields: _a0 +func (_m *MockGlobalConfigRepository) Get(_a0 context.Context) (config.GlobalConfig, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 config.GlobalConfig + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (config.GlobalConfig, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) config.GlobalConfig); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(config.GlobalConfig) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockGlobalConfigRepository_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockGlobalConfigRepository_Expecter) Get(_a0 interface{}) *MockGlobalConfigRepository_Get_Call { + return &MockGlobalConfigRepository_Get_Call{Call: _e.mock.On("Get", _a0)} +} + +func (_c *MockGlobalConfigRepository_Get_Call) Run(run func(_a0 context.Context)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) Return(_a0 config.GlobalConfig, _a1 error) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) RunAndReturn(run func(context.Context) (config.GlobalConfig, error)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, globalConfig +func (_m *MockGlobalConfigRepository) Update(ctx context.Context, globalConfig config.GlobalConfig) (config.GlobalConfig, error) { + ret := _m.Called(ctx, globalConfig) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 config.GlobalConfig + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, config.GlobalConfig) (config.GlobalConfig, error)); ok { + return rf(ctx, globalConfig) + } + if rf, ok := ret.Get(0).(func(context.Context, config.GlobalConfig) config.GlobalConfig); ok { + r0 = rf(ctx, globalConfig) + } else { + r0 = ret.Get(0).(config.GlobalConfig) + } + + if rf, ok := ret.Get(1).(func(context.Context, config.GlobalConfig) error); ok { + r1 = rf(ctx, globalConfig) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockGlobalConfigRepository_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - globalConfig config.GlobalConfig +func (_e *MockGlobalConfigRepository_Expecter) Update(ctx interface{}, globalConfig interface{}) *MockGlobalConfigRepository_Update_Call { + return &MockGlobalConfigRepository_Update_Call{Call: _e.mock.On("Update", ctx, globalConfig)} +} + +func (_c *MockGlobalConfigRepository_Update_Call) Run(run func(ctx context.Context, globalConfig config.GlobalConfig)) *MockGlobalConfigRepository_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(config.GlobalConfig)) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Update_Call) Return(_a0 config.GlobalConfig, _a1 error) *MockGlobalConfigRepository_Update_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Update_Call) RunAndReturn(run func(context.Context, config.GlobalConfig) (config.GlobalConfig, error)) *MockGlobalConfigRepository_Update_Call { + _c.Call.Return(run) + return _c +} + +// Watch provides a mock function with given fields: _a0, _a1 +func (_m *MockGlobalConfigRepository) Watch(_a0 context.Context, _a1 ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) { + _va := make([]interface{}, len(_a1)) + for _i := range _a1 { + _va[_i] = _a1[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Watch") + } + + var r0 <-chan repository.GlobalConfigWatchResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)); ok { + return rf(_a0, _a1...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) <-chan repository.GlobalConfigWatchResult); ok { + r0 = rf(_a0, _a1...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan repository.GlobalConfigWatchResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...config.WatchFilter) error); ok { + r1 = rf(_a0, _a1...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' +type MockGlobalConfigRepository_Watch_Call struct { + *mock.Call +} + +// Watch is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 ...config.WatchFilter +func (_e *MockGlobalConfigRepository_Expecter) Watch(_a0 interface{}, _a1 ...interface{}) *MockGlobalConfigRepository_Watch_Call { + return &MockGlobalConfigRepository_Watch_Call{Call: _e.mock.On("Watch", + append([]interface{}{_a0}, _a1...)...)} +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Run(run func(_a0 context.Context, _a1 ...config.WatchFilter)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]config.WatchFilter, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(config.WatchFilter) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Return(_a0 <-chan repository.GlobalConfigWatchResult, _a1 error) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) RunAndReturn(run func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(run) + return _c +} + +// NewMockGlobalConfigRepository creates a new instance of MockGlobalConfigRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockGlobalConfigRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGlobalConfigRepository { + mock := &MockGlobalConfigRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/ssl/mock_cesSSLWriter_test.go b/controllers/ssl/mock_cesSSLWriter_test.go index f4da650..daaef26 100644 --- a/controllers/ssl/mock_cesSSLWriter_test.go +++ b/controllers/ssl/mock_cesSSLWriter_test.go @@ -1,8 +1,12 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package ssl -import mock "github.com/stretchr/testify/mock" +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) // mockCesSSLWriter is an autogenerated mock type for the cesSSLWriter type type mockCesSSLWriter struct { @@ -17,13 +21,17 @@ func (_m *mockCesSSLWriter) EXPECT() *mockCesSSLWriter_Expecter { return &mockCesSSLWriter_Expecter{mock: &_m.Mock} } -// WriteCertificate provides a mock function with given fields: certType, cert, key -func (_m *mockCesSSLWriter) WriteCertificate(certType string, cert string, key string) error { - ret := _m.Called(certType, cert, key) +// WriteCertificate provides a mock function with given fields: ctx, certType, cert, key +func (_m *mockCesSSLWriter) WriteCertificate(ctx context.Context, certType string, cert string, key string) error { + ret := _m.Called(ctx, certType, cert, key) + + if len(ret) == 0 { + panic("no return value specified for WriteCertificate") + } var r0 error - if rf, ok := ret.Get(0).(func(string, string, string) error); ok { - r0 = rf(certType, cert, key) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { + r0 = rf(ctx, certType, cert, key) } else { r0 = ret.Error(0) } @@ -37,16 +45,17 @@ type mockCesSSLWriter_WriteCertificate_Call struct { } // WriteCertificate is a helper method to define mock.On call +// - ctx context.Context // - certType string // - cert string // - key string -func (_e *mockCesSSLWriter_Expecter) WriteCertificate(certType interface{}, cert interface{}, key interface{}) *mockCesSSLWriter_WriteCertificate_Call { - return &mockCesSSLWriter_WriteCertificate_Call{Call: _e.mock.On("WriteCertificate", certType, cert, key)} +func (_e *mockCesSSLWriter_Expecter) WriteCertificate(ctx interface{}, certType interface{}, cert interface{}, key interface{}) *mockCesSSLWriter_WriteCertificate_Call { + return &mockCesSSLWriter_WriteCertificate_Call{Call: _e.mock.On("WriteCertificate", ctx, certType, cert, key)} } -func (_c *mockCesSSLWriter_WriteCertificate_Call) Run(run func(certType string, cert string, key string)) *mockCesSSLWriter_WriteCertificate_Call { +func (_c *mockCesSSLWriter_WriteCertificate_Call) Run(run func(ctx context.Context, certType string, cert string, key string)) *mockCesSSLWriter_WriteCertificate_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(string)) + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string)) }) return _c } @@ -56,18 +65,17 @@ func (_c *mockCesSSLWriter_WriteCertificate_Call) Return(_a0 error) *mockCesSSLW return _c } -func (_c *mockCesSSLWriter_WriteCertificate_Call) RunAndReturn(run func(string, string, string) error) *mockCesSSLWriter_WriteCertificate_Call { +func (_c *mockCesSSLWriter_WriteCertificate_Call) RunAndReturn(run func(context.Context, string, string, string) error) *mockCesSSLWriter_WriteCertificate_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTnewMockCesSSLWriter interface { +// newMockCesSSLWriter creates a new instance of mockCesSSLWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockCesSSLWriter(t interface { mock.TestingT Cleanup(func()) -} - -// newMockCesSSLWriter creates a new instance of mockCesSSLWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockCesSSLWriter(t mockConstructorTestingTnewMockCesSSLWriter) *mockCesSSLWriter { +}) *mockCesSSLWriter { mock := &mockCesSSLWriter{} mock.Mock.Test(t) diff --git a/controllers/ssl/mock_cesSelfSignedSSLGenerator_test.go b/controllers/ssl/mock_cesSelfSignedSSLGenerator_test.go index 00b9904..9217e05 100644 --- a/controllers/ssl/mock_cesSelfSignedSSLGenerator_test.go +++ b/controllers/ssl/mock_cesSelfSignedSSLGenerator_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package ssl @@ -21,6 +21,10 @@ func (_m *mockCesSelfSignedSSLGenerator) EXPECT() *mockCesSelfSignedSSLGenerator func (_m *mockCesSelfSignedSSLGenerator) GenerateSelfSignedCert(fqdn string, domain string, certExpireDays int, country string, province string, locality string, altDNSNames []string) (string, string, error) { ret := _m.Called(fqdn, domain, certExpireDays, country, province, locality, altDNSNames) + if len(ret) == 0 { + panic("no return value specified for GenerateSelfSignedCert") + } + var r0 string var r1 string var r2 error @@ -82,13 +86,12 @@ func (_c *mockCesSelfSignedSSLGenerator_GenerateSelfSignedCert_Call) RunAndRetur return _c } -type mockConstructorTestingTnewMockCesSelfSignedSSLGenerator interface { +// newMockCesSelfSignedSSLGenerator creates a new instance of mockCesSelfSignedSSLGenerator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockCesSelfSignedSSLGenerator(t interface { mock.TestingT Cleanup(func()) -} - -// newMockCesSelfSignedSSLGenerator creates a new instance of mockCesSelfSignedSSLGenerator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockCesSelfSignedSSLGenerator(t mockConstructorTestingTnewMockCesSelfSignedSSLGenerator) *mockCesSelfSignedSSLGenerator { +}) *mockCesSelfSignedSSLGenerator { mock := &mockCesSelfSignedSSLGenerator{} mock.Mock.Test(t) diff --git a/controllers/ssl/mock_ginRouter_test.go b/controllers/ssl/mock_ginRouter_test.go index c515fac..9fd4481 100644 --- a/controllers/ssl/mock_ginRouter_test.go +++ b/controllers/ssl/mock_ginRouter_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package ssl @@ -34,6 +34,10 @@ func (_m *mockGinRouter) Any(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Any") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -93,6 +97,10 @@ func (_m *mockGinRouter) DELETE(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DELETE") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -152,6 +160,10 @@ func (_m *mockGinRouter) GET(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GET") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -211,6 +223,10 @@ func (_m *mockGinRouter) HEAD(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for HEAD") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -270,6 +286,10 @@ func (_m *mockGinRouter) Handle(_a0 string, _a1 string, _a2 ...gin.HandlerFunc) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Handle") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1, _a2...) @@ -330,6 +350,10 @@ func (_m *mockGinRouter) Match(_a0 []string, _a1 string, _a2 ...gin.HandlerFunc) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Match") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func([]string, string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1, _a2...) @@ -390,6 +414,10 @@ func (_m *mockGinRouter) OPTIONS(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for OPTIONS") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -449,6 +477,10 @@ func (_m *mockGinRouter) PATCH(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for PATCH") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -508,6 +540,10 @@ func (_m *mockGinRouter) POST(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for POST") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -567,6 +603,10 @@ func (_m *mockGinRouter) PUT(_a0 string, _a1 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for PUT") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, ...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0, _a1...) @@ -619,6 +659,10 @@ func (_c *mockGinRouter_PUT_Call) RunAndReturn(run func(string, ...gin.HandlerFu func (_m *mockGinRouter) Static(_a0 string, _a1 string) gin.IRoutes { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for Static") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, string) gin.IRoutes); ok { r0 = rf(_a0, _a1) @@ -664,6 +708,10 @@ func (_c *mockGinRouter_Static_Call) RunAndReturn(run func(string, string) gin.I func (_m *mockGinRouter) StaticFS(_a0 string, _a1 http.FileSystem) gin.IRoutes { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for StaticFS") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, http.FileSystem) gin.IRoutes); ok { r0 = rf(_a0, _a1) @@ -709,6 +757,10 @@ func (_c *mockGinRouter_StaticFS_Call) RunAndReturn(run func(string, http.FileSy func (_m *mockGinRouter) StaticFile(_a0 string, _a1 string) gin.IRoutes { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for StaticFile") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, string) gin.IRoutes); ok { r0 = rf(_a0, _a1) @@ -754,6 +806,10 @@ func (_c *mockGinRouter_StaticFile_Call) RunAndReturn(run func(string, string) g func (_m *mockGinRouter) StaticFileFS(_a0 string, _a1 string, _a2 http.FileSystem) gin.IRoutes { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for StaticFileFS") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(string, string, http.FileSystem) gin.IRoutes); ok { r0 = rf(_a0, _a1, _a2) @@ -806,6 +862,10 @@ func (_m *mockGinRouter) Use(_a0 ...gin.HandlerFunc) gin.IRoutes { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Use") + } + var r0 gin.IRoutes if rf, ok := ret.Get(0).(func(...gin.HandlerFunc) gin.IRoutes); ok { r0 = rf(_a0...) @@ -853,13 +913,12 @@ func (_c *mockGinRouter_Use_Call) RunAndReturn(run func(...gin.HandlerFunc) gin. return _c } -type mockConstructorTestingTnewMockGinRouter interface { +// newMockGinRouter creates a new instance of mockGinRouter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockGinRouter(t interface { mock.TestingT Cleanup(func()) -} - -// newMockGinRouter creates a new instance of mockGinRouter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockGinRouter(t mockConstructorTestingTnewMockGinRouter) *mockGinRouter { +}) *mockGinRouter { mock := &mockGinRouter{} mock.Mock.Test(t) diff --git a/controllers/ssl/mock_globalConfig_test.go b/controllers/ssl/mock_globalConfig_test.go deleted file mode 100644 index fd908cf..0000000 --- a/controllers/ssl/mock_globalConfig_test.go +++ /dev/null @@ -1,504 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package ssl - -import mock "github.com/stretchr/testify/mock" - -// mockGlobalConfig is an autogenerated mock type for the globalConfig type -type mockGlobalConfig struct { - mock.Mock -} - -type mockGlobalConfig_Expecter struct { - mock *mock.Mock -} - -func (_m *mockGlobalConfig) EXPECT() *mockGlobalConfig_Expecter { - return &mockGlobalConfig_Expecter{mock: &_m.Mock} -} - -// Delete provides a mock function with given fields: key -func (_m *mockGlobalConfig) Delete(key string) error { - ret := _m.Called(key) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type mockGlobalConfig_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -// - key string -func (_e *mockGlobalConfig_Expecter) Delete(key interface{}) *mockGlobalConfig_Delete_Call { - return &mockGlobalConfig_Delete_Call{Call: _e.mock.On("Delete", key)} -} - -func (_c *mockGlobalConfig_Delete_Call) Run(run func(key string)) *mockGlobalConfig_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_Delete_Call) Return(_a0 error) *mockGlobalConfig_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_Delete_Call) RunAndReturn(run func(string) error) *mockGlobalConfig_Delete_Call { - _c.Call.Return(run) - return _c -} - -// DeleteRecursive provides a mock function with given fields: key -func (_m *mockGlobalConfig) DeleteRecursive(key string) error { - ret := _m.Called(key) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_DeleteRecursive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteRecursive' -type mockGlobalConfig_DeleteRecursive_Call struct { - *mock.Call -} - -// DeleteRecursive is a helper method to define mock.On call -// - key string -func (_e *mockGlobalConfig_Expecter) DeleteRecursive(key interface{}) *mockGlobalConfig_DeleteRecursive_Call { - return &mockGlobalConfig_DeleteRecursive_Call{Call: _e.mock.On("DeleteRecursive", key)} -} - -func (_c *mockGlobalConfig_DeleteRecursive_Call) Run(run func(key string)) *mockGlobalConfig_DeleteRecursive_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_DeleteRecursive_Call) Return(_a0 error) *mockGlobalConfig_DeleteRecursive_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_DeleteRecursive_Call) RunAndReturn(run func(string) error) *mockGlobalConfig_DeleteRecursive_Call { - _c.Call.Return(run) - return _c -} - -// Exists provides a mock function with given fields: key -func (_m *mockGlobalConfig) Exists(key string) (bool, error) { - ret := _m.Called(key) - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockGlobalConfig_Exists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exists' -type mockGlobalConfig_Exists_Call struct { - *mock.Call -} - -// Exists is a helper method to define mock.On call -// - key string -func (_e *mockGlobalConfig_Expecter) Exists(key interface{}) *mockGlobalConfig_Exists_Call { - return &mockGlobalConfig_Exists_Call{Call: _e.mock.On("Exists", key)} -} - -func (_c *mockGlobalConfig_Exists_Call) Run(run func(key string)) *mockGlobalConfig_Exists_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_Exists_Call) Return(_a0 bool, _a1 error) *mockGlobalConfig_Exists_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockGlobalConfig_Exists_Call) RunAndReturn(run func(string) (bool, error)) *mockGlobalConfig_Exists_Call { - _c.Call.Return(run) - return _c -} - -// Get provides a mock function with given fields: key -func (_m *mockGlobalConfig) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockGlobalConfig_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockGlobalConfig_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockGlobalConfig_Expecter) Get(key interface{}) *mockGlobalConfig_Get_Call { - return &mockGlobalConfig_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockGlobalConfig_Get_Call) Run(run func(key string)) *mockGlobalConfig_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_Get_Call) Return(_a0 string, _a1 error) *mockGlobalConfig_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockGlobalConfig_Get_Call) RunAndReturn(run func(string) (string, error)) *mockGlobalConfig_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetAll provides a mock function with given fields: -func (_m *mockGlobalConfig) GetAll() (map[string]string, error) { - ret := _m.Called() - - var r0 map[string]string - var r1 error - if rf, ok := ret.Get(0).(func() (map[string]string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() map[string]string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]string) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockGlobalConfig_GetAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAll' -type mockGlobalConfig_GetAll_Call struct { - *mock.Call -} - -// GetAll is a helper method to define mock.On call -func (_e *mockGlobalConfig_Expecter) GetAll() *mockGlobalConfig_GetAll_Call { - return &mockGlobalConfig_GetAll_Call{Call: _e.mock.On("GetAll")} -} - -func (_c *mockGlobalConfig_GetAll_Call) Run(run func()) *mockGlobalConfig_GetAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockGlobalConfig_GetAll_Call) Return(_a0 map[string]string, _a1 error) *mockGlobalConfig_GetAll_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockGlobalConfig_GetAll_Call) RunAndReturn(run func() (map[string]string, error)) *mockGlobalConfig_GetAll_Call { - _c.Call.Return(run) - return _c -} - -// GetOrFalse provides a mock function with given fields: key -func (_m *mockGlobalConfig) GetOrFalse(key string) (bool, string, error) { - ret := _m.Called(key) - - var r0 bool - var r1 string - var r2 error - if rf, ok := ret.Get(0).(func(string) (bool, string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(string) string); ok { - r1 = rf(key) - } else { - r1 = ret.Get(1).(string) - } - - if rf, ok := ret.Get(2).(func(string) error); ok { - r2 = rf(key) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// mockGlobalConfig_GetOrFalse_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrFalse' -type mockGlobalConfig_GetOrFalse_Call struct { - *mock.Call -} - -// GetOrFalse is a helper method to define mock.On call -// - key string -func (_e *mockGlobalConfig_Expecter) GetOrFalse(key interface{}) *mockGlobalConfig_GetOrFalse_Call { - return &mockGlobalConfig_GetOrFalse_Call{Call: _e.mock.On("GetOrFalse", key)} -} - -func (_c *mockGlobalConfig_GetOrFalse_Call) Run(run func(key string)) *mockGlobalConfig_GetOrFalse_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_GetOrFalse_Call) Return(_a0 bool, _a1 string, _a2 error) *mockGlobalConfig_GetOrFalse_Call { - _c.Call.Return(_a0, _a1, _a2) - return _c -} - -func (_c *mockGlobalConfig_GetOrFalse_Call) RunAndReturn(run func(string) (bool, string, error)) *mockGlobalConfig_GetOrFalse_Call { - _c.Call.Return(run) - return _c -} - -// Refresh provides a mock function with given fields: key, timeToLiveInSeconds -func (_m *mockGlobalConfig) Refresh(key string, timeToLiveInSeconds int) error { - ret := _m.Called(key, timeToLiveInSeconds) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int) error); ok { - r0 = rf(key, timeToLiveInSeconds) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_Refresh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Refresh' -type mockGlobalConfig_Refresh_Call struct { - *mock.Call -} - -// Refresh is a helper method to define mock.On call -// - key string -// - timeToLiveInSeconds int -func (_e *mockGlobalConfig_Expecter) Refresh(key interface{}, timeToLiveInSeconds interface{}) *mockGlobalConfig_Refresh_Call { - return &mockGlobalConfig_Refresh_Call{Call: _e.mock.On("Refresh", key, timeToLiveInSeconds)} -} - -func (_c *mockGlobalConfig_Refresh_Call) Run(run func(key string, timeToLiveInSeconds int)) *mockGlobalConfig_Refresh_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(int)) - }) - return _c -} - -func (_c *mockGlobalConfig_Refresh_Call) Return(_a0 error) *mockGlobalConfig_Refresh_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_Refresh_Call) RunAndReturn(run func(string, int) error) *mockGlobalConfig_Refresh_Call { - _c.Call.Return(run) - return _c -} - -// RemoveAll provides a mock function with given fields: -func (_m *mockGlobalConfig) RemoveAll() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_RemoveAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAll' -type mockGlobalConfig_RemoveAll_Call struct { - *mock.Call -} - -// RemoveAll is a helper method to define mock.On call -func (_e *mockGlobalConfig_Expecter) RemoveAll() *mockGlobalConfig_RemoveAll_Call { - return &mockGlobalConfig_RemoveAll_Call{Call: _e.mock.On("RemoveAll")} -} - -func (_c *mockGlobalConfig_RemoveAll_Call) Run(run func()) *mockGlobalConfig_RemoveAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockGlobalConfig_RemoveAll_Call) Return(_a0 error) *mockGlobalConfig_RemoveAll_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_RemoveAll_Call) RunAndReturn(run func() error) *mockGlobalConfig_RemoveAll_Call { - _c.Call.Return(run) - return _c -} - -// Set provides a mock function with given fields: key, value -func (_m *mockGlobalConfig) Set(key string, value string) error { - ret := _m.Called(key, value) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(key, value) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' -type mockGlobalConfig_Set_Call struct { - *mock.Call -} - -// Set is a helper method to define mock.On call -// - key string -// - value string -func (_e *mockGlobalConfig_Expecter) Set(key interface{}, value interface{}) *mockGlobalConfig_Set_Call { - return &mockGlobalConfig_Set_Call{Call: _e.mock.On("Set", key, value)} -} - -func (_c *mockGlobalConfig_Set_Call) Run(run func(key string, value string)) *mockGlobalConfig_Set_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *mockGlobalConfig_Set_Call) Return(_a0 error) *mockGlobalConfig_Set_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_Set_Call) RunAndReturn(run func(string, string) error) *mockGlobalConfig_Set_Call { - _c.Call.Return(run) - return _c -} - -// SetWithLifetime provides a mock function with given fields: key, value, timeToLiveInSeconds -func (_m *mockGlobalConfig) SetWithLifetime(key string, value string, timeToLiveInSeconds int) error { - ret := _m.Called(key, value, timeToLiveInSeconds) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, int) error); ok { - r0 = rf(key, value, timeToLiveInSeconds) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockGlobalConfig_SetWithLifetime_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWithLifetime' -type mockGlobalConfig_SetWithLifetime_Call struct { - *mock.Call -} - -// SetWithLifetime is a helper method to define mock.On call -// - key string -// - value string -// - timeToLiveInSeconds int -func (_e *mockGlobalConfig_Expecter) SetWithLifetime(key interface{}, value interface{}, timeToLiveInSeconds interface{}) *mockGlobalConfig_SetWithLifetime_Call { - return &mockGlobalConfig_SetWithLifetime_Call{Call: _e.mock.On("SetWithLifetime", key, value, timeToLiveInSeconds)} -} - -func (_c *mockGlobalConfig_SetWithLifetime_Call) Run(run func(key string, value string, timeToLiveInSeconds int)) *mockGlobalConfig_SetWithLifetime_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string), args[2].(int)) - }) - return _c -} - -func (_c *mockGlobalConfig_SetWithLifetime_Call) Return(_a0 error) *mockGlobalConfig_SetWithLifetime_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockGlobalConfig_SetWithLifetime_Call) RunAndReturn(run func(string, string, int) error) *mockGlobalConfig_SetWithLifetime_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockGlobalConfig interface { - mock.TestingT - Cleanup(func()) -} - -// newMockGlobalConfig creates a new instance of mockGlobalConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockGlobalConfig(t mockConstructorTestingTnewMockGlobalConfig) *mockGlobalConfig { - mock := &mockGlobalConfig{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/ssl/mock_selfSignedCertificateCreator_test.go b/controllers/ssl/mock_selfSignedCertificateCreator_test.go index 3f89b7e..0f0123f 100644 --- a/controllers/ssl/mock_selfSignedCertificateCreator_test.go +++ b/controllers/ssl/mock_selfSignedCertificateCreator_test.go @@ -1,8 +1,12 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package ssl -import mock "github.com/stretchr/testify/mock" +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) // mockSelfSignedCertificateCreator is an autogenerated mock type for the selfSignedCertificateCreator type type mockSelfSignedCertificateCreator struct { @@ -17,13 +21,17 @@ func (_m *mockSelfSignedCertificateCreator) EXPECT() *mockSelfSignedCertificateC return &mockSelfSignedCertificateCreator_Expecter{mock: &_m.Mock} } -// CreateAndSafeCertificate provides a mock function with given fields: certExpireDays, country, province, locality, altDNSNames -func (_m *mockSelfSignedCertificateCreator) CreateAndSafeCertificate(certExpireDays int, country string, province string, locality string, altDNSNames []string) error { - ret := _m.Called(certExpireDays, country, province, locality, altDNSNames) +// CreateAndSafeCertificate provides a mock function with given fields: ctx, certExpireDays, country, province, locality, altDNSNames +func (_m *mockSelfSignedCertificateCreator) CreateAndSafeCertificate(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string) error { + ret := _m.Called(ctx, certExpireDays, country, province, locality, altDNSNames) + + if len(ret) == 0 { + panic("no return value specified for CreateAndSafeCertificate") + } var r0 error - if rf, ok := ret.Get(0).(func(int, string, string, string, []string) error); ok { - r0 = rf(certExpireDays, country, province, locality, altDNSNames) + if rf, ok := ret.Get(0).(func(context.Context, int, string, string, string, []string) error); ok { + r0 = rf(ctx, certExpireDays, country, province, locality, altDNSNames) } else { r0 = ret.Error(0) } @@ -37,18 +45,19 @@ type mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call struct { } // CreateAndSafeCertificate is a helper method to define mock.On call +// - ctx context.Context // - certExpireDays int // - country string // - province string // - locality string // - altDNSNames []string -func (_e *mockSelfSignedCertificateCreator_Expecter) CreateAndSafeCertificate(certExpireDays interface{}, country interface{}, province interface{}, locality interface{}, altDNSNames interface{}) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { - return &mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call{Call: _e.mock.On("CreateAndSafeCertificate", certExpireDays, country, province, locality, altDNSNames)} +func (_e *mockSelfSignedCertificateCreator_Expecter) CreateAndSafeCertificate(ctx interface{}, certExpireDays interface{}, country interface{}, province interface{}, locality interface{}, altDNSNames interface{}) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { + return &mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call{Call: _e.mock.On("CreateAndSafeCertificate", ctx, certExpireDays, country, province, locality, altDNSNames)} } -func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Run(run func(certExpireDays int, country string, province string, locality string, altDNSNames []string)) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { +func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Run(run func(ctx context.Context, certExpireDays int, country string, province string, locality string, altDNSNames []string)) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int), args[1].(string), args[2].(string), args[3].(string), args[4].([]string)) + run(args[0].(context.Context), args[1].(int), args[2].(string), args[3].(string), args[4].(string), args[5].([]string)) }) return _c } @@ -58,18 +67,17 @@ func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) Return return _c } -func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) RunAndReturn(run func(int, string, string, string, []string) error) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { +func (_c *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call) RunAndReturn(run func(context.Context, int, string, string, string, []string) error) *mockSelfSignedCertificateCreator_CreateAndSafeCertificate_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTnewMockSelfSignedCertificateCreator interface { +// newMockSelfSignedCertificateCreator creates a new instance of mockSelfSignedCertificateCreator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockSelfSignedCertificateCreator(t interface { mock.TestingT Cleanup(func()) -} - -// newMockSelfSignedCertificateCreator creates a new instance of mockSelfSignedCertificateCreator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockSelfSignedCertificateCreator(t mockConstructorTestingTnewMockSelfSignedCertificateCreator) *mockSelfSignedCertificateCreator { +}) *mockSelfSignedCertificateCreator { mock := &mockSelfSignedCertificateCreator{} mock.Mock.Test(t) diff --git a/controllers/ssl/mock_setConfigurationContext_test.go b/controllers/ssl/mock_setConfigurationContext_test.go deleted file mode 100644 index 9c149e0..0000000 --- a/controllers/ssl/mock_setConfigurationContext_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package ssl - -import mock "github.com/stretchr/testify/mock" - -// mockSetConfigurationContext is an autogenerated mock type for the setConfigurationContext type -type mockSetConfigurationContext struct { - mock.Mock -} - -type mockSetConfigurationContext_Expecter struct { - mock *mock.Mock -} - -func (_m *mockSetConfigurationContext) EXPECT() *mockSetConfigurationContext_Expecter { - return &mockSetConfigurationContext_Expecter{mock: &_m.Mock} -} - -// Set provides a mock function with given fields: key, value -func (_m *mockSetConfigurationContext) Set(key string, value string) error { - ret := _m.Called(key, value) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(key, value) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockSetConfigurationContext_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' -type mockSetConfigurationContext_Set_Call struct { - *mock.Call -} - -// Set is a helper method to define mock.On call -// - key string -// - value string -func (_e *mockSetConfigurationContext_Expecter) Set(key interface{}, value interface{}) *mockSetConfigurationContext_Set_Call { - return &mockSetConfigurationContext_Set_Call{Call: _e.mock.On("Set", key, value)} -} - -func (_c *mockSetConfigurationContext_Set_Call) Run(run func(key string, value string)) *mockSetConfigurationContext_Set_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *mockSetConfigurationContext_Set_Call) Return(_a0 error) *mockSetConfigurationContext_Set_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockSetConfigurationContext_Set_Call) RunAndReturn(run func(string, string) error) *mockSetConfigurationContext_Set_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockSetConfigurationContext interface { - mock.TestingT - Cleanup(func()) -} - -// newMockSetConfigurationContext creates a new instance of mockSetConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockSetConfigurationContext(t mockConstructorTestingTnewMockSetConfigurationContext) *mockSetConfigurationContext { - mock := &mockSetConfigurationContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/ssl/sslWriter.go b/controllers/ssl/sslWriter.go index 22e2232..9fd17bb 100644 --- a/controllers/ssl/sslWriter.go +++ b/controllers/ssl/sslWriter.go @@ -1,39 +1,46 @@ package ssl import ( + "context" "fmt" + libconfig "github.com/cloudogu/k8s-registry-lib/config" ) type sslWriter struct { - globalConfig setConfigurationContext -} - -type setConfigurationContext interface { - // Set sets a configuration value in current context - Set(key, value string) error + globalConfigRepo GlobalConfigRepository } // NewSSLWriter creates a new sslWriter instance to write certificate information in the global config -func NewSSLWriter(globalConfig setConfigurationContext) *sslWriter { - return &sslWriter{globalConfig: globalConfig} +func NewSSLWriter(globalConfigRepo GlobalConfigRepository) *sslWriter { + return &sslWriter{globalConfigRepo: globalConfigRepo} } // WriteCertificate writes the type, cert and key to the global config -func (sw *sslWriter) WriteCertificate(certType string, cert string, key string) error { - err := sw.globalConfig.Set("certificate/type", certType) +func (sw *sslWriter) WriteCertificate(ctx context.Context, certType string, cert string, key string) error { + globalConfig, err := sw.globalConfigRepo.Get(ctx) + if err != nil { + return fmt.Errorf("failed to get global config for ssl creation: %w", err) + } + + globalConfig.Config, err = globalConfig.Set("certificate/type", libconfig.Value(certType)) if err != nil { return fmt.Errorf("failed to set certificate type: %w", err) } - err = sw.globalConfig.Set("certificate/server.crt", cert) + globalConfig.Config, err = globalConfig.Set("certificate/server.crt", libconfig.Value(cert)) if err != nil { return fmt.Errorf("failed to set certificate: %w", err) } - err = sw.globalConfig.Set("certificate/server.key", key) + globalConfig.Config, err = globalConfig.Set("certificate/server.key", libconfig.Value(key)) if err != nil { return fmt.Errorf("failed to set certificate key: %w", err) } + _, err = sw.globalConfigRepo.Update(ctx, globalConfig) + if err != nil { + return fmt.Errorf("failed to update global config writing ssl: %w", err) + } + return nil } diff --git a/controllers/ssl/sslWriter_test.go b/controllers/ssl/sslWriter_test.go index f4c2584..183ed08 100644 --- a/controllers/ssl/sslWriter_test.go +++ b/controllers/ssl/sslWriter_test.go @@ -1,6 +1,8 @@ package ssl import ( + "context" + registryconfig "github.com/cloudogu/k8s-registry-lib/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -12,68 +14,89 @@ func Test_sslWriter_WriteCertificate(t *testing.T) { t.Run("success", func(t *testing.T) { // given - globalConfig := newMockSetConfigurationContext(t) - setExpect := globalConfig.EXPECT().Set - setExpect("certificate/type", "self-signed").Return(nil) - setExpect("certificate/server.crt", "cert").Return(nil) - setExpect("certificate/server.key", "key").Return(nil) - writer := NewSSLWriter(globalConfig) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{}), + } + + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + globalConfigRepoMock.EXPECT().Update(testCtx, mock.Anything).RunAndReturn(func(ctx context.Context, config registryconfig.GlobalConfig) (registryconfig.GlobalConfig, error) { + assert.Equal(t, 3, len(config.GetChangeHistory())) + certType, _ := config.Get("certificate/type") + assert.Equal(t, "self-signed", certType.String()) + cert, _ := config.Get("certificate/server.crt") + assert.Equal(t, "cert", cert.String()) + key, _ := config.Get("certificate/server.key") + assert.Equal(t, "key", key.String()) + + return registryconfig.GlobalConfig{}, nil + }) + writer := NewSSLWriter(globalConfigRepoMock) // when - err := writer.WriteCertificate("self-signed", "cert", "key") + err := writer.WriteCertificate(testCtx, "self-signed", "cert", "key") // then require.NoError(t, err) - mock.AssertExpectationsForObjects(t, globalConfig) }) t.Run("failed to write type", func(t *testing.T) { // given - globalConfig := newMockSetConfigurationContext(t) - globalConfig.EXPECT().Set("certificate/type", "self-signed").Return(assert.AnError) - writer := NewSSLWriter(globalConfig) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "certificate/type/key": "already a dictionary", + }), + } + + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + writer := NewSSLWriter(globalConfigRepoMock) // when - err := writer.WriteCertificate("self-signed", "cert", "key") + err := writer.WriteCertificate(testCtx, "self-signed", "cert", "key") // then require.Error(t, err) assert.Contains(t, err.Error(), "failed to set certificate type") - mock.AssertExpectationsForObjects(t, globalConfig) }) t.Run("failed to write certificate", func(t *testing.T) { // given - globalConfig := newMockSetConfigurationContext(t) - setExpect := globalConfig.EXPECT().Set - setExpect("certificate/type", "self-signed").Return(nil) - setExpect("certificate/server.crt", "cert").Return(assert.AnError) - writer := NewSSLWriter(globalConfig) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "certificate/server.crt/key": "already a dictionary", + }), + } + + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + writer := NewSSLWriter(globalConfigRepoMock) // when - err := writer.WriteCertificate("self-signed", "cert", "key") + err := writer.WriteCertificate(testCtx, "self-signed", "cert", "key") // then require.Error(t, err) assert.Contains(t, err.Error(), "failed to set certificate") - mock.AssertExpectationsForObjects(t, globalConfig) }) t.Run("failed to write certificate key", func(t *testing.T) { // given - globalConfig := newMockSetConfigurationContext(t) - setExpect := globalConfig.EXPECT().Set - setExpect("certificate/type", "self-signed").Return(nil) - setExpect("certificate/server.crt", "cert").Return(nil) - setExpect("certificate/server.key", "key").Return(assert.AnError) - writer := NewSSLWriter(globalConfig) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "certificate/server.key/key": "already a dictionary", + }), + } + + globalConfigRepoMock.EXPECT().Get(testCtx).Return(globalConfig, nil) + writer := NewSSLWriter(globalConfigRepoMock) // when - err := writer.WriteCertificate("self-signed", "cert", "key") + err := writer.WriteCertificate(testCtx, "self-signed", "cert", "key") // then require.Error(t, err) assert.Contains(t, err.Error(), "failed to set certificate key") - mock.AssertExpectationsForObjects(t, globalConfig) }) } diff --git a/controllers/sslCertificateUpdater.go b/controllers/sslCertificateUpdater.go index 83128a8..215f918 100644 --- a/controllers/sslCertificateUpdater.go +++ b/controllers/sslCertificateUpdater.go @@ -3,25 +3,24 @@ package controllers import ( "context" "fmt" + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/cloudogu/k8s-service-discovery/controllers/util" appsv1 "k8s.io/api/apps/v1" - "k8s.io/client-go/util/retry" - "strings" - - "github.com/cloudogu/cesapp-lib/registry" - etcdclient "go.etcd.io/etcd/client/v2" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) const ( - serverCertificatePath = "/config/_global/certificate" - serverCertificateID = "certificate/server.crt" - serverCertificateKeyID = "certificate/server.key" - certificateSecretName = "ecosystem-certificate" + globalServerCertificatePath = "certificate" + serverCertificateID = "certificate/server.crt" + serverCertificateKeyID = "certificate/server.key" + certificateSecretName = "ecosystem-certificate" ) const ( @@ -30,27 +29,19 @@ const ( // sslCertificateUpdater is responsible to update the ssl certificate of the ecosystem. type sslCertificateUpdater struct { - client client.Client - namespace string - registry cesRegistry - eventRecorder eventRecorder -} - -type cesRegistry interface { - registry.Registry -} - -type watchConfigurationContext interface { - registry.WatchConfigurationContext + client client.Client + namespace string + globalConfigRepo GlobalConfigRepository + eventRecorder eventRecorder } // NewSslCertificateUpdater creates a new updater. -func NewSslCertificateUpdater(client client.Client, namespace string, cesRegistry cesRegistry, recorder eventRecorder) *sslCertificateUpdater { +func NewSslCertificateUpdater(client client.Client, namespace string, globalConfigRepo GlobalConfigRepository, recorder eventRecorder) *sslCertificateUpdater { return &sslCertificateUpdater{ - client: client, - namespace: namespace, - registry: cesRegistry, - eventRecorder: recorder, + client: client, + namespace: namespace, + globalConfigRepo: globalConfigRepo, + eventRecorder: recorder, } } @@ -58,28 +49,45 @@ func NewSslCertificateUpdater(client client.Client, namespace string, cesRegistr func (scu *sslCertificateUpdater) Start(ctx context.Context) error { logger := ctrl.LoggerFrom(ctx) logger.Info("Starting ssl updater...") - return scu.startEtcdWatch(ctx, scu.registry.RootConfig()) + return scu.startGlobalConfigWatch(ctx) } -func (scu *sslCertificateUpdater) startEtcdWatch(ctx context.Context, reg watchConfigurationContext) error { - ctrl.LoggerFrom(ctx).Info("Start etcd watcher on certificate keys") +func (scu *sslCertificateUpdater) startGlobalConfigWatch(ctx context.Context) error { + ctrl.LoggerFrom(ctx).Info("Start global config watcher on certificate keys") + + sslWatchChannel, err := scu.globalConfigRepo.Watch(ctx, config.DirectoryFilter(globalServerCertificatePath)) + if err != nil { + return fmt.Errorf("failed to create ssl watch: %w", err) + } - sslChannel := make(chan *etcdclient.Response) go func() { - ctrl.LoggerFrom(ctx).Info("start etcd watcher for ssl certificates") - reg.Watch(ctx, serverCertificatePath, true, sslChannel) - ctrl.LoggerFrom(ctx).Info("stop etcd watcher for ssl certificates") + ctrl.LoggerFrom(ctx).Info("start global config watcher for ssl certificates") + scu.startSSLWatch(ctx, sslWatchChannel) + ctrl.LoggerFrom(ctx).Info("stop global config watcher for ssl certificates") }() + return nil +} + +func (scu *sslCertificateUpdater) startSSLWatch(ctx context.Context, sslWatchChannel <-chan repository.GlobalConfigWatchResult) { for { select { case <-ctx.Done(): - return nil - case <-sslChannel: - ctrl.Log.Info(fmt.Sprintf("Context: [%+v]", ctx)) + ctrl.LoggerFrom(ctx).Info("context done - stop global config watcher for ssl certificate changes") + return + case result, open := <-sslWatchChannel: + if !open { + ctrl.LoggerFrom(ctx).Info("ssl watch channel canceled - stop watch") + return + } + if result.Err != nil { + ctrl.LoggerFrom(ctx).Error(result.Err, "ssl watch channel error") + continue + } + err := scu.handleSslChange(ctx) if err != nil { - return err + ctrl.LoggerFrom(ctx).Error(err, "failed to handle ssl update") } } } @@ -88,13 +96,9 @@ func (scu *sslCertificateUpdater) startEtcdWatch(ctx context.Context, reg watchC func (scu *sslCertificateUpdater) handleSslChange(ctx context.Context) error { ctrl.LoggerFrom(ctx).Info("Certificate key changed in registry. Refresh ssl certificate secret...") - cert, key, err := scu.readCertificateFromRegistry() - if err != nil && isEtcdKeyNotFoundError(err) { - message := fmt.Sprintf("The etcd keys [%s/server.crt] and [%s/server.key] are required but not set in the etcd.", serverCertificatePath, serverCertificatePath) - ctrl.LoggerFrom(ctx).Error(fmt.Errorf("%w", err), fmt.Sprintf("%s %s", message, "Writing an event...")) - return nil - } else if err != nil { - return err + cert, key, err := scu.readCertificateFromRegistry(ctx) + if err != nil { + return fmt.Errorf("failed to read certificate: %w", err) } deployment := &appsv1.Deployment{} @@ -141,18 +145,23 @@ func (scu *sslCertificateUpdater) handleSslChange(ctx context.Context) error { return nil } -func (scu *sslCertificateUpdater) readCertificateFromRegistry() (string, string, error) { - cert, err := scu.registry.GlobalConfig().Get(serverCertificateID) +func (scu *sslCertificateUpdater) readCertificateFromRegistry(ctx context.Context) (string, string, error) { + globalConfig, err := scu.globalConfigRepo.Get(ctx) if err != nil { - return "", "", fmt.Errorf("failed to read the ssl certificate from the registry: %w", err) + return "", "", fmt.Errorf("failed to get global config for ssl read: %w", err) } - key, err := scu.registry.GlobalConfig().Get(serverCertificateKeyID) - if err != nil { - return "", "", fmt.Errorf("failed to read the ssl certificate key from the registry: %w", err) + cert, exists := globalConfig.Get(serverCertificateID) + if !exists || !util.ContainsChars(cert.String()) { + return "", "", fmt.Errorf("%q is empty or doesn't exists", serverCertificateID) + } + + key, exists := globalConfig.Get(serverCertificateKeyID) + if !exists || !util.ContainsChars(key.String()) { + return "", "", fmt.Errorf("%q is empty or doesn't exists", serverCertificateKeyID) } - return cert, key, nil + return cert.String(), key.String(), nil } func (scu *sslCertificateUpdater) getSslSecret(ctx context.Context) (*v1.Secret, bool, error) { @@ -193,7 +202,3 @@ func (scu *sslCertificateUpdater) createSslSecret(ctx context.Context, cert stri return nil } - -func isEtcdKeyNotFoundError(err error) bool { - return strings.Contains(err.Error(), "Key not found") -} diff --git a/controllers/sslCertificateUpdater_test.go b/controllers/sslCertificateUpdater_test.go index 3d38781..7dcbb01 100644 --- a/controllers/sslCertificateUpdater_test.go +++ b/controllers/sslCertificateUpdater_test.go @@ -2,30 +2,23 @@ package controllers import ( "context" - "fmt" doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" "github.com/stretchr/testify/assert" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - - etcdclient "go.etcd.io/etcd/client/v2" - "github.com/stretchr/testify/mock" - - "github.com/cloudogu/cesapp-lib/registry/mocks" "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" testclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + "testing" + "time" ) func getScheme() *runtime.Scheme { @@ -40,12 +33,31 @@ func getScheme() *runtime.Scheme { } func Test_sslCertificateUpdater_Start(t *testing.T) { + t.Run("should return error on error creating watch", func(t *testing.T) { + // given + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfigRepoMock.EXPECT().Watch(testCtx, mock.Anything).Return(nil, assert.AnError) + + namespace := "myTestNamespace" + sslUpdater := &sslCertificateUpdater{ + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + } + + // when + err := sslUpdater.Start(testCtx) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "failed to create ssl watch") + }) + t.Run("run start without change and send done to context", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - regMock.EXPECT().RootConfig().Return(watchContextMock) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/certificate", true, mock.Anything).Return() + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*50) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) recorderMock := newMockEventRecorder(t) @@ -53,14 +65,12 @@ func Test_sslCertificateUpdater_Start(t *testing.T) { deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + eventRecorder: recorderMock, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond*50) - // when err := sslUpdater.Start(ctx) cancelFunc() @@ -69,42 +79,99 @@ func Test_sslCertificateUpdater_Start(t *testing.T) { require.NoError(t, err) }) - t.Run("run start and send change event", func(t *testing.T) { + t.Run("run start with change error and send done to context", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/certificate", true, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("mykey", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) recorderMock := newMockEventRecorder(t) - recorderMock.On("Event", mock.IsType(&appsv1.Deployment{}), "Normal", "Certificate", "SSL secret created.") namespace := "myTestNamespace" deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + eventRecorder: recorderMock, } + // when + err := sslUpdater.Start(ctx) + + resultChannel <- repository.GlobalConfigWatchResult{ + Err: assert.AnError, + } + cancelFunc() + + // then + require.NoError(t, err) + }) + + t.Run("run start and close channel", func(t *testing.T) { + // given ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + + recorderMock := newMockEventRecorder(t) + + namespace := "myTestNamespace" + deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() + sslUpdater := &sslCertificateUpdater{ + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + eventRecorder: recorderMock, + } // when err := sslUpdater.Start(ctx) + + close(resultChannel) cancelFunc() // then require.NoError(t, err) + }) + + t.Run("run start and send change event", func(t *testing.T) { + // given + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "mycert", + "certificate/server.key": "mykey", + }) + globalConfigRepoMock.EXPECT().Get(ctx).Return(globalConfig, nil) + + recorderMock := newMockEventRecorder(t) + recorderMock.On("Event", mock.IsType(&appsv1.Deployment{}), "Normal", "Certificate", "SSL secret created.") + + namespace := "myTestNamespace" + deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() + sslUpdater := &sslCertificateUpdater{ + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, + eventRecorder: recorderMock, + } + + // when + err := sslUpdater.Start(ctx) + resultChannel <- repository.GlobalConfigWatchResult{} + timer := time.NewTimer(time.Second * 2) + <-timer.C + + // then + require.NoError(t, err) sslSecret := &v1.Secret{} objectKey := types.NamespacedName{Namespace: namespace, Name: certificateSecretName} @@ -113,55 +180,50 @@ func Test_sslCertificateUpdater_Start(t *testing.T) { assert.Equal(t, "mycert", sslSecret.StringData[v1.TLSCertKey]) assert.Equal(t, "mykey", sslSecret.StringData[v1.TLSPrivateKeyKey]) + cancelFunc() }) t.Run("run start and get error on ssl change method", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - watchContextMock := newMockWatchConfigurationContext(t) - watchContextMock.EXPECT().Watch(mock.Anything, "/config/_global/certificate", true, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - testResponse := &etcdclient.Response{} - eventChannel <- testResponse - }).Return() - regMock.EXPECT().RootConfig().Return(watchContextMock) - - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("", assert.AnError) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(ctx, mock.Anything).Return(resultChannel, nil) + globalConfig := config.CreateGlobalConfig(config.Entries{}) + globalConfigRepoMock.EXPECT().Get(ctx).Return(globalConfig, assert.AnError) clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() namespace := "myTestNamespace" sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: globalConfigRepoMock, } - ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2) - // when err := sslUpdater.Start(ctx) - cancelFunc() + resultChannel <- repository.GlobalConfigWatchResult{} + timer := time.NewTimer(time.Second * 2) + <-timer.C // then - require.Error(t, err, assert.AnError) + require.NoError(t, err) + cancelFunc() }) } func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { - t.Run("error on retrieving server cert", func(t *testing.T) { + t.Run("error on getting global config", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("", assert.AnError) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(config.GlobalConfig{}, assert.AnError) clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() namespace := "myTestNamespace" sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, } // when @@ -169,22 +231,20 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { // then require.Error(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to get global config for ssl read") }) - t.Run("error on retrieving server key", func(t *testing.T) { + t.Run("error on retrieving server cert (key not found)", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("", assert.AnError) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(config.GlobalConfig{}, nil) clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() namespace := "myTestNamespace" sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, } // when @@ -192,45 +252,97 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { // then require.Error(t, err, assert.AnError) + assert.ErrorContains(t, err, "\"certificate/server.crt\" is empty or doesn't exists") }) - t.Run("key not found on retrieving server key result in no error", func(t *testing.T) { + t.Run("error on retrieving server cert (value is empty)", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("", fmt.Errorf("error: Key not found")) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() namespace := "myTestNamespace" sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, } // when err := sslUpdater.handleSslChange(context.Background()) // then - require.NoError(t, err) + require.Error(t, err, assert.AnError) + assert.ErrorContains(t, err, "\"certificate/server.crt\" is empty or doesn't exists") + }) + + t.Run("error on retrieving server key (key not found)", func(t *testing.T) { + // given + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "cert", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() + namespace := "myTestNamespace" + sslUpdater := &sslCertificateUpdater{ + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + } + + // when + err := sslUpdater.handleSslChange(context.Background()) + + // then + require.Error(t, err, assert.AnError) + assert.ErrorContains(t, err, "\"certificate/server.key\" is empty or doesn't exists") + }) + + t.Run("error on retrieving server key (value is empty)", func(t *testing.T) { + // given + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "cert", + "certificate/server.key": "", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() + namespace := "myTestNamespace" + sslUpdater := &sslCertificateUpdater{ + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + } + + // when + err := sslUpdater.handleSslChange(context.Background()) + + // then + require.Error(t, err, assert.AnError) + assert.ErrorContains(t, err, "\"certificate/server.key\" is empty or doesn't exists") }) t.Run("should return error if the deployment does not exist", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("mykey", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "cert", + "certificate/server.key": "key", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).Build() namespace := "myTestNamespace" sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, } // when @@ -243,11 +355,12 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { t.Run("successfully handle ssl change with existing ssl secret", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("mykey", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "cert", + "certificate/server.key": "key", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) recorderMock := newMockEventRecorder(t) recorderMock.On("Event", mock.IsType(&appsv1.Deployment{}), "Normal", "Certificate", "SSL secret changed.") @@ -268,10 +381,10 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment, initialSslSecret).Build() sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: recorderMock, } // when @@ -285,17 +398,18 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { err = clientMock.Get(context.Background(), objectKey, sslSecret) require.NoError(t, err) - assert.Equal(t, "mycert", sslSecret.StringData[v1.TLSCertKey]) - assert.Equal(t, "mykey", sslSecret.StringData[v1.TLSPrivateKeyKey]) + assert.Equal(t, "cert", sslSecret.StringData[v1.TLSCertKey]) + assert.Equal(t, "key", sslSecret.StringData[v1.TLSPrivateKeyKey]) }) t.Run("successfully handle ssl change", func(t *testing.T) { // given - regMock := newMockCesRegistry(t) - globalConfigMock := mocks.NewConfigurationContext(t) - globalConfigMock.On("Get", "certificate/server.crt").Return("mycert", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("mykey", nil) - regMock.On("GlobalConfig").Return(globalConfigMock, nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "cert", + "certificate/server.key": "key", + }) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) recorderMock := newMockEventRecorder(t) recorderMock.On("Event", mock.IsType(&appsv1.Deployment{}), "Normal", "Certificate", "SSL secret created.") @@ -304,10 +418,10 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} clientMock := testclient.NewClientBuilder().WithScheme(getScheme()).WithObjects(deployment).Build() sslUpdater := &sslCertificateUpdater{ - client: clientMock, - namespace: namespace, - registry: regMock, - eventRecorder: recorderMock, + client: clientMock, + namespace: namespace, + globalConfigRepo: mockGlobalConfigRepo, + eventRecorder: recorderMock, } // when @@ -321,8 +435,8 @@ func Test_sslCertificateUpdater_handleSslChange(t *testing.T) { err = clientMock.Get(context.Background(), objectKey, sslSecret) require.NoError(t, err) - assert.Equal(t, "mycert", sslSecret.StringData[v1.TLSCertKey]) - assert.Equal(t, "mykey", sslSecret.StringData[v1.TLSPrivateKeyKey]) + assert.Equal(t, "cert", sslSecret.StringData[v1.TLSCertKey]) + assert.Equal(t, "key", sslSecret.StringData[v1.TLSPrivateKeyKey]) }) } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 799ff5a..da76223 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -6,10 +6,10 @@ package controllers import ( "context" "fmt" - cesmocks "github.com/cloudogu/cesapp-lib/registry/mocks" doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1" + "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/repository" "github.com/stretchr/testify/mock" - etcdclient "go.etcd.io/etcd/client/v2" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +46,9 @@ var stage string const myNamespace = "my-test-namespace" const myIngressClassName = "my-ingress-class-name" -var SSLChannel chan *etcdclient.Response +var ( + SSLChannel chan repository.GlobalConfigWatchResult +) func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) @@ -94,15 +96,18 @@ var _ = BeforeSuite(func() { }) Expect(err).ToNot(HaveOccurred()) - myRegistry := &cesmocks.Registry{} - globalConfigMock := &cesmocks.ConfigurationContext{} - keyNotFoundErr := etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound} - globalConfigMock.On("Get", "maintenance").Return("", keyNotFoundErr) - myRegistry.On("GlobalConfig").Return(globalConfigMock, nil) - eventRecorder := k8sManager.GetEventRecorderFor("k8s-service-discovery-controller-manager") - ingressCreator, err := NewIngressUpdater(k8sManager.GetClient(), globalConfigMock, myNamespace, myIngressClassName, eventRecorder) + t := &testing.T{} + globalConfig := config.CreateGlobalConfig(config.Entries{ + "certificate/server.crt": "mycert", + "certificate/server.key": "mykey", + "certificate/type": "selfsigned", + }) + globalConfigRepoMock := NewMockGlobalConfigRepository(t) + globalConfigRepoMock.EXPECT().Get(mock.Anything).Return(globalConfig, nil) + + ingressCreator, err := NewIngressUpdater(k8sManager.GetClient(), globalConfigRepoMock, myNamespace, myIngressClassName, eventRecorder) Expect(err).ToNot(HaveOccurred()) serviceReconciler := &serviceReconciler{ @@ -124,18 +129,9 @@ var _ = BeforeSuite(func() { err = k8sManager.Add(ingressClassCreator) Expect(err).ToNot(HaveOccurred()) - watchRegistry := &cesmocks.WatchConfigurationContext{} - myRegistry.On("RootConfig").Return(watchRegistry) - - globalConfigMock.On("Get", "certificate/server.crt").Return("mycrt", nil) - globalConfigMock.On("Get", "certificate/server.key").Return("mykey", nil) - - // create ssl updater class - watchRegistry.On("Watch", mock.Anything, "/config/_global/certificate", true, mock.Anything).Run(func(args mock.Arguments) { - SSLChannel = args.Get(3).(chan *etcdclient.Response) - }) - - sslUpdater := NewSslCertificateUpdater(k8sManager.GetClient(), myNamespace, myRegistry, eventRecorder) + SSLChannel = make(chan repository.GlobalConfigWatchResult) + globalConfigRepoMock.EXPECT().Watch(mock.Anything, mock.Anything).Return(SSLChannel, nil) + sslUpdater := NewSslCertificateUpdater(k8sManager.GetClient(), myNamespace, globalConfigRepoMock, eventRecorder) err = k8sManager.Add(sslUpdater) Expect(err).ToNot(HaveOccurred()) @@ -144,20 +140,6 @@ var _ = BeforeSuite(func() { err = os.Unsetenv("STAGE") Expect(err).NotTo(HaveOccurred()) - watchRegistry.On("Watch", mock.Anything, "/dogu", mock.Anything, mock.Anything) - watchRegistry.On("Watch", mock.Anything, "/config/nginx/externals", mock.Anything, mock.Anything) - watchRegistry.On("Watch", mock.Anything, "/config/_global/disabled_warpmenu_support_entries", mock.Anything, mock.Anything) - - warpMenuCreator := NewWarpMenuCreator(k8sManager.GetClient(), myRegistry, myNamespace, eventRecorder) - err = k8sManager.Add(warpMenuCreator) - Expect(err).ToNot(HaveOccurred()) - - // create maintenance updater - maintenanceUpdater, err := NewMaintenanceModeUpdater(k8sManager.GetClient(), myNamespace, ingressCreator, eventRecorder) - Expect(err).ToNot(HaveOccurred()) - err = k8sManager.Add(maintenanceUpdater) - Expect(err).ToNot(HaveOccurred()) - createInitialTestData(k8sManager.GetClient()) go func() { defer GinkgoRecover() diff --git a/controllers/util/util.go b/controllers/util/util.go new file mode 100644 index 0000000..2fdae1b --- /dev/null +++ b/controllers/util/util.go @@ -0,0 +1,7 @@ +package util + +import "strings" + +func ContainsChars(s string) bool { + return len(strings.TrimSpace(s)) != 0 +} diff --git a/controllers/warp/configReader.go b/controllers/warp/configReader.go index 6adfd62..c10d490 100644 --- a/controllers/warp/configReader.go +++ b/controllers/warp/configReader.go @@ -1,9 +1,14 @@ package warp import ( + "context" "encoding/json" "fmt" + libconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-service-discovery/controllers/util" "sort" + "strconv" + "strings" "github.com/cloudogu/k8s-service-discovery/controllers/config" "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" @@ -12,37 +17,31 @@ import ( "github.com/pkg/errors" ) -// ConfigReader reads the configuration for the warp menu from etcd +// ConfigReader reads the configuration for the warp menu from the global configuration type ConfigReader struct { - configuration *config.Configuration - registry watchConfigurationContext - doguConverter DoguConverter - externalConverter ExternalConverter + configuration *config.Configuration + globalConfigRepo GlobalConfigRepository + doguVersionRegistry DoguVersionRegistry + localDoguRepo LocalDoguRepo + doguConverter DoguConverter + externalConverter ExternalConverter } -// DoguConverter is used to Read dogus from the registry and convert them to objects fitting in the warp menu -type DoguConverter interface { - ReadAndUnmarshalDogu(registry types.WatchConfigurationContext, key string, tag string) (types.EntryWithCategory, error) -} - -// ExternalConverter is used to Read external links from the registry and convert them to objects fitting in the warp menu -type ExternalConverter interface { - ReadAndUnmarshalExternal(registry types.WatchConfigurationContext, key string) (types.EntryWithCategory, error) -} - -const disableWarpSupportEntriesConfigurationKey = "/config/_global/disabled_warpmenu_support_entries" +const globalBlockWarpSupportCategoryConfigurationKey = "block_warpmenu_support_category" +const globalDisabledWarpSupportEntriesConfigurationKey = "disabled_warpmenu_support_entries" +const globalAllowedWarpSupportEntriesConfigurationKey = "allowed_warpmenu_support_entries" // Read reads sources specified in a configuration and build warp menu categories for them. -func (reader *ConfigReader) Read(configuration *config.Configuration) (types.Categories, error) { +func (reader *ConfigReader) Read(ctx context.Context, configuration *config.Configuration) (types.Categories, error) { var data types.Categories for _, source := range configuration.Sources { // Disabled support entries refresh every time - if source.Type == "disabled_support_entries" { + if source.Type == "support_entry_config" { continue } - categories, err := reader.readSource(source) + categories, err := reader.readSource(ctx, source) if err != nil { ctrl.Log.Info(fmt.Sprintf("Error during Read: %s", err.Error())) } @@ -50,89 +49,174 @@ func (reader *ConfigReader) Read(configuration *config.Configuration) (types.Cat } ctrl.Log.Info("Read SupportEntries") - disabledSupportEntries, err := reader.getDisabledSupportIdentifiers() + + readKeyErrorFmt := "Warning, could not read Key: %v. Err: %v" + + isSupportCategoryBlocked, err := reader.readBool(ctx, globalBlockWarpSupportCategoryConfigurationKey) if err != nil { - ctrl.Log.Info(fmt.Sprintf("Error during support Read: %s", err.Error())) + ctrl.Log.Info(fmt.Sprintf(readKeyErrorFmt, globalBlockWarpSupportCategoryConfigurationKey, err)) } - supportCategory := reader.readSupport(configuration.Support, disabledSupportEntries) + + disabledSupportEntries, err := reader.readStrings(ctx, globalDisabledWarpSupportEntriesConfigurationKey) + if err != nil { + ctrl.Log.Info(fmt.Sprintf(readKeyErrorFmt, globalDisabledWarpSupportEntriesConfigurationKey, err)) + } + + allowedSupportEntries, err := reader.readStrings(ctx, globalAllowedWarpSupportEntriesConfigurationKey) + if err != nil { + ctrl.Log.Info(fmt.Sprintf(readKeyErrorFmt, globalAllowedWarpSupportEntriesConfigurationKey, err)) + } + + supportCategory := reader.readSupport(configuration.Support, isSupportCategoryBlocked, disabledSupportEntries, allowedSupportEntries) data.InsertCategories(supportCategory) return data, nil } -func (reader *ConfigReader) readSource(source config.Source) (types.Categories, error) { +func (reader *ConfigReader) readSource(ctx context.Context, source config.Source) (types.Categories, error) { switch source.Type { case "dogus": - return reader.dogusReader(source) + return reader.dogusReader(ctx, source) case "externals": - return reader.externalsReader(source) + return reader.externalsReader(ctx, source) } return nil, errors.Errorf("wrong source type: %v", source.Type) } -func (reader *ConfigReader) externalsReader(source config.Source) (types.Categories, error) { - ctrl.Log.Info(fmt.Sprintf("Read externals from %s for warp menu", source.Path)) - resp, err := reader.registry.GetChildrenPaths(source.Path) +func (reader *ConfigReader) externalsReader(ctx context.Context, source config.Source) (types.Categories, error) { + ctrl.Log.Info(fmt.Sprintf("Read externals from %s for warp menu in global config", source.Path)) + children, err := reader.readGlobalConfigDir(ctx, removeLegacyGlobalConfigPrefix(source.Path)) if err != nil { - return nil, fmt.Errorf("failed to Read root entry %s from etcd: %w", source.Path, err) + return nil, fmt.Errorf("failed to read root entry %s from config: %w", source.Path, err) } var externals []types.EntryWithCategory - for _, child := range resp { - external, err := reader.externalConverter.ReadAndUnmarshalExternal(reader.registry, child) - if err == nil { - externals = append(externals, external) + for _, value := range children { + external, unmarshalErr := reader.externalConverter.ReadAndUnmarshalExternal(value) + if unmarshalErr != nil { + ctrl.Log.Error(unmarshalErr, fmt.Sprintf("failed to read and unmarshal external link key %q", value)) + continue } + externals = append(externals, external) } return reader.createCategories(externals), nil } -// dogusReader reads from etcd and converts the keys and values to a warp menu +func (reader *ConfigReader) readGlobalConfigDir(ctx context.Context, key string) (map[string]string, error) { + globalConfig, err := reader.getGlobalConfig(ctx) + if err != nil { + return nil, err + } + + entries := globalConfig.GetAll() + children := make(map[string]string, len(entries)) + for entryKey, entryValue := range entries { + if strings.HasPrefix(entryKey.String(), key) && entryKey.String() != key { + children[entryKey.String()] = entryValue.String() + } + } + + return children, nil +} + +// dogusReader reads from dogu repository and converts the keys and values to a warp menu // conform structure -func (reader *ConfigReader) dogusReader(source config.Source) (types.Categories, error) { +func (reader *ConfigReader) dogusReader(ctx context.Context, source config.Source) (types.Categories, error) { ctrl.Log.Info(fmt.Sprintf("Read dogus from %s for warp menu", source.Path)) - resp, err := reader.registry.GetChildrenPaths(source.Path) + allCurrentDoguVersions, err := reader.doguVersionRegistry.GetCurrentOfAll(ctx) if err != nil { - return nil, fmt.Errorf("failed to Read root entry %s from etcd: %w", source.Path, err) + return nil, fmt.Errorf("failed to get all current dogu versions: %w", err) + } + + if len(allCurrentDoguVersions) == 0 { + return []*types.Category{}, nil } - var dogus []types.EntryWithCategory - for _, path := range resp { - dogu, err := reader.doguConverter.ReadAndUnmarshalDogu(reader.registry, path, source.Tag) - if err == nil && dogu.Entry.Title != "" { - dogus = append(dogus, dogu) + + allCurrentDogus, err := reader.localDoguRepo.GetAll(ctx, allCurrentDoguVersions) + if err != nil { + return nil, fmt.Errorf("failed to get all dogu specs with current versions: %w", err) + } + + var doguCategories []types.EntryWithCategory + for _, currentDogu := range allCurrentDogus { + doguCategory, err := reader.doguConverter.CreateEntryWithCategoryFromDogu(currentDogu, source.Tag) + if err == nil && doguCategory.Entry.Title != "" { + ctrl.Log.Info(fmt.Sprintf("Add dogu %s with category %s", currentDogu.GetSimpleName(), doguCategory.Category)) + doguCategories = append(doguCategories, doguCategory) } } - return reader.createCategories(dogus), nil + return reader.createCategories(doguCategories), nil } -func (reader *ConfigReader) getDisabledSupportIdentifiers() ([]string, error) { - disabledSupportEntries, err := reader.registry.Get(disableWarpSupportEntriesConfigurationKey) +func (reader *ConfigReader) readStrings(ctx context.Context, registryKey string) ([]string, error) { + globalConfig, err := reader.getGlobalConfig(ctx) + if err != nil { + return nil, err + } + + entry, exists := globalConfig.Get(libconfig.Key(registryKey)) + if !exists || !util.ContainsChars(entry.String()) { + return []string{}, nil + } + + var stringSlice []string + err = json.Unmarshal([]byte(entry.String()), &stringSlice) if err != nil { - return []string{}, fmt.Errorf("failed to Read configuration entry %s from etcd: %w", disableWarpSupportEntriesConfigurationKey, err) + return []string{}, fmt.Errorf("failed to unmarshal global config key to string slice: %w", err) } - var disabledEntries []string - err = json.Unmarshal([]byte(disabledSupportEntries), &disabledEntries) + return stringSlice, nil +} + +func removeLegacyGlobalConfigPrefix(key string) string { + if strings.HasPrefix(key, "config/_global") || strings.HasPrefix(key, "/config/_global") { + _, after, _ := strings.Cut(key, "config/_global/") + return after + } + + return key +} + +func (reader *ConfigReader) getGlobalConfig(ctx context.Context) (libconfig.GlobalConfig, error) { + globalConfig, err := reader.globalConfigRepo.Get(ctx) if err != nil { - return []string{}, fmt.Errorf("failed to unmarshal etcd key: %w", err) + return libconfig.GlobalConfig{}, fmt.Errorf("failed to get global config: %w", err) } - return disabledEntries, nil + return globalConfig, nil } -func (reader *ConfigReader) readSupport(supportSources []config.SupportSource, disabledSupportEntries []string) types.Categories { +func (reader *ConfigReader) readBool(ctx context.Context, registryKey string) (bool, error) { + globalConfig, err := reader.getGlobalConfig(ctx) + if err != nil { + return false, err + } + + entry, exists := globalConfig.Get(libconfig.Key(registryKey)) + if !exists || !util.ContainsChars(entry.String()) { + return false, nil + } + + boolValue, err := strconv.ParseBool(entry.String()) + if err != nil { + return false, fmt.Errorf("failed to unmarshal value %q to bool: %w", entry, err) + } + + return boolValue, nil +} + +func (reader *ConfigReader) readSupport(supportSources []config.SupportSource, blocked bool, disabledEntries []string, allowedEntries []string) types.Categories { var supportEntries []types.EntryWithCategory for _, supportSource := range supportSources { - // supportSource -> EntryWithCategory - if !StringInSlice(supportSource.Identifier, disabledSupportEntries) { - var entry types.Entry + if (blocked && StringInSlice(supportSource.Identifier, allowedEntries)) || (!blocked && !StringInSlice(supportSource.Identifier, disabledEntries)) { + // support category is blocked, but this entry is explicitly allowed OR support category is NOT blocked and this entry is NOT explicitly disabled + + entry := types.Entry{Title: supportSource.Identifier, Href: supportSource.Href, Target: types.TARGET_SELF} if supportSource.External { - entry = types.Entry{Title: supportSource.Identifier, Href: supportSource.Href, Target: types.TARGET_EXTERNAL} - } else { - entry = types.Entry{Title: supportSource.Identifier, Href: supportSource.Href, Target: types.TARGET_SELF} + entry.Target = types.TARGET_EXTERNAL } - entryWithCategory := types.EntryWithCategory{Entry: entry, Category: "Support"} - supportEntries = append(supportEntries, entryWithCategory) + + supportEntries = append(supportEntries, types.EntryWithCategory{Entry: entry, Category: "Support"}) } } diff --git a/controllers/warp/configReader_test.go b/controllers/warp/configReader_test.go index e2f7385..1c738e4 100644 --- a/controllers/warp/configReader_test.go +++ b/controllers/warp/configReader_test.go @@ -1,6 +1,11 @@ package warp import ( + "context" + _ "embed" + "github.com/cloudogu/cesapp-lib/core" + registryconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/dogu" "github.com/cloudogu/k8s-service-discovery/controllers/config" "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" "github.com/stretchr/testify/assert" @@ -9,250 +14,420 @@ import ( "testing" ) +var testCtx = context.Background() + +//go:embed testdata/redmine.json +var redmineBytes []byte + +//go:embed testdata/jenkins.json +var jenkinsBytes []byte + func TestConfigReader_readSupport(t *testing.T) { supportSources := []config.SupportSource{{Identifier: "aboutCloudoguToken", External: false, Href: "/local/href"}, {Identifier: "myCloudogu", External: true, Href: "https://ecosystem.cloudogu.com/"}, {Identifier: "docsCloudoguComUrl", External: true, Href: "https://docs.cloudogu.com/"}} reader := &ConfigReader{ configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: nil, } - t.Run("success with one disabled entry", func(t *testing.T) { - // given - expectedCategories := types.Categories{{Title: "Support", Entries: []types.Entry{ - {Title: "aboutCloudoguToken", Target: types.TARGET_SELF, Href: "/local/href"}, - {Title: "myCloudogu", Target: types.TARGET_EXTERNAL, Href: "https://ecosystem.cloudogu.com/"}}}} - // when - actual := reader.readSupport(supportSources, []string{"docsCloudoguComUrl"}) + t.Run("should successfully read support entries without filters", func(t *testing.T) { + actual := reader.readSupport(supportSources, false, []string{}, []string{}) - // then - assert.Equal(t, expectedCategories, actual, "readSupport did not return the correct Category of two entries") - }) - - t.Run("success with empty filter", func(t *testing.T) { - // given expectedCategories := types.Categories{ {Title: "Support", Entries: []types.Entry{ {Title: "aboutCloudoguToken", Target: types.TARGET_SELF, Href: "/local/href"}, {Title: "myCloudogu", Target: types.TARGET_EXTERNAL, Href: "https://ecosystem.cloudogu.com/"}, - {Title: "docsCloudoguComUrl", Target: types.TARGET_EXTERNAL, Href: "https://docs.cloudogu.com/"}}}} + {Title: "docsCloudoguComUrl", Target: types.TARGET_EXTERNAL, Href: "https://docs.cloudogu.com/"}, + }}} + assert.Equal(t, expectedCategories, actual) + }) - // when - actual := reader.readSupport(supportSources, []string{}) + t.Run("should block all entries", func(t *testing.T) { + actual := reader.readSupport(supportSources, true, []string{}, []string{}) - // then + expectedCategories := types.Categories{} assert.Equal(t, expectedCategories, actual) }) - t.Run("success with complete filter", func(t *testing.T) { - // given - expectedCategories := types.Categories{} + t.Run("should add allowed entries when blocked", func(t *testing.T) { + actual := reader.readSupport(supportSources, true, []string{}, []string{"myCloudogu"}) - // when - actual := reader.readSupport(supportSources, []string{"myCloudogu", "aboutCloudoguToken", "docsCloudoguComUrl"}) + expectedCategories := types.Categories{ + {Title: "Support", Entries: []types.Entry{ + {Title: "myCloudogu", Target: types.TARGET_EXTERNAL, Href: "https://ecosystem.cloudogu.com/"}, + }}} + assert.Equal(t, expectedCategories, actual) + }) - // then - assert.Equal(t, 0, expectedCategories.Len()) - assert.Equal(t, expectedCategories, actual, "readSupport did not return the correct Category of three entries") + t.Run("should remove disabled entries when not blocked", func(t *testing.T) { + actual := reader.readSupport(supportSources, false, []string{"aboutCloudoguToken", "docsCloudoguComUrl"}, []string{}) + + expectedCategories := types.Categories{ + {Title: "Support", Entries: []types.Entry{ + {Title: "myCloudogu", Target: types.TARGET_EXTERNAL, Href: "https://ecosystem.cloudogu.com/"}, + }}} + assert.Equal(t, expectedCategories, actual) + }) + + t.Run("should remove disabled entries when not blocked", func(t *testing.T) { + actual := reader.readSupport(supportSources, false, []string{"aboutCloudoguToken", "docsCloudoguComUrl"}, []string{}) + + expectedCategories := types.Categories{ + {Title: "Support", Entries: []types.Entry{ + {Title: "myCloudogu", Target: types.TARGET_EXTERNAL, Href: "https://ecosystem.cloudogu.com/"}, + }}} + assert.Equal(t, expectedCategories, actual) }) } +func TestConfigReader_readStrings(t *testing.T) { + t.Run("should successfully read strings", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "disabled_warpmenu_support_entries": "[\"lorem\",\"ipsum\"]", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) -func TestConfigReader_getDisabledSupportIdentifiers(t *testing.T) { - t.Run("success", func(t *testing.T) { - // given - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("[\"lorem\", \"ipsum\"]", nil) reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, } - // when - identifiers, err := reader.getDisabledSupportIdentifiers() - - // then - assert.Empty(t, err) + identifiers, err := reader.readStrings(testCtx, "disabled_warpmenu_support_entries") + require.NoError(t, err) assert.Equal(t, []string{"lorem", "ipsum"}, identifiers) - mock.AssertExpectationsForObjects(t, mockRegistry) }) - t.Run("failed to get disabled support entries", func(t *testing.T) { - // given - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("", assert.AnError) + t.Run("should fail getting global config", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(registryconfig.GlobalConfig{}, assert.AnError) reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, } - // when - _, err := reader.getDisabledSupportIdentifiers() + _, err := reader.readStrings(testCtx, "disabled_warpmenu_support_entries") + require.Error(t, err) + assert.ErrorIs(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to get global config") + }) - // then + t.Run("should fail unmarshalling", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "disabled_warpmenu_support_entries": "not a string array]", + }), + } + + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + reader := &ConfigReader{ + globalConfigRepo: mockGlobalConfigRepo, + } + + identifiers, err := reader.readStrings(testCtx, "disabled_warpmenu_support_entries") require.Error(t, err) - assert.Contains(t, err.Error(), "failed to Read configuration entry /config/_global/disabled_warpmenu_support_entries from etcd") - mock.AssertExpectationsForObjects(t, mockRegistry) + assert.ErrorContains(t, err, "failed to unmarshal global config key to string slice") + assert.Equal(t, []string{}, identifiers) }) +} + +func TestConfigReader_readBool(t *testing.T) { + t.Run("should successfully read true bool", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "myBool": "true", + }), + } + + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) - t.Run("failed to unmarshal disabled support entries", func(t *testing.T) { - // given - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("{\"lorem\": \"ipsum\"}", nil) reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, } - // when - _, err := reader.getDisabledSupportIdentifiers() + boolValue, err := reader.readBool(testCtx, "myBool") + require.NoError(t, err) + assert.True(t, boolValue) + }) - // then + t.Run("should successfully read false bool", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "myBool": "false", + }), + } + + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + reader := &ConfigReader{ + globalConfigRepo: mockGlobalConfigRepo, + } + + boolValue, err := reader.readBool(testCtx, "myBool") + require.NoError(t, err) + assert.False(t, boolValue) + }) + + t.Run("should fail getting global config", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(registryconfig.GlobalConfig{}, assert.AnError) + + reader := &ConfigReader{ + globalConfigRepo: mockGlobalConfigRepo, + } + + _, err := reader.readBool(testCtx, "myBool") require.Error(t, err) - assert.Contains(t, err.Error(), "failed to unmarshal etcd key") - mock.AssertExpectationsForObjects(t, mockRegistry) + assert.ErrorIs(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to get global config") }) -} + t.Run("should fail unmarshalling", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "myBool": "not a pool", + }), + } + + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + reader := &ConfigReader{ + globalConfigRepo: mockGlobalConfigRepo, + } + + boolValue, err := reader.readBool(testCtx, "myBool") + require.Error(t, err) + assert.ErrorContains(t, err, "failed to unmarshal value \"not a pool\" to bool") + assert.False(t, boolValue) + }) +} func TestConfigReader_readFromConfig(t *testing.T) { - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/path/to/etcd/key").Return([]string{"/path/to/etcd/key"}, nil) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("[\"lorem\", \"ipsum\"]", nil) - testSources := []config.Source{{Path: "/path/to/etcd/key", Type: "externals", Tag: "tag"}, {Path: "/path", Type: "disabled_support_entries"}} - testSupportSoureces := []config.SupportSource{{Identifier: "supportSrc", External: true, Href: "path/to/external"}} - mockDoguConverter := NewMockDoguConverter(t) + + testSources := []config.Source{{Path: "/path/to/external/link", Type: "externals", Tag: "tag"}, {Path: "/path", Type: "support_entry_config"}} + testSupportSources := []config.SupportSource{{Identifier: "supportSrc", External: true, Href: "path/to/external"}} t.Run("success with one external and support link", func(t *testing.T) { // given + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "/path/to/external/link/Cloudogu": "[\"lorem\", \"ipsum\"]", + globalBlockWarpSupportCategoryConfigurationKey: "false", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + mockDoguConverter := NewMockDoguConverter(t) + cloudoguEntryWithCategory := getEntryWithCategory("Cloudogu", "www.cloudogu.com", "Cloudogu", "External", types.TARGET_EXTERNAL) mockExternalConverter := NewMockExternalConverter(t) - mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mockRegistry, mock.Anything).Return(cloudoguEntryWithCategory, nil) + mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mock.Anything).Return(cloudoguEntryWithCategory, nil) reader := &ConfigReader{ configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, doguConverter: mockDoguConverter, externalConverter: mockExternalConverter, } // when - actual, err := reader.Read(&config.Configuration{Sources: testSources, Support: testSupportSoureces}) + actual, err := reader.Read(testCtx, &config.Configuration{Sources: testSources, Support: testSupportSources}) // then assert.Empty(t, err) assert.NotEmpty(t, actual) assert.Equal(t, 2, len(actual)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter, mockExternalConverter) }) t.Run("success with one dogu and support link", func(t *testing.T) { // given + mockDoguConverter := NewMockDoguConverter(t) + mockDoguConverter.EXPECT().CreateEntryWithCategoryFromDogu(readRedmineDogu(t), "warp").Return(types.EntryWithCategory{Entry: types.Entry{DisplayName: "Redmine", Title: "Redmine"}, Category: "Development Apps"}, nil) mockExternalConverter := NewMockExternalConverter(t) doguSource := config.Source{ Path: "/dogu", Type: "dogus", Tag: "warp", } - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths(mock.Anything).Return([]string{}, nil) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("[\"lorem\", \"ipsum\"]", nil) + + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "disabled_warpmenu_support_entries": "[\"lorem\", \"ipsum\"]", + globalBlockWarpSupportCategoryConfigurationKey: "false", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + versionRegistryMock := NewMockDoguVersionRegistry(t) + redmineVersion := parseVersion(t, "5.1.3-1") + redmineDoguVersion := dogu.DoguVersion{Name: "redmine", Version: *redmineVersion} + currentDoguVersions := []dogu.DoguVersion{redmineDoguVersion} + versionRegistryMock.EXPECT().GetCurrentOfAll(testCtx).Return(currentDoguVersions, nil) + doguSpecRepoMock := NewMockLocalDoguRepo(t) + doguSpecRepoMock.EXPECT().GetAll(testCtx, currentDoguVersions).Return(map[dogu.DoguVersion]*core.Dogu{redmineDoguVersion: readRedmineDogu(t)}, nil) + reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, - doguConverter: mockDoguConverter, - externalConverter: mockExternalConverter, + configuration: &config.Configuration{Support: []config.SupportSource{}}, + globalConfigRepo: mockGlobalConfigRepo, + doguConverter: mockDoguConverter, + externalConverter: mockExternalConverter, + doguVersionRegistry: versionRegistryMock, + localDoguRepo: doguSpecRepoMock, } // when - actual, err := reader.Read(&config.Configuration{Sources: []config.Source{doguSource}, Support: testSupportSoureces}) + actual, err := reader.Read(testCtx, &config.Configuration{Sources: []config.Source{doguSource}, Support: testSupportSources}) // then assert.Empty(t, err) assert.NotEmpty(t, actual) - assert.Equal(t, 1, len(actual)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter, mockExternalConverter) + assert.Equal(t, 2, len(actual)) }) t.Run("error during external Read should not result in an error", func(t *testing.T) { // given - mockExternalConverter := NewMockExternalConverter(t) - mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mockRegistry, mock.Anything).Return(types.EntryWithCategory{}, assert.AnError) - reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, - doguConverter: mockDoguConverter, - externalConverter: mockExternalConverter, + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "/path/to/external/link/Cloudogu": "[\"lorem\", \"ipsum\"]", + "disabled_warpmenu_support_entries": "[\"lorem\", \"ipsum\"]", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + globalBlockWarpSupportCategoryConfigurationKey: "false", + }), } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) - // when - actual, err := reader.Read(&config.Configuration{Sources: testSources, Support: testSupportSoureces}) - - // then - assert.Empty(t, err) - assert.NotEmpty(t, actual) - assert.Equal(t, 1, len(actual)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter, mockExternalConverter) - }) + mockDoguConverter := NewMockDoguConverter(t) - t.Run("error during support Read should not result in an error", func(t *testing.T) { - // given - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/path/to/etcd/key").Return([]string{"/path/to/etcd/key"}, nil) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("[\"lorem\", \"ipsum\"]", assert.AnError) mockExternalConverter := NewMockExternalConverter(t) - mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mockRegistry, mock.Anything).Return(types.EntryWithCategory{}, assert.AnError) + mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mock.Anything).Return(types.EntryWithCategory{}, assert.AnError) reader := &ConfigReader{ configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, doguConverter: mockDoguConverter, externalConverter: mockExternalConverter, } // when - actual, err := reader.Read(&config.Configuration{Sources: testSources, Support: testSupportSoureces}) + actual, err := reader.Read(testCtx, &config.Configuration{Sources: testSources, Support: testSupportSources}) // then assert.Empty(t, err) assert.NotEmpty(t, actual) assert.Equal(t, 1, len(actual)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter, mockExternalConverter) }) t.Run("empty support category should not result in an error", func(t *testing.T) { // given - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/path/to/etcd/key").Return([]string{"/path/to/etcd/key"}, nil) - mockRegistry.EXPECT().Get("/config/_global/disabled_warpmenu_support_entries").Return("[]", nil) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "/path/to/external/link/Cloudogu": "[\"lorem\", \"ipsum\"]", + "disabled_warpmenu_support_entries": "[]", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + globalBlockWarpSupportCategoryConfigurationKey: "false", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + mockExternalConverter := NewMockExternalConverter(t) - mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mockRegistry, mock.Anything).Return(types.EntryWithCategory{}, assert.AnError) + mockExternalConverter.EXPECT().ReadAndUnmarshalExternal(mock.Anything).Return(types.EntryWithCategory{}, assert.AnError) + mockDoguConverter := NewMockDoguConverter(t) reader := &ConfigReader{ configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + globalConfigRepo: mockGlobalConfigRepo, doguConverter: mockDoguConverter, externalConverter: mockExternalConverter, } // when - actual, err := reader.Read(&config.Configuration{Sources: testSources, Support: testSupportSoureces}) + actual, err := reader.Read(testCtx, &config.Configuration{Sources: testSources, Support: testSupportSources}) // then assert.Empty(t, err) assert.NotEmpty(t, actual) assert.Equal(t, 1, len(actual)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter, mockExternalConverter) }) t.Run("skip wrong source type", func(t *testing.T) { // given - testSources := []config.Source{{Path: "/path/to/etcd/key", Type: "fjkhsdfjh", Tag: "tag"}} + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "/path/to/external/link/Cloudogu": "[\"lorem\", \"ipsum\"]", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + globalBlockWarpSupportCategoryConfigurationKey: "false", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + testSources := []config.Source{{Path: "/path/to/config/key", Type: "fjkhsdfjh", Tag: "tag"}} reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + configuration: &config.Configuration{Support: []config.SupportSource{}}, + globalConfigRepo: mockGlobalConfigRepo, } // when - _, err := reader.Read(&config.Configuration{Sources: testSources, Support: testSupportSoureces}) + _, err := reader.Read(testCtx, &config.Configuration{Sources: testSources, Support: testSupportSources}) // then require.NoError(t, err) }) + + t.Run("should read categories from config", func(t *testing.T) { + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + globalConfig := registryconfig.GlobalConfig{ + Config: registryconfig.CreateConfig(registryconfig.Entries{ + "externals/ext1": "external", + globalAllowedWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + globalDisabledWarpSupportEntriesConfigurationKey: "[\"lorem\", \"ipsum\"]", + }), + } + mockGlobalConfigRepo.EXPECT().Get(testCtx).Return(globalConfig, nil) + + mockConverter := NewMockExternalConverter(t) + mockConverter.EXPECT().ReadAndUnmarshalExternal("external").Return(types.EntryWithCategory{ + Entry: types.Entry{ + DisplayName: "ext1", + Href: "https://my.url/ext1", + Title: "ext1 Description", + Target: types.TARGET_EXTERNAL, + }, + Category: "Documentation", + }, nil) + + reader := &ConfigReader{ + configuration: &config.Configuration{Support: []config.SupportSource{}}, + globalConfigRepo: mockGlobalConfigRepo, + externalConverter: mockConverter, + } + + testSources := []config.Source{{Path: "externals", Type: "externals", Tag: "tag"}} + testSupportSoureces := []config.SupportSource{{Identifier: "supportSrc", External: true, Href: "https://support.source"}} + + actual, err := reader.Read(testCtx, &config.Configuration{Sources: testSources, Support: testSupportSoureces}) + require.NoError(t, err) + + expectedCategories := types.Categories{ + {Title: "Documentation", Entries: []types.Entry{ + {DisplayName: "ext1", Title: "ext1 Description", Target: types.TARGET_EXTERNAL, Href: "https://my.url/ext1"}, + }}, + {Title: "Support", Entries: []types.Entry{ + {Title: "supportSrc", Target: types.TARGET_EXTERNAL, Href: "https://support.source"}, + }}, + } + assert.Equal(t, expectedCategories, actual) + }) } func TestConfigReader_dogusReader(t *testing.T) { @@ -263,81 +438,92 @@ func TestConfigReader_dogusReader(t *testing.T) { Type: "dogus", Tag: "warp", } - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/dogu").Return([]string{"/dogu/redmine", "/dogu/jenkins"}, nil) redmineEntryWithCategory := getEntryWithCategory("Redmine", "/redmine", "Redmine", "Development Apps", types.TARGET_SELF) jenkinsEntryWithCategory := getEntryWithCategory("Jenkins", "/jenkins", "Jenkins", "Development Apps", types.TARGET_SELF) mockDoguConverter := NewMockDoguConverter(t) - mockDoguConverter.EXPECT().ReadAndUnmarshalDogu(mockRegistry, "/dogu/redmine", "warp").Return(redmineEntryWithCategory, nil) - mockDoguConverter.EXPECT().ReadAndUnmarshalDogu(mockRegistry, "/dogu/jenkins", "warp").Return(jenkinsEntryWithCategory, nil) + mockDoguConverter.EXPECT().CreateEntryWithCategoryFromDogu(readRedmineDogu(t), "warp").Return(redmineEntryWithCategory, nil) + mockDoguConverter.EXPECT().CreateEntryWithCategoryFromDogu(readJenkinsDogu(t), "warp").Return(jenkinsEntryWithCategory, nil) + versionRegistryMock := NewMockDoguVersionRegistry(t) + redmineVersion := parseVersion(t, "5.1.3-1") + jenkinsVersion := parseVersion(t, "2.452.2-1") + redmineDoguVersion := dogu.DoguVersion{Name: "redmine", Version: *redmineVersion} + jenkinsDoguVersion := dogu.DoguVersion{Name: "jenkins", Version: *jenkinsVersion} + currentDoguVersions := []dogu.DoguVersion{redmineDoguVersion, jenkinsDoguVersion} + versionRegistryMock.EXPECT().GetCurrentOfAll(testCtx).Return(currentDoguVersions, nil) + doguSpecRepoMock := NewMockLocalDoguRepo(t) + doguSpecRepoMock.EXPECT().GetAll(testCtx, currentDoguVersions).Return(map[dogu.DoguVersion]*core.Dogu{redmineDoguVersion: readRedmineDogu(t), jenkinsDoguVersion: readJenkinsDogu(t)}, nil) + reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, - doguConverter: mockDoguConverter, + configuration: &config.Configuration{Support: []config.SupportSource{}}, + doguConverter: mockDoguConverter, + doguVersionRegistry: versionRegistryMock, + localDoguRepo: doguSpecRepoMock, } // when - categories, err := reader.dogusReader(source) + categories, err := reader.dogusReader(testCtx, source) // then require.NoError(t, err) assert.Equal(t, 1, categories.Len()) assert.Equal(t, 2, len(categories[0].Entries)) - mock.AssertExpectationsForObjects(t, mockRegistry, mockDoguConverter) }) - t.Run("failed to get children of /dogu path", func(t *testing.T) { + t.Run("failed to get all current versions", func(t *testing.T) { // given source := config.Source{ Path: "/dogu", Type: "dogus", Tag: "warp", } - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/dogu").Return([]string{}, assert.AnError) + versionRegistryMock := NewMockDoguVersionRegistry(t) + versionRegistryMock.EXPECT().GetCurrentOfAll(testCtx).Return(nil, assert.AnError) reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + doguVersionRegistry: versionRegistryMock, + configuration: &config.Configuration{Support: []config.SupportSource{}}, } // when - _, err := reader.dogusReader(source) + _, err := reader.dogusReader(testCtx, source) // then require.Error(t, err) - assert.Contains(t, err.Error(), "failed to Read root entry /dogu from etcd") - mock.AssertExpectationsForObjects(t, mockRegistry) + assert.Contains(t, err.Error(), "failed to get all current dogu versions") }) -} -func getEntryWithCategory(displayName string, href string, title string, category string, target types.Target) types.EntryWithCategory { - return types.EntryWithCategory{Entry: types.Entry{ - DisplayName: displayName, - Href: href, - Title: title, - Target: target, - }, Category: category} -} - -func TestConfigReader_externalsReader(t *testing.T) { - t.Run("fail to get children paths", func(t *testing.T) { + t.Run("failed to get dogus of currents", func(t *testing.T) { // given source := config.Source{ - Path: "/path", - Type: "externals", + Path: "/dogu", + Type: "dogus", + Tag: "warp", } - mockRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().GetChildrenPaths("/path").Return([]string{}, assert.AnError) + redmineVersion := parseVersion(t, "5.1.3-1") + redmineDoguVersion := dogu.DoguVersion{Name: "redmine", Version: *redmineVersion} + currentDoguVersions := []dogu.DoguVersion{redmineDoguVersion} + versionRegistryMock := NewMockDoguVersionRegistry(t) + versionRegistryMock.EXPECT().GetCurrentOfAll(testCtx).Return(currentDoguVersions, nil) + doguSpecMock := NewMockLocalDoguRepo(t) + doguSpecMock.EXPECT().GetAll(testCtx, currentDoguVersions).Return(nil, assert.AnError) reader := &ConfigReader{ - configuration: &config.Configuration{Support: []config.SupportSource{}}, - registry: mockRegistry, + doguVersionRegistry: versionRegistryMock, + localDoguRepo: doguSpecMock, + configuration: &config.Configuration{Support: []config.SupportSource{}}, } // when - _, err := reader.externalsReader(source) + _, err := reader.dogusReader(testCtx, source) // then require.Error(t, err) - mock.AssertExpectationsForObjects(t, mockRegistry) + assert.Contains(t, err.Error(), "failed to get all dogu specs with current versions") }) } +func getEntryWithCategory(displayName string, href string, title string, category string, target types.Target) types.EntryWithCategory { + return types.EntryWithCategory{Entry: types.Entry{ + DisplayName: displayName, + Href: href, + Title: title, + Target: target, + }, Category: category} +} diff --git a/controllers/warp/interfaces.go b/controllers/warp/interfaces.go new file mode 100644 index 0000000..8deb258 --- /dev/null +++ b/controllers/warp/interfaces.go @@ -0,0 +1,54 @@ +package warp + +import ( + "context" + "github.com/cloudogu/cesapp-lib/core" + libconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/dogu" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/cloudogu/k8s-service-discovery/controllers/config" + "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Reader is used to fetch warp categories with a configuration +type Reader interface { + Read(context.Context, *config.Configuration) (types.Categories, error) +} + +type eventRecorder interface { + record.EventRecorder +} + +// DoguConverter is used to Read dogus from the registry and convert them to objects fitting in the warp menu +type DoguConverter interface { + CreateEntryWithCategoryFromDogu(dogu *core.Dogu, tag string) (types.EntryWithCategory, error) +} + +// ExternalConverter is used to Read external links from the registry and convert them to objects fitting in the warp menu +type ExternalConverter interface { + ReadAndUnmarshalExternal(link string) (types.EntryWithCategory, error) +} + +type DoguVersionRegistry interface { + WatchAllCurrent(context.Context) (<-chan dogu.CurrentVersionsWatchResult, error) + GetCurrentOfAll(context.Context) ([]dogu.DoguVersion, error) +} + +type LocalDoguRepo interface { + GetAll(context.Context, []dogu.DoguVersion) (map[dogu.DoguVersion]*core.Dogu, error) +} + +type GlobalConfigRepository interface { + Watch(context.Context, ...libconfig.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) + Get(context.Context) (libconfig.GlobalConfig, error) +} + +// used for mocks + +//nolint:unused +//goland:noinspection GoUnusedType +type k8sClient interface { + client.Client +} diff --git a/controllers/warp/mock_DoguConverter_test.go b/controllers/warp/mock_DoguConverter_test.go index bf0a3e5..b6e479a 100644 --- a/controllers/warp/mock_DoguConverter_test.go +++ b/controllers/warp/mock_DoguConverter_test.go @@ -1,10 +1,12 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package warp import ( - types "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" + core "github.com/cloudogu/cesapp-lib/core" mock "github.com/stretchr/testify/mock" + + types "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" ) // MockDoguConverter is an autogenerated mock type for the DoguConverter type @@ -20,23 +22,27 @@ func (_m *MockDoguConverter) EXPECT() *MockDoguConverter_Expecter { return &MockDoguConverter_Expecter{mock: &_m.Mock} } -// ReadAndUnmarshalDogu provides a mock function with given fields: registry, key, tag -func (_m *MockDoguConverter) ReadAndUnmarshalDogu(registry types.WatchConfigurationContext, key string, tag string) (types.EntryWithCategory, error) { - ret := _m.Called(registry, key, tag) +// CreateEntryWithCategoryFromDogu provides a mock function with given fields: dogu, tag +func (_m *MockDoguConverter) CreateEntryWithCategoryFromDogu(dogu *core.Dogu, tag string) (types.EntryWithCategory, error) { + ret := _m.Called(dogu, tag) + + if len(ret) == 0 { + panic("no return value specified for CreateEntryWithCategoryFromDogu") + } var r0 types.EntryWithCategory var r1 error - if rf, ok := ret.Get(0).(func(types.WatchConfigurationContext, string, string) (types.EntryWithCategory, error)); ok { - return rf(registry, key, tag) + if rf, ok := ret.Get(0).(func(*core.Dogu, string) (types.EntryWithCategory, error)); ok { + return rf(dogu, tag) } - if rf, ok := ret.Get(0).(func(types.WatchConfigurationContext, string, string) types.EntryWithCategory); ok { - r0 = rf(registry, key, tag) + if rf, ok := ret.Get(0).(func(*core.Dogu, string) types.EntryWithCategory); ok { + r0 = rf(dogu, tag) } else { r0 = ret.Get(0).(types.EntryWithCategory) } - if rf, ok := ret.Get(1).(func(types.WatchConfigurationContext, string, string) error); ok { - r1 = rf(registry, key, tag) + if rf, ok := ret.Get(1).(func(*core.Dogu, string) error); ok { + r1 = rf(dogu, tag) } else { r1 = ret.Error(1) } @@ -44,43 +50,41 @@ func (_m *MockDoguConverter) ReadAndUnmarshalDogu(registry types.WatchConfigurat return r0, r1 } -// MockDoguConverter_ReadAndUnmarshalDogu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadAndUnmarshalDogu' -type MockDoguConverter_ReadAndUnmarshalDogu_Call struct { +// MockDoguConverter_CreateEntryWithCategoryFromDogu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateEntryWithCategoryFromDogu' +type MockDoguConverter_CreateEntryWithCategoryFromDogu_Call struct { *mock.Call } -// ReadAndUnmarshalDogu is a helper method to define mock.On call -// - registry types.WatchConfigurationContext -// - key string +// CreateEntryWithCategoryFromDogu is a helper method to define mock.On call +// - dogu *core.Dogu // - tag string -func (_e *MockDoguConverter_Expecter) ReadAndUnmarshalDogu(registry interface{}, key interface{}, tag interface{}) *MockDoguConverter_ReadAndUnmarshalDogu_Call { - return &MockDoguConverter_ReadAndUnmarshalDogu_Call{Call: _e.mock.On("ReadAndUnmarshalDogu", registry, key, tag)} +func (_e *MockDoguConverter_Expecter) CreateEntryWithCategoryFromDogu(dogu interface{}, tag interface{}) *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call { + return &MockDoguConverter_CreateEntryWithCategoryFromDogu_Call{Call: _e.mock.On("CreateEntryWithCategoryFromDogu", dogu, tag)} } -func (_c *MockDoguConverter_ReadAndUnmarshalDogu_Call) Run(run func(registry types.WatchConfigurationContext, key string, tag string)) *MockDoguConverter_ReadAndUnmarshalDogu_Call { +func (_c *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call) Run(run func(dogu *core.Dogu, tag string)) *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.WatchConfigurationContext), args[1].(string), args[2].(string)) + run(args[0].(*core.Dogu), args[1].(string)) }) return _c } -func (_c *MockDoguConverter_ReadAndUnmarshalDogu_Call) Return(_a0 types.EntryWithCategory, _a1 error) *MockDoguConverter_ReadAndUnmarshalDogu_Call { +func (_c *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call) Return(_a0 types.EntryWithCategory, _a1 error) *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockDoguConverter_ReadAndUnmarshalDogu_Call) RunAndReturn(run func(types.WatchConfigurationContext, string, string) (types.EntryWithCategory, error)) *MockDoguConverter_ReadAndUnmarshalDogu_Call { +func (_c *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call) RunAndReturn(run func(*core.Dogu, string) (types.EntryWithCategory, error)) *MockDoguConverter_CreateEntryWithCategoryFromDogu_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTNewMockDoguConverter interface { +// NewMockDoguConverter creates a new instance of MockDoguConverter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDoguConverter(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockDoguConverter creates a new instance of MockDoguConverter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockDoguConverter(t mockConstructorTestingTNewMockDoguConverter) *MockDoguConverter { +}) *MockDoguConverter { mock := &MockDoguConverter{} mock.Mock.Test(t) diff --git a/controllers/warp/mock_DoguVersionRegistry_test.go b/controllers/warp/mock_DoguVersionRegistry_test.go new file mode 100644 index 0000000..41589bc --- /dev/null +++ b/controllers/warp/mock_DoguVersionRegistry_test.go @@ -0,0 +1,153 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package warp + +import ( + context "context" + + dogu "github.com/cloudogu/k8s-registry-lib/dogu" + mock "github.com/stretchr/testify/mock" +) + +// MockDoguVersionRegistry is an autogenerated mock type for the DoguVersionRegistry type +type MockDoguVersionRegistry struct { + mock.Mock +} + +type MockDoguVersionRegistry_Expecter struct { + mock *mock.Mock +} + +func (_m *MockDoguVersionRegistry) EXPECT() *MockDoguVersionRegistry_Expecter { + return &MockDoguVersionRegistry_Expecter{mock: &_m.Mock} +} + +// GetCurrentOfAll provides a mock function with given fields: _a0 +func (_m *MockDoguVersionRegistry) GetCurrentOfAll(_a0 context.Context) ([]dogu.DoguVersion, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for GetCurrentOfAll") + } + + var r0 []dogu.DoguVersion + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]dogu.DoguVersion, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) []dogu.DoguVersion); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]dogu.DoguVersion) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDoguVersionRegistry_GetCurrentOfAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCurrentOfAll' +type MockDoguVersionRegistry_GetCurrentOfAll_Call struct { + *mock.Call +} + +// GetCurrentOfAll is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockDoguVersionRegistry_Expecter) GetCurrentOfAll(_a0 interface{}) *MockDoguVersionRegistry_GetCurrentOfAll_Call { + return &MockDoguVersionRegistry_GetCurrentOfAll_Call{Call: _e.mock.On("GetCurrentOfAll", _a0)} +} + +func (_c *MockDoguVersionRegistry_GetCurrentOfAll_Call) Run(run func(_a0 context.Context)) *MockDoguVersionRegistry_GetCurrentOfAll_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockDoguVersionRegistry_GetCurrentOfAll_Call) Return(_a0 []dogu.DoguVersion, _a1 error) *MockDoguVersionRegistry_GetCurrentOfAll_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDoguVersionRegistry_GetCurrentOfAll_Call) RunAndReturn(run func(context.Context) ([]dogu.DoguVersion, error)) *MockDoguVersionRegistry_GetCurrentOfAll_Call { + _c.Call.Return(run) + return _c +} + +// WatchAllCurrent provides a mock function with given fields: _a0 +func (_m *MockDoguVersionRegistry) WatchAllCurrent(_a0 context.Context) (<-chan dogu.CurrentVersionsWatchResult, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WatchAllCurrent") + } + + var r0 <-chan dogu.CurrentVersionsWatchResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (<-chan dogu.CurrentVersionsWatchResult, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) <-chan dogu.CurrentVersionsWatchResult); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan dogu.CurrentVersionsWatchResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDoguVersionRegistry_WatchAllCurrent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAllCurrent' +type MockDoguVersionRegistry_WatchAllCurrent_Call struct { + *mock.Call +} + +// WatchAllCurrent is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockDoguVersionRegistry_Expecter) WatchAllCurrent(_a0 interface{}) *MockDoguVersionRegistry_WatchAllCurrent_Call { + return &MockDoguVersionRegistry_WatchAllCurrent_Call{Call: _e.mock.On("WatchAllCurrent", _a0)} +} + +func (_c *MockDoguVersionRegistry_WatchAllCurrent_Call) Run(run func(_a0 context.Context)) *MockDoguVersionRegistry_WatchAllCurrent_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockDoguVersionRegistry_WatchAllCurrent_Call) Return(_a0 <-chan dogu.CurrentVersionsWatchResult, _a1 error) *MockDoguVersionRegistry_WatchAllCurrent_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDoguVersionRegistry_WatchAllCurrent_Call) RunAndReturn(run func(context.Context) (<-chan dogu.CurrentVersionsWatchResult, error)) *MockDoguVersionRegistry_WatchAllCurrent_Call { + _c.Call.Return(run) + return _c +} + +// NewMockDoguVersionRegistry creates a new instance of MockDoguVersionRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDoguVersionRegistry(t interface { + mock.TestingT + Cleanup(func()) +}) *MockDoguVersionRegistry { + mock := &MockDoguVersionRegistry{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/warp/mock_ExternalConverter_test.go b/controllers/warp/mock_ExternalConverter_test.go index 69a0c23..22c1c49 100644 --- a/controllers/warp/mock_ExternalConverter_test.go +++ b/controllers/warp/mock_ExternalConverter_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package warp @@ -20,23 +20,27 @@ func (_m *MockExternalConverter) EXPECT() *MockExternalConverter_Expecter { return &MockExternalConverter_Expecter{mock: &_m.Mock} } -// ReadAndUnmarshalExternal provides a mock function with given fields: registry, key -func (_m *MockExternalConverter) ReadAndUnmarshalExternal(registry types.WatchConfigurationContext, key string) (types.EntryWithCategory, error) { - ret := _m.Called(registry, key) +// ReadAndUnmarshalExternal provides a mock function with given fields: link +func (_m *MockExternalConverter) ReadAndUnmarshalExternal(link string) (types.EntryWithCategory, error) { + ret := _m.Called(link) + + if len(ret) == 0 { + panic("no return value specified for ReadAndUnmarshalExternal") + } var r0 types.EntryWithCategory var r1 error - if rf, ok := ret.Get(0).(func(types.WatchConfigurationContext, string) (types.EntryWithCategory, error)); ok { - return rf(registry, key) + if rf, ok := ret.Get(0).(func(string) (types.EntryWithCategory, error)); ok { + return rf(link) } - if rf, ok := ret.Get(0).(func(types.WatchConfigurationContext, string) types.EntryWithCategory); ok { - r0 = rf(registry, key) + if rf, ok := ret.Get(0).(func(string) types.EntryWithCategory); ok { + r0 = rf(link) } else { r0 = ret.Get(0).(types.EntryWithCategory) } - if rf, ok := ret.Get(1).(func(types.WatchConfigurationContext, string) error); ok { - r1 = rf(registry, key) + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(link) } else { r1 = ret.Error(1) } @@ -50,15 +54,14 @@ type MockExternalConverter_ReadAndUnmarshalExternal_Call struct { } // ReadAndUnmarshalExternal is a helper method to define mock.On call -// - registry types.WatchConfigurationContext -// - key string -func (_e *MockExternalConverter_Expecter) ReadAndUnmarshalExternal(registry interface{}, key interface{}) *MockExternalConverter_ReadAndUnmarshalExternal_Call { - return &MockExternalConverter_ReadAndUnmarshalExternal_Call{Call: _e.mock.On("ReadAndUnmarshalExternal", registry, key)} +// - link string +func (_e *MockExternalConverter_Expecter) ReadAndUnmarshalExternal(link interface{}) *MockExternalConverter_ReadAndUnmarshalExternal_Call { + return &MockExternalConverter_ReadAndUnmarshalExternal_Call{Call: _e.mock.On("ReadAndUnmarshalExternal", link)} } -func (_c *MockExternalConverter_ReadAndUnmarshalExternal_Call) Run(run func(registry types.WatchConfigurationContext, key string)) *MockExternalConverter_ReadAndUnmarshalExternal_Call { +func (_c *MockExternalConverter_ReadAndUnmarshalExternal_Call) Run(run func(link string)) *MockExternalConverter_ReadAndUnmarshalExternal_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.WatchConfigurationContext), args[1].(string)) + run(args[0].(string)) }) return _c } @@ -68,18 +71,17 @@ func (_c *MockExternalConverter_ReadAndUnmarshalExternal_Call) Return(_a0 types. return _c } -func (_c *MockExternalConverter_ReadAndUnmarshalExternal_Call) RunAndReturn(run func(types.WatchConfigurationContext, string) (types.EntryWithCategory, error)) *MockExternalConverter_ReadAndUnmarshalExternal_Call { +func (_c *MockExternalConverter_ReadAndUnmarshalExternal_Call) RunAndReturn(run func(string) (types.EntryWithCategory, error)) *MockExternalConverter_ReadAndUnmarshalExternal_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTNewMockExternalConverter interface { +// NewMockExternalConverter creates a new instance of MockExternalConverter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockExternalConverter(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockExternalConverter creates a new instance of MockExternalConverter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockExternalConverter(t mockConstructorTestingTNewMockExternalConverter) *MockExternalConverter { +}) *MockExternalConverter { mock := &MockExternalConverter{} mock.Mock.Test(t) diff --git a/controllers/warp/mock_GlobalConfigRepository_test.go b/controllers/warp/mock_GlobalConfigRepository_test.go new file mode 100644 index 0000000..5d3a90a --- /dev/null +++ b/controllers/warp/mock_GlobalConfigRepository_test.go @@ -0,0 +1,169 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package warp + +import ( + context "context" + + config "github.com/cloudogu/k8s-registry-lib/config" + + mock "github.com/stretchr/testify/mock" + + repository "github.com/cloudogu/k8s-registry-lib/repository" +) + +// MockGlobalConfigRepository is an autogenerated mock type for the GlobalConfigRepository type +type MockGlobalConfigRepository struct { + mock.Mock +} + +type MockGlobalConfigRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGlobalConfigRepository) EXPECT() *MockGlobalConfigRepository_Expecter { + return &MockGlobalConfigRepository_Expecter{mock: &_m.Mock} +} + +// Get provides a mock function with given fields: _a0 +func (_m *MockGlobalConfigRepository) Get(_a0 context.Context) (config.GlobalConfig, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 config.GlobalConfig + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (config.GlobalConfig, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) config.GlobalConfig); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(config.GlobalConfig) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockGlobalConfigRepository_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockGlobalConfigRepository_Expecter) Get(_a0 interface{}) *MockGlobalConfigRepository_Get_Call { + return &MockGlobalConfigRepository_Get_Call{Call: _e.mock.On("Get", _a0)} +} + +func (_c *MockGlobalConfigRepository_Get_Call) Run(run func(_a0 context.Context)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) Return(_a0 config.GlobalConfig, _a1 error) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Get_Call) RunAndReturn(run func(context.Context) (config.GlobalConfig, error)) *MockGlobalConfigRepository_Get_Call { + _c.Call.Return(run) + return _c +} + +// Watch provides a mock function with given fields: _a0, _a1 +func (_m *MockGlobalConfigRepository) Watch(_a0 context.Context, _a1 ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error) { + _va := make([]interface{}, len(_a1)) + for _i := range _a1 { + _va[_i] = _a1[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Watch") + } + + var r0 <-chan repository.GlobalConfigWatchResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)); ok { + return rf(_a0, _a1...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...config.WatchFilter) <-chan repository.GlobalConfigWatchResult); ok { + r0 = rf(_a0, _a1...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan repository.GlobalConfigWatchResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...config.WatchFilter) error); ok { + r1 = rf(_a0, _a1...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGlobalConfigRepository_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' +type MockGlobalConfigRepository_Watch_Call struct { + *mock.Call +} + +// Watch is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 ...config.WatchFilter +func (_e *MockGlobalConfigRepository_Expecter) Watch(_a0 interface{}, _a1 ...interface{}) *MockGlobalConfigRepository_Watch_Call { + return &MockGlobalConfigRepository_Watch_Call{Call: _e.mock.On("Watch", + append([]interface{}{_a0}, _a1...)...)} +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Run(run func(_a0 context.Context, _a1 ...config.WatchFilter)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]config.WatchFilter, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(config.WatchFilter) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) Return(_a0 <-chan repository.GlobalConfigWatchResult, _a1 error) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGlobalConfigRepository_Watch_Call) RunAndReturn(run func(context.Context, ...config.WatchFilter) (<-chan repository.GlobalConfigWatchResult, error)) *MockGlobalConfigRepository_Watch_Call { + _c.Call.Return(run) + return _c +} + +// NewMockGlobalConfigRepository creates a new instance of MockGlobalConfigRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockGlobalConfigRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGlobalConfigRepository { + mock := &MockGlobalConfigRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/warp/mock_LocalDoguRepo_test.go b/controllers/warp/mock_LocalDoguRepo_test.go new file mode 100644 index 0000000..095f04c --- /dev/null +++ b/controllers/warp/mock_LocalDoguRepo_test.go @@ -0,0 +1,98 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package warp + +import ( + context "context" + + core "github.com/cloudogu/cesapp-lib/core" + dogu "github.com/cloudogu/k8s-registry-lib/dogu" + + mock "github.com/stretchr/testify/mock" +) + +// MockLocalDoguRepo is an autogenerated mock type for the LocalDoguRepo type +type MockLocalDoguRepo struct { + mock.Mock +} + +type MockLocalDoguRepo_Expecter struct { + mock *mock.Mock +} + +func (_m *MockLocalDoguRepo) EXPECT() *MockLocalDoguRepo_Expecter { + return &MockLocalDoguRepo_Expecter{mock: &_m.Mock} +} + +// GetAll provides a mock function with given fields: _a0, _a1 +func (_m *MockLocalDoguRepo) GetAll(_a0 context.Context, _a1 []dogu.DoguVersion) (map[dogu.DoguVersion]*core.Dogu, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + + var r0 map[dogu.DoguVersion]*core.Dogu + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []dogu.DoguVersion) (map[dogu.DoguVersion]*core.Dogu, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, []dogu.DoguVersion) map[dogu.DoguVersion]*core.Dogu); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[dogu.DoguVersion]*core.Dogu) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []dogu.DoguVersion) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockLocalDoguRepo_GetAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAll' +type MockLocalDoguRepo_GetAll_Call struct { + *mock.Call +} + +// GetAll is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 []dogu.DoguVersion +func (_e *MockLocalDoguRepo_Expecter) GetAll(_a0 interface{}, _a1 interface{}) *MockLocalDoguRepo_GetAll_Call { + return &MockLocalDoguRepo_GetAll_Call{Call: _e.mock.On("GetAll", _a0, _a1)} +} + +func (_c *MockLocalDoguRepo_GetAll_Call) Run(run func(_a0 context.Context, _a1 []dogu.DoguVersion)) *MockLocalDoguRepo_GetAll_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([]dogu.DoguVersion)) + }) + return _c +} + +func (_c *MockLocalDoguRepo_GetAll_Call) Return(_a0 map[dogu.DoguVersion]*core.Dogu, _a1 error) *MockLocalDoguRepo_GetAll_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockLocalDoguRepo_GetAll_Call) RunAndReturn(run func(context.Context, []dogu.DoguVersion) (map[dogu.DoguVersion]*core.Dogu, error)) *MockLocalDoguRepo_GetAll_Call { + _c.Call.Return(run) + return _c +} + +// NewMockLocalDoguRepo creates a new instance of MockLocalDoguRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockLocalDoguRepo(t interface { + mock.TestingT + Cleanup(func()) +}) *MockLocalDoguRepo { + mock := &MockLocalDoguRepo{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/warp/mock_Reader_test.go b/controllers/warp/mock_Reader_test.go index 07e94ee..c017162 100644 --- a/controllers/warp/mock_Reader_test.go +++ b/controllers/warp/mock_Reader_test.go @@ -1,9 +1,12 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package warp import ( + context "context" + config "github.com/cloudogu/k8s-service-discovery/controllers/config" + mock "github.com/stretchr/testify/mock" types "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" @@ -22,25 +25,29 @@ func (_m *MockReader) EXPECT() *MockReader_Expecter { return &MockReader_Expecter{mock: &_m.Mock} } -// Read provides a mock function with given fields: configuration -func (_m *MockReader) Read(configuration *config.Configuration) (types.Categories, error) { - ret := _m.Called(configuration) +// Read provides a mock function with given fields: _a0, _a1 +func (_m *MockReader) Read(_a0 context.Context, _a1 *config.Configuration) (types.Categories, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Read") + } var r0 types.Categories var r1 error - if rf, ok := ret.Get(0).(func(*config.Configuration) (types.Categories, error)); ok { - return rf(configuration) + if rf, ok := ret.Get(0).(func(context.Context, *config.Configuration) (types.Categories, error)); ok { + return rf(_a0, _a1) } - if rf, ok := ret.Get(0).(func(*config.Configuration) types.Categories); ok { - r0 = rf(configuration) + if rf, ok := ret.Get(0).(func(context.Context, *config.Configuration) types.Categories); ok { + r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(types.Categories) } } - if rf, ok := ret.Get(1).(func(*config.Configuration) error); ok { - r1 = rf(configuration) + if rf, ok := ret.Get(1).(func(context.Context, *config.Configuration) error); ok { + r1 = rf(_a0, _a1) } else { r1 = ret.Error(1) } @@ -54,14 +61,15 @@ type MockReader_Read_Call struct { } // Read is a helper method to define mock.On call -// - configuration *config.Configuration -func (_e *MockReader_Expecter) Read(configuration interface{}) *MockReader_Read_Call { - return &MockReader_Read_Call{Call: _e.mock.On("Read", configuration)} +// - _a0 context.Context +// - _a1 *config.Configuration +func (_e *MockReader_Expecter) Read(_a0 interface{}, _a1 interface{}) *MockReader_Read_Call { + return &MockReader_Read_Call{Call: _e.mock.On("Read", _a0, _a1)} } -func (_c *MockReader_Read_Call) Run(run func(configuration *config.Configuration)) *MockReader_Read_Call { +func (_c *MockReader_Read_Call) Run(run func(_a0 context.Context, _a1 *config.Configuration)) *MockReader_Read_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*config.Configuration)) + run(args[0].(context.Context), args[1].(*config.Configuration)) }) return _c } @@ -71,18 +79,17 @@ func (_c *MockReader_Read_Call) Return(_a0 types.Categories, _a1 error) *MockRea return _c } -func (_c *MockReader_Read_Call) RunAndReturn(run func(*config.Configuration) (types.Categories, error)) *MockReader_Read_Call { +func (_c *MockReader_Read_Call) RunAndReturn(run func(context.Context, *config.Configuration) (types.Categories, error)) *MockReader_Read_Call { _c.Call.Return(run) return _c } -type mockConstructorTestingTNewMockReader interface { +// NewMockReader creates a new instance of MockReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReader(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockReader creates a new instance of MockReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockReader(t mockConstructorTestingTNewMockReader) *MockReader { +}) *MockReader { mock := &MockReader{} mock.Mock.Test(t) diff --git a/controllers/warp/mock_cesRegistry_test.go b/controllers/warp/mock_cesRegistry_test.go deleted file mode 100644 index 84c04dc..0000000 --- a/controllers/warp/mock_cesRegistry_test.go +++ /dev/null @@ -1,391 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package warp - -import ( - registry "github.com/cloudogu/cesapp-lib/registry" - mock "github.com/stretchr/testify/mock" -) - -// mockCesRegistry is an autogenerated mock type for the cesRegistry type -type mockCesRegistry struct { - mock.Mock -} - -type mockCesRegistry_Expecter struct { - mock *mock.Mock -} - -func (_m *mockCesRegistry) EXPECT() *mockCesRegistry_Expecter { - return &mockCesRegistry_Expecter{mock: &_m.Mock} -} - -// BlueprintRegistry provides a mock function with given fields: -func (_m *mockCesRegistry) BlueprintRegistry() registry.ConfigurationContext { - ret := _m.Called() - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func() registry.ConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_BlueprintRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlueprintRegistry' -type mockCesRegistry_BlueprintRegistry_Call struct { - *mock.Call -} - -// BlueprintRegistry is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) BlueprintRegistry() *mockCesRegistry_BlueprintRegistry_Call { - return &mockCesRegistry_BlueprintRegistry_Call{Call: _e.mock.On("BlueprintRegistry")} -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) Run(run func()) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_BlueprintRegistry_Call) RunAndReturn(run func() registry.ConfigurationContext) *mockCesRegistry_BlueprintRegistry_Call { - _c.Call.Return(run) - return _c -} - -// DoguConfig provides a mock function with given fields: dogu -func (_m *mockCesRegistry) DoguConfig(dogu string) registry.ConfigurationContext { - ret := _m.Called(dogu) - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func(string) registry.ConfigurationContext); ok { - r0 = rf(dogu) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_DoguConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoguConfig' -type mockCesRegistry_DoguConfig_Call struct { - *mock.Call -} - -// DoguConfig is a helper method to define mock.On call -// - dogu string -func (_e *mockCesRegistry_Expecter) DoguConfig(dogu interface{}) *mockCesRegistry_DoguConfig_Call { - return &mockCesRegistry_DoguConfig_Call{Call: _e.mock.On("DoguConfig", dogu)} -} - -func (_c *mockCesRegistry_DoguConfig_Call) Run(run func(dogu string)) *mockCesRegistry_DoguConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_DoguConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_DoguConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_DoguConfig_Call) RunAndReturn(run func(string) registry.ConfigurationContext) *mockCesRegistry_DoguConfig_Call { - _c.Call.Return(run) - return _c -} - -// DoguRegistry provides a mock function with given fields: -func (_m *mockCesRegistry) DoguRegistry() registry.DoguRegistry { - ret := _m.Called() - - var r0 registry.DoguRegistry - if rf, ok := ret.Get(0).(func() registry.DoguRegistry); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.DoguRegistry) - } - } - - return r0 -} - -// mockCesRegistry_DoguRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoguRegistry' -type mockCesRegistry_DoguRegistry_Call struct { - *mock.Call -} - -// DoguRegistry is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) DoguRegistry() *mockCesRegistry_DoguRegistry_Call { - return &mockCesRegistry_DoguRegistry_Call{Call: _e.mock.On("DoguRegistry")} -} - -func (_c *mockCesRegistry_DoguRegistry_Call) Run(run func()) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_DoguRegistry_Call) Return(_a0 registry.DoguRegistry) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_DoguRegistry_Call) RunAndReturn(run func() registry.DoguRegistry) *mockCesRegistry_DoguRegistry_Call { - _c.Call.Return(run) - return _c -} - -// GetNode provides a mock function with given fields: -func (_m *mockCesRegistry) GetNode() (registry.Node, error) { - ret := _m.Called() - - var r0 registry.Node - var r1 error - if rf, ok := ret.Get(0).(func() (registry.Node, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() registry.Node); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(registry.Node) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockCesRegistry_GetNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNode' -type mockCesRegistry_GetNode_Call struct { - *mock.Call -} - -// GetNode is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) GetNode() *mockCesRegistry_GetNode_Call { - return &mockCesRegistry_GetNode_Call{Call: _e.mock.On("GetNode")} -} - -func (_c *mockCesRegistry_GetNode_Call) Run(run func()) *mockCesRegistry_GetNode_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_GetNode_Call) Return(_a0 registry.Node, _a1 error) *mockCesRegistry_GetNode_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockCesRegistry_GetNode_Call) RunAndReturn(run func() (registry.Node, error)) *mockCesRegistry_GetNode_Call { - _c.Call.Return(run) - return _c -} - -// GlobalConfig provides a mock function with given fields: -func (_m *mockCesRegistry) GlobalConfig() registry.ConfigurationContext { - ret := _m.Called() - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func() registry.ConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_GlobalConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GlobalConfig' -type mockCesRegistry_GlobalConfig_Call struct { - *mock.Call -} - -// GlobalConfig is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) GlobalConfig() *mockCesRegistry_GlobalConfig_Call { - return &mockCesRegistry_GlobalConfig_Call{Call: _e.mock.On("GlobalConfig")} -} - -func (_c *mockCesRegistry_GlobalConfig_Call) Run(run func()) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_GlobalConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_GlobalConfig_Call) RunAndReturn(run func() registry.ConfigurationContext) *mockCesRegistry_GlobalConfig_Call { - _c.Call.Return(run) - return _c -} - -// HostConfig provides a mock function with given fields: hostService -func (_m *mockCesRegistry) HostConfig(hostService string) registry.ConfigurationContext { - ret := _m.Called(hostService) - - var r0 registry.ConfigurationContext - if rf, ok := ret.Get(0).(func(string) registry.ConfigurationContext); ok { - r0 = rf(hostService) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.ConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_HostConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HostConfig' -type mockCesRegistry_HostConfig_Call struct { - *mock.Call -} - -// HostConfig is a helper method to define mock.On call -// - hostService string -func (_e *mockCesRegistry_Expecter) HostConfig(hostService interface{}) *mockCesRegistry_HostConfig_Call { - return &mockCesRegistry_HostConfig_Call{Call: _e.mock.On("HostConfig", hostService)} -} - -func (_c *mockCesRegistry_HostConfig_Call) Run(run func(hostService string)) *mockCesRegistry_HostConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_HostConfig_Call) Return(_a0 registry.ConfigurationContext) *mockCesRegistry_HostConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_HostConfig_Call) RunAndReturn(run func(string) registry.ConfigurationContext) *mockCesRegistry_HostConfig_Call { - _c.Call.Return(run) - return _c -} - -// RootConfig provides a mock function with given fields: -func (_m *mockCesRegistry) RootConfig() registry.WatchConfigurationContext { - ret := _m.Called() - - var r0 registry.WatchConfigurationContext - if rf, ok := ret.Get(0).(func() registry.WatchConfigurationContext); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.WatchConfigurationContext) - } - } - - return r0 -} - -// mockCesRegistry_RootConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RootConfig' -type mockCesRegistry_RootConfig_Call struct { - *mock.Call -} - -// RootConfig is a helper method to define mock.On call -func (_e *mockCesRegistry_Expecter) RootConfig() *mockCesRegistry_RootConfig_Call { - return &mockCesRegistry_RootConfig_Call{Call: _e.mock.On("RootConfig")} -} - -func (_c *mockCesRegistry_RootConfig_Call) Run(run func()) *mockCesRegistry_RootConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockCesRegistry_RootConfig_Call) Return(_a0 registry.WatchConfigurationContext) *mockCesRegistry_RootConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_RootConfig_Call) RunAndReturn(run func() registry.WatchConfigurationContext) *mockCesRegistry_RootConfig_Call { - _c.Call.Return(run) - return _c -} - -// State provides a mock function with given fields: dogu -func (_m *mockCesRegistry) State(dogu string) registry.State { - ret := _m.Called(dogu) - - var r0 registry.State - if rf, ok := ret.Get(0).(func(string) registry.State); ok { - r0 = rf(dogu) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(registry.State) - } - } - - return r0 -} - -// mockCesRegistry_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State' -type mockCesRegistry_State_Call struct { - *mock.Call -} - -// State is a helper method to define mock.On call -// - dogu string -func (_e *mockCesRegistry_Expecter) State(dogu interface{}) *mockCesRegistry_State_Call { - return &mockCesRegistry_State_Call{Call: _e.mock.On("State", dogu)} -} - -func (_c *mockCesRegistry_State_Call) Run(run func(dogu string)) *mockCesRegistry_State_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockCesRegistry_State_Call) Return(_a0 registry.State) *mockCesRegistry_State_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockCesRegistry_State_Call) RunAndReturn(run func(string) registry.State) *mockCesRegistry_State_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockCesRegistry interface { - mock.TestingT - Cleanup(func()) -} - -// newMockCesRegistry creates a new instance of mockCesRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockCesRegistry(t mockConstructorTestingTnewMockCesRegistry) *mockCesRegistry { - mock := &mockCesRegistry{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/warp/mock_eventRecorder_test.go b/controllers/warp/mock_eventRecorder_test.go index 86b8fe8..51ed7f3 100644 --- a/controllers/warp/mock_eventRecorder_test.go +++ b/controllers/warp/mock_eventRecorder_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package warp @@ -151,13 +151,12 @@ func (_c *mockEventRecorder_Eventf_Call) RunAndReturn(run func(runtime.Object, s return _c } -type mockConstructorTestingTnewMockEventRecorder interface { +// newMockEventRecorder creates a new instance of mockEventRecorder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockEventRecorder(t interface { mock.TestingT Cleanup(func()) -} - -// newMockEventRecorder creates a new instance of mockEventRecorder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockEventRecorder(t mockConstructorTestingTnewMockEventRecorder) *mockEventRecorder { +}) *mockEventRecorder { mock := &mockEventRecorder{} mock.Mock.Test(t) diff --git a/controllers/warp/mock_k8sClient_test.go b/controllers/warp/mock_k8sClient_test.go new file mode 100644 index 0000000..9a3b045 --- /dev/null +++ b/controllers/warp/mock_k8sClient_test.go @@ -0,0 +1,783 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package warp + +import ( + context "context" + + client "sigs.k8s.io/controller-runtime/pkg/client" + + meta "k8s.io/apimachinery/pkg/api/meta" + + mock "github.com/stretchr/testify/mock" + + runtime "k8s.io/apimachinery/pkg/runtime" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + + types "k8s.io/apimachinery/pkg/types" +) + +// mockK8sClient is an autogenerated mock type for the k8sClient type +type mockK8sClient struct { + mock.Mock +} + +type mockK8sClient_Expecter struct { + mock *mock.Mock +} + +func (_m *mockK8sClient) EXPECT() *mockK8sClient_Expecter { + return &mockK8sClient_Expecter{mock: &_m.Mock} +} + +// Create provides a mock function with given fields: ctx, obj, opts +func (_m *mockK8sClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.CreateOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type mockK8sClient_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.CreateOption +func (_e *mockK8sClient_Expecter) Create(ctx interface{}, obj interface{}, opts ...interface{}) *mockK8sClient_Create_Call { + return &mockK8sClient_Create_Call{Call: _e.mock.On("Create", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *mockK8sClient_Create_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.CreateOption)) *mockK8sClient_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.CreateOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.CreateOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_Create_Call) Return(_a0 error) *mockK8sClient_Create_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Create_Call) RunAndReturn(run func(context.Context, client.Object, ...client.CreateOption) error) *mockK8sClient_Create_Call { + _c.Call.Return(run) + return _c +} + +// Delete provides a mock function with given fields: ctx, obj, opts +func (_m *mockK8sClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' +type mockK8sClient_Delete_Call struct { + *mock.Call +} + +// Delete is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.DeleteOption +func (_e *mockK8sClient_Expecter) Delete(ctx interface{}, obj interface{}, opts ...interface{}) *mockK8sClient_Delete_Call { + return &mockK8sClient_Delete_Call{Call: _e.mock.On("Delete", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *mockK8sClient_Delete_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.DeleteOption)) *mockK8sClient_Delete_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.DeleteOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.DeleteOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_Delete_Call) Return(_a0 error) *mockK8sClient_Delete_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Delete_Call) RunAndReturn(run func(context.Context, client.Object, ...client.DeleteOption) error) *mockK8sClient_Delete_Call { + _c.Call.Return(run) + return _c +} + +// DeleteAllOf provides a mock function with given fields: ctx, obj, opts +func (_m *mockK8sClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DeleteAllOf") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteAllOfOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_DeleteAllOf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteAllOf' +type mockK8sClient_DeleteAllOf_Call struct { + *mock.Call +} + +// DeleteAllOf is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.DeleteAllOfOption +func (_e *mockK8sClient_Expecter) DeleteAllOf(ctx interface{}, obj interface{}, opts ...interface{}) *mockK8sClient_DeleteAllOf_Call { + return &mockK8sClient_DeleteAllOf_Call{Call: _e.mock.On("DeleteAllOf", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *mockK8sClient_DeleteAllOf_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption)) *mockK8sClient_DeleteAllOf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.DeleteAllOfOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.DeleteAllOfOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_DeleteAllOf_Call) Return(_a0 error) *mockK8sClient_DeleteAllOf_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_DeleteAllOf_Call) RunAndReturn(run func(context.Context, client.Object, ...client.DeleteAllOfOption) error) *mockK8sClient_DeleteAllOf_Call { + _c.Call.Return(run) + return _c +} + +// Get provides a mock function with given fields: ctx, key, obj, opts +func (_m *mockK8sClient) Get(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, key, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error); ok { + r0 = rf(ctx, key, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type mockK8sClient_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - ctx context.Context +// - key types.NamespacedName +// - obj client.Object +// - opts ...client.GetOption +func (_e *mockK8sClient_Expecter) Get(ctx interface{}, key interface{}, obj interface{}, opts ...interface{}) *mockK8sClient_Get_Call { + return &mockK8sClient_Get_Call{Call: _e.mock.On("Get", + append([]interface{}{ctx, key, obj}, opts...)...)} +} + +func (_c *mockK8sClient_Get_Call) Run(run func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption)) *mockK8sClient_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.GetOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(client.GetOption) + } + } + run(args[0].(context.Context), args[1].(types.NamespacedName), args[2].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_Get_Call) Return(_a0 error) *mockK8sClient_Get_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Get_Call) RunAndReturn(run func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error) *mockK8sClient_Get_Call { + _c.Call.Return(run) + return _c +} + +// GroupVersionKindFor provides a mock function with given fields: obj +func (_m *mockK8sClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { + ret := _m.Called(obj) + + if len(ret) == 0 { + panic("no return value specified for GroupVersionKindFor") + } + + var r0 schema.GroupVersionKind + var r1 error + if rf, ok := ret.Get(0).(func(runtime.Object) (schema.GroupVersionKind, error)); ok { + return rf(obj) + } + if rf, ok := ret.Get(0).(func(runtime.Object) schema.GroupVersionKind); ok { + r0 = rf(obj) + } else { + r0 = ret.Get(0).(schema.GroupVersionKind) + } + + if rf, ok := ret.Get(1).(func(runtime.Object) error); ok { + r1 = rf(obj) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockK8sClient_GroupVersionKindFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GroupVersionKindFor' +type mockK8sClient_GroupVersionKindFor_Call struct { + *mock.Call +} + +// GroupVersionKindFor is a helper method to define mock.On call +// - obj runtime.Object +func (_e *mockK8sClient_Expecter) GroupVersionKindFor(obj interface{}) *mockK8sClient_GroupVersionKindFor_Call { + return &mockK8sClient_GroupVersionKindFor_Call{Call: _e.mock.On("GroupVersionKindFor", obj)} +} + +func (_c *mockK8sClient_GroupVersionKindFor_Call) Run(run func(obj runtime.Object)) *mockK8sClient_GroupVersionKindFor_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(runtime.Object)) + }) + return _c +} + +func (_c *mockK8sClient_GroupVersionKindFor_Call) Return(_a0 schema.GroupVersionKind, _a1 error) *mockK8sClient_GroupVersionKindFor_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockK8sClient_GroupVersionKindFor_Call) RunAndReturn(run func(runtime.Object) (schema.GroupVersionKind, error)) *mockK8sClient_GroupVersionKindFor_Call { + _c.Call.Return(run) + return _c +} + +// IsObjectNamespaced provides a mock function with given fields: obj +func (_m *mockK8sClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { + ret := _m.Called(obj) + + if len(ret) == 0 { + panic("no return value specified for IsObjectNamespaced") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(runtime.Object) (bool, error)); ok { + return rf(obj) + } + if rf, ok := ret.Get(0).(func(runtime.Object) bool); ok { + r0 = rf(obj) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(runtime.Object) error); ok { + r1 = rf(obj) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockK8sClient_IsObjectNamespaced_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsObjectNamespaced' +type mockK8sClient_IsObjectNamespaced_Call struct { + *mock.Call +} + +// IsObjectNamespaced is a helper method to define mock.On call +// - obj runtime.Object +func (_e *mockK8sClient_Expecter) IsObjectNamespaced(obj interface{}) *mockK8sClient_IsObjectNamespaced_Call { + return &mockK8sClient_IsObjectNamespaced_Call{Call: _e.mock.On("IsObjectNamespaced", obj)} +} + +func (_c *mockK8sClient_IsObjectNamespaced_Call) Run(run func(obj runtime.Object)) *mockK8sClient_IsObjectNamespaced_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(runtime.Object)) + }) + return _c +} + +func (_c *mockK8sClient_IsObjectNamespaced_Call) Return(_a0 bool, _a1 error) *mockK8sClient_IsObjectNamespaced_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockK8sClient_IsObjectNamespaced_Call) RunAndReturn(run func(runtime.Object) (bool, error)) *mockK8sClient_IsObjectNamespaced_Call { + _c.Call.Return(run) + return _c +} + +// List provides a mock function with given fields: ctx, list, opts +func (_m *mockK8sClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, list) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for List") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.ObjectList, ...client.ListOption) error); ok { + r0 = rf(ctx, list, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' +type mockK8sClient_List_Call struct { + *mock.Call +} + +// List is a helper method to define mock.On call +// - ctx context.Context +// - list client.ObjectList +// - opts ...client.ListOption +func (_e *mockK8sClient_Expecter) List(ctx interface{}, list interface{}, opts ...interface{}) *mockK8sClient_List_Call { + return &mockK8sClient_List_Call{Call: _e.mock.On("List", + append([]interface{}{ctx, list}, opts...)...)} +} + +func (_c *mockK8sClient_List_Call) Run(run func(ctx context.Context, list client.ObjectList, opts ...client.ListOption)) *mockK8sClient_List_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.ListOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.ListOption) + } + } + run(args[0].(context.Context), args[1].(client.ObjectList), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_List_Call) Return(_a0 error) *mockK8sClient_List_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_List_Call) RunAndReturn(run func(context.Context, client.ObjectList, ...client.ListOption) error) *mockK8sClient_List_Call { + _c.Call.Return(run) + return _c +} + +// Patch provides a mock function with given fields: ctx, obj, patch, opts +func (_m *mockK8sClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj, patch) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Patch") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, client.Patch, ...client.PatchOption) error); ok { + r0 = rf(ctx, obj, patch, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_Patch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Patch' +type mockK8sClient_Patch_Call struct { + *mock.Call +} + +// Patch is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - patch client.Patch +// - opts ...client.PatchOption +func (_e *mockK8sClient_Expecter) Patch(ctx interface{}, obj interface{}, patch interface{}, opts ...interface{}) *mockK8sClient_Patch_Call { + return &mockK8sClient_Patch_Call{Call: _e.mock.On("Patch", + append([]interface{}{ctx, obj, patch}, opts...)...)} +} + +func (_c *mockK8sClient_Patch_Call) Run(run func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption)) *mockK8sClient_Patch_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.PatchOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(client.PatchOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), args[2].(client.Patch), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_Patch_Call) Return(_a0 error) *mockK8sClient_Patch_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Patch_Call) RunAndReturn(run func(context.Context, client.Object, client.Patch, ...client.PatchOption) error) *mockK8sClient_Patch_Call { + _c.Call.Return(run) + return _c +} + +// RESTMapper provides a mock function with given fields: +func (_m *mockK8sClient) RESTMapper() meta.RESTMapper { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for RESTMapper") + } + + var r0 meta.RESTMapper + if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(meta.RESTMapper) + } + } + + return r0 +} + +// mockK8sClient_RESTMapper_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RESTMapper' +type mockK8sClient_RESTMapper_Call struct { + *mock.Call +} + +// RESTMapper is a helper method to define mock.On call +func (_e *mockK8sClient_Expecter) RESTMapper() *mockK8sClient_RESTMapper_Call { + return &mockK8sClient_RESTMapper_Call{Call: _e.mock.On("RESTMapper")} +} + +func (_c *mockK8sClient_RESTMapper_Call) Run(run func()) *mockK8sClient_RESTMapper_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockK8sClient_RESTMapper_Call) Return(_a0 meta.RESTMapper) *mockK8sClient_RESTMapper_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_RESTMapper_Call) RunAndReturn(run func() meta.RESTMapper) *mockK8sClient_RESTMapper_Call { + _c.Call.Return(run) + return _c +} + +// Scheme provides a mock function with given fields: +func (_m *mockK8sClient) Scheme() *runtime.Scheme { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Scheme") + } + + var r0 *runtime.Scheme + if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*runtime.Scheme) + } + } + + return r0 +} + +// mockK8sClient_Scheme_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Scheme' +type mockK8sClient_Scheme_Call struct { + *mock.Call +} + +// Scheme is a helper method to define mock.On call +func (_e *mockK8sClient_Expecter) Scheme() *mockK8sClient_Scheme_Call { + return &mockK8sClient_Scheme_Call{Call: _e.mock.On("Scheme")} +} + +func (_c *mockK8sClient_Scheme_Call) Run(run func()) *mockK8sClient_Scheme_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockK8sClient_Scheme_Call) Return(_a0 *runtime.Scheme) *mockK8sClient_Scheme_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Scheme_Call) RunAndReturn(run func() *runtime.Scheme) *mockK8sClient_Scheme_Call { + _c.Call.Return(run) + return _c +} + +// Status provides a mock function with given fields: +func (_m *mockK8sClient) Status() client.SubResourceWriter { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Status") + } + + var r0 client.SubResourceWriter + if rf, ok := ret.Get(0).(func() client.SubResourceWriter); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.SubResourceWriter) + } + } + + return r0 +} + +// mockK8sClient_Status_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Status' +type mockK8sClient_Status_Call struct { + *mock.Call +} + +// Status is a helper method to define mock.On call +func (_e *mockK8sClient_Expecter) Status() *mockK8sClient_Status_Call { + return &mockK8sClient_Status_Call{Call: _e.mock.On("Status")} +} + +func (_c *mockK8sClient_Status_Call) Run(run func()) *mockK8sClient_Status_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockK8sClient_Status_Call) Return(_a0 client.SubResourceWriter) *mockK8sClient_Status_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Status_Call) RunAndReturn(run func() client.SubResourceWriter) *mockK8sClient_Status_Call { + _c.Call.Return(run) + return _c +} + +// SubResource provides a mock function with given fields: subResource +func (_m *mockK8sClient) SubResource(subResource string) client.SubResourceClient { + ret := _m.Called(subResource) + + if len(ret) == 0 { + panic("no return value specified for SubResource") + } + + var r0 client.SubResourceClient + if rf, ok := ret.Get(0).(func(string) client.SubResourceClient); ok { + r0 = rf(subResource) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.SubResourceClient) + } + } + + return r0 +} + +// mockK8sClient_SubResource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubResource' +type mockK8sClient_SubResource_Call struct { + *mock.Call +} + +// SubResource is a helper method to define mock.On call +// - subResource string +func (_e *mockK8sClient_Expecter) SubResource(subResource interface{}) *mockK8sClient_SubResource_Call { + return &mockK8sClient_SubResource_Call{Call: _e.mock.On("SubResource", subResource)} +} + +func (_c *mockK8sClient_SubResource_Call) Run(run func(subResource string)) *mockK8sClient_SubResource_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *mockK8sClient_SubResource_Call) Return(_a0 client.SubResourceClient) *mockK8sClient_SubResource_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_SubResource_Call) RunAndReturn(run func(string) client.SubResourceClient) *mockK8sClient_SubResource_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, obj, opts +func (_m *mockK8sClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.UpdateOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockK8sClient_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type mockK8sClient_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.UpdateOption +func (_e *mockK8sClient_Expecter) Update(ctx interface{}, obj interface{}, opts ...interface{}) *mockK8sClient_Update_Call { + return &mockK8sClient_Update_Call{Call: _e.mock.On("Update", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *mockK8sClient_Update_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.UpdateOption)) *mockK8sClient_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.UpdateOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.UpdateOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *mockK8sClient_Update_Call) Return(_a0 error) *mockK8sClient_Update_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockK8sClient_Update_Call) RunAndReturn(run func(context.Context, client.Object, ...client.UpdateOption) error) *mockK8sClient_Update_Call { + _c.Call.Return(run) + return _c +} + +// newMockK8sClient creates a new instance of mockK8sClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockK8sClient(t interface { + mock.TestingT + Cleanup(func()) +}) *mockK8sClient { + mock := &mockK8sClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/warp/mock_logSink_test.go b/controllers/warp/mock_logSink_test.go new file mode 100644 index 0000000..88eeeea --- /dev/null +++ b/controllers/warp/mock_logSink_test.go @@ -0,0 +1,298 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package warp + +import ( + logr "github.com/go-logr/logr" + mock "github.com/stretchr/testify/mock" +) + +// MockLogSink is an autogenerated mock type for the LogSink type +type MockLogSink struct { + mock.Mock +} + +type MockLogSink_Expecter struct { + mock *mock.Mock +} + +func (_m *MockLogSink) EXPECT() *MockLogSink_Expecter { + return &MockLogSink_Expecter{mock: &_m.Mock} +} + +// Enabled provides a mock function with given fields: level +func (_m *MockLogSink) Enabled(level int) bool { + ret := _m.Called(level) + + var r0 bool + if rf, ok := ret.Get(0).(func(int) bool); ok { + r0 = rf(level) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLogSink_Enabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Enabled' +type MockLogSink_Enabled_Call struct { + *mock.Call +} + +// Enabled is a helper method to define mock.On call +// - level int +func (_e *MockLogSink_Expecter) Enabled(level interface{}) *MockLogSink_Enabled_Call { + return &MockLogSink_Enabled_Call{Call: _e.mock.On("Enabled", level)} +} + +func (_c *MockLogSink_Enabled_Call) Run(run func(level int)) *MockLogSink_Enabled_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int)) + }) + return _c +} + +func (_c *MockLogSink_Enabled_Call) Return(_a0 bool) *MockLogSink_Enabled_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLogSink_Enabled_Call) RunAndReturn(run func(int) bool) *MockLogSink_Enabled_Call { + _c.Call.Return(run) + return _c +} + +// Error provides a mock function with given fields: err, msg, keysAndValues +func (_m *MockLogSink) Error(err error, msg string, keysAndValues ...interface{}) { + var _ca []interface{} + _ca = append(_ca, err, msg) + _ca = append(_ca, keysAndValues...) + _m.Called(_ca...) +} + +// MockLogSink_Error_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Error' +type MockLogSink_Error_Call struct { + *mock.Call +} + +// Error is a helper method to define mock.On call +// - err error +// - msg string +// - keysAndValues ...interface{} +func (_e *MockLogSink_Expecter) Error(err interface{}, msg interface{}, keysAndValues ...interface{}) *MockLogSink_Error_Call { + return &MockLogSink_Error_Call{Call: _e.mock.On("Error", + append([]interface{}{err, msg}, keysAndValues...)...)} +} + +func (_c *MockLogSink_Error_Call) Run(run func(err error, msg string, keysAndValues ...interface{})) *MockLogSink_Error_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(error), args[1].(string), variadicArgs...) + }) + return _c +} + +func (_c *MockLogSink_Error_Call) Return() *MockLogSink_Error_Call { + _c.Call.Return() + return _c +} + +func (_c *MockLogSink_Error_Call) RunAndReturn(run func(error, string, ...interface{})) *MockLogSink_Error_Call { + _c.Call.Return(run) + return _c +} + +// Info provides a mock function with given fields: level, msg, keysAndValues +func (_m *MockLogSink) Info(level int, msg string, keysAndValues ...interface{}) { + var _ca []interface{} + _ca = append(_ca, level, msg) + _ca = append(_ca, keysAndValues...) + _m.Called(_ca...) +} + +// MockLogSink_Info_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Info' +type MockLogSink_Info_Call struct { + *mock.Call +} + +// Info is a helper method to define mock.On call +// - level int +// - msg string +// - keysAndValues ...interface{} +func (_e *MockLogSink_Expecter) Info(level interface{}, msg interface{}, keysAndValues ...interface{}) *MockLogSink_Info_Call { + return &MockLogSink_Info_Call{Call: _e.mock.On("Info", + append([]interface{}{level, msg}, keysAndValues...)...)} +} + +func (_c *MockLogSink_Info_Call) Run(run func(level int, msg string, keysAndValues ...interface{})) *MockLogSink_Info_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(int), args[1].(string), variadicArgs...) + }) + return _c +} + +func (_c *MockLogSink_Info_Call) Return() *MockLogSink_Info_Call { + _c.Call.Return() + return _c +} + +func (_c *MockLogSink_Info_Call) RunAndReturn(run func(int, string, ...interface{})) *MockLogSink_Info_Call { + _c.Call.Return(run) + return _c +} + +// Init provides a mock function with given fields: info +func (_m *MockLogSink) Init(info logr.RuntimeInfo) { + _m.Called(info) +} + +// MockLogSink_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init' +type MockLogSink_Init_Call struct { + *mock.Call +} + +// Init is a helper method to define mock.On call +// - info logr.RuntimeInfo +func (_e *MockLogSink_Expecter) Init(info interface{}) *MockLogSink_Init_Call { + return &MockLogSink_Init_Call{Call: _e.mock.On("Init", info)} +} + +func (_c *MockLogSink_Init_Call) Run(run func(info logr.RuntimeInfo)) *MockLogSink_Init_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(logr.RuntimeInfo)) + }) + return _c +} + +func (_c *MockLogSink_Init_Call) Return() *MockLogSink_Init_Call { + _c.Call.Return() + return _c +} + +func (_c *MockLogSink_Init_Call) RunAndReturn(run func(logr.RuntimeInfo)) *MockLogSink_Init_Call { + _c.Call.Return(run) + return _c +} + +// WithName provides a mock function with given fields: name +func (_m *MockLogSink) WithName(name string) logr.LogSink { + ret := _m.Called(name) + + var r0 logr.LogSink + if rf, ok := ret.Get(0).(func(string) logr.LogSink); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(logr.LogSink) + } + } + + return r0 +} + +// MockLogSink_WithName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithName' +type MockLogSink_WithName_Call struct { + *mock.Call +} + +// WithName is a helper method to define mock.On call +// - name string +func (_e *MockLogSink_Expecter) WithName(name interface{}) *MockLogSink_WithName_Call { + return &MockLogSink_WithName_Call{Call: _e.mock.On("WithName", name)} +} + +func (_c *MockLogSink_WithName_Call) Run(run func(name string)) *MockLogSink_WithName_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLogSink_WithName_Call) Return(_a0 logr.LogSink) *MockLogSink_WithName_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLogSink_WithName_Call) RunAndReturn(run func(string) logr.LogSink) *MockLogSink_WithName_Call { + _c.Call.Return(run) + return _c +} + +// WithValues provides a mock function with given fields: keysAndValues +func (_m *MockLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { + var _ca []interface{} + _ca = append(_ca, keysAndValues...) + ret := _m.Called(_ca...) + + var r0 logr.LogSink + if rf, ok := ret.Get(0).(func(...interface{}) logr.LogSink); ok { + r0 = rf(keysAndValues...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(logr.LogSink) + } + } + + return r0 +} + +// MockLogSink_WithValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithValues' +type MockLogSink_WithValues_Call struct { + *mock.Call +} + +// WithValues is a helper method to define mock.On call +// - keysAndValues ...interface{} +func (_e *MockLogSink_Expecter) WithValues(keysAndValues ...interface{}) *MockLogSink_WithValues_Call { + return &MockLogSink_WithValues_Call{Call: _e.mock.On("WithValues", + append([]interface{}{}, keysAndValues...)...)} +} + +func (_c *MockLogSink_WithValues_Call) Run(run func(keysAndValues ...interface{})) *MockLogSink_WithValues_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *MockLogSink_WithValues_Call) Return(_a0 logr.LogSink) *MockLogSink_WithValues_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLogSink_WithValues_Call) RunAndReturn(run func(...interface{}) logr.LogSink) *MockLogSink_WithValues_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockLogSink interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockLogSink creates a new instance of MockLogSink. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockLogSink(t mockConstructorTestingTNewMockLogSink) *MockLogSink { + mock := &MockLogSink{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/warp/mock_watchConfigurationContext_test.go b/controllers/warp/mock_watchConfigurationContext_test.go deleted file mode 100644 index 3f1d9f8..0000000 --- a/controllers/warp/mock_watchConfigurationContext_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package warp - -import ( - context "context" - - client "go.etcd.io/etcd/client/v2" - - mock "github.com/stretchr/testify/mock" -) - -// mockWatchConfigurationContext is an autogenerated mock type for the watchConfigurationContext type -type mockWatchConfigurationContext struct { - mock.Mock -} - -type mockWatchConfigurationContext_Expecter struct { - mock *mock.Mock -} - -func (_m *mockWatchConfigurationContext) EXPECT() *mockWatchConfigurationContext_Expecter { - return &mockWatchConfigurationContext_Expecter{mock: &_m.Mock} -} - -// Get provides a mock function with given fields: key -func (_m *mockWatchConfigurationContext) Get(key string) (string, error) { - ret := _m.Called(key) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(key) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfigurationContext_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type mockWatchConfigurationContext_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfigurationContext_Expecter) Get(key interface{}) *mockWatchConfigurationContext_Get_Call { - return &mockWatchConfigurationContext_Get_Call{Call: _e.mock.On("Get", key)} -} - -func (_c *mockWatchConfigurationContext_Get_Call) Run(run func(key string)) *mockWatchConfigurationContext_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_Get_Call) Return(_a0 string, _a1 error) *mockWatchConfigurationContext_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfigurationContext_Get_Call) RunAndReturn(run func(string) (string, error)) *mockWatchConfigurationContext_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetChildrenPaths provides a mock function with given fields: key -func (_m *mockWatchConfigurationContext) GetChildrenPaths(key string) ([]string, error) { - ret := _m.Called(key) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { - return rf(key) - } - if rf, ok := ret.Get(0).(func(string) []string); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockWatchConfigurationContext_GetChildrenPaths_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChildrenPaths' -type mockWatchConfigurationContext_GetChildrenPaths_Call struct { - *mock.Call -} - -// GetChildrenPaths is a helper method to define mock.On call -// - key string -func (_e *mockWatchConfigurationContext_Expecter) GetChildrenPaths(key interface{}) *mockWatchConfigurationContext_GetChildrenPaths_Call { - return &mockWatchConfigurationContext_GetChildrenPaths_Call{Call: _e.mock.On("GetChildrenPaths", key)} -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) Run(run func(key string)) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) Return(_a0 []string, _a1 error) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockWatchConfigurationContext_GetChildrenPaths_Call) RunAndReturn(run func(string) ([]string, error)) *mockWatchConfigurationContext_GetChildrenPaths_Call { - _c.Call.Return(run) - return _c -} - -// Watch provides a mock function with given fields: ctx, key, recursive, eventChannel -func (_m *mockWatchConfigurationContext) Watch(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response) { - _m.Called(ctx, key, recursive, eventChannel) -} - -// mockWatchConfigurationContext_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' -type mockWatchConfigurationContext_Watch_Call struct { - *mock.Call -} - -// Watch is a helper method to define mock.On call -// - ctx context.Context -// - key string -// - recursive bool -// - eventChannel chan *client.Response -func (_e *mockWatchConfigurationContext_Expecter) Watch(ctx interface{}, key interface{}, recursive interface{}, eventChannel interface{}) *mockWatchConfigurationContext_Watch_Call { - return &mockWatchConfigurationContext_Watch_Call{Call: _e.mock.On("Watch", ctx, key, recursive, eventChannel)} -} - -func (_c *mockWatchConfigurationContext_Watch_Call) Run(run func(ctx context.Context, key string, recursive bool, eventChannel chan *client.Response)) *mockWatchConfigurationContext_Watch_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(bool), args[3].(chan *client.Response)) - }) - return _c -} - -func (_c *mockWatchConfigurationContext_Watch_Call) Return() *mockWatchConfigurationContext_Watch_Call { - _c.Call.Return() - return _c -} - -func (_c *mockWatchConfigurationContext_Watch_Call) RunAndReturn(run func(context.Context, string, bool, chan *client.Response)) *mockWatchConfigurationContext_Watch_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockWatchConfigurationContext interface { - mock.TestingT - Cleanup(func()) -} - -// newMockWatchConfigurationContext creates a new instance of mockWatchConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockWatchConfigurationContext(t mockConstructorTestingTnewMockWatchConfigurationContext) *mockWatchConfigurationContext { - mock := &mockWatchConfigurationContext{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/controllers/warp/testdata/jenkins.json b/controllers/warp/testdata/jenkins.json new file mode 100644 index 0000000..9040ff0 --- /dev/null +++ b/controllers/warp/testdata/jenkins.json @@ -0,0 +1,186 @@ +{ + "Name": "official/jenkins", + "Version": "2.452.2-1", + "DisplayName": "Jenkins CI", + "Description": "Jenkins Continuous Integration Server", + "Category": "Development Apps", + "Tags": [ + "warp", + "build", + "ci", + "cd" + ], + "Logo": "https://cloudogu.com/images/dogus/jenkins.png", + "Url": "https://jenkins-ci.org", + "Image": "registry.cloudogu.com/official/jenkins", + "Dependencies": [ + { + "type": "dogu", + "name": "cas" + }, + { + "type": "dogu", + "name": "nginx" + }, + { + "type": "dogu", + "name": "postfix" + } + ], + "Volumes": [ + { + "Name": "data", + "Path": "/var/lib/jenkins", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "custom.init.groovy.d", + "Path": "/var/lib/custom.init.groovy.d", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "tmp", + "Path": "/tmp", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": false + } + ], + "Configuration": [ + { + "Name": "additional.plugins", + "Description": "Comma separated list of plugin names to install on start", + "Optional": true + }, + { + "Name": "container_config/memory_limit", + "Description": "Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/swap_limit", + "Description": "Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/java_max_ram_percentage", + "Description": "Limits the heap stack size of the Jenkins process to the configured percentage of the available physical memory when the container has more than approx. 250 MB of memory available. Is only considered when a memory_limit is set. Use a valid float value with decimals between 0 and 100 (f. ex. 55.0 for 55%). Default value for Jenkins: 25%", + "Optional": true, + "Default": "25.0", + "Validation": { + "Type": "FLOAT_PERCENTAGE_HUNDRED" + } + }, + { + "Name": "container_config/java_min_ram_percentage", + "Description": "Limits the heap stack size of the Jenkins process to the configured percentage of the available physical memory when the container has less than approx. 250 MB of memory available. Is only considered when a memory_limit is set. Use a valid float value with decimals between 0 and 100 (f. ex. 55.0 for 55%). Default value for Jenkins: 50%", + "Optional": true, + "Default": "50.0", + "Validation": { + "Type": "FLOAT_PERCENTAGE_HUNDRED" + } + }, + { + "Name": "container_config/memory_limit", + "Description": "Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/memory_request", + "Description": "Requests the container's minimal memory requirement. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + }, + "Default": "2g" + }, + { + "Name": "container_config/swap_limit", + "Description": "Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/cpu_core_limit", + "Description": "Limits the container's CPU core usage. Use a positive floating value describing a fraction of 1 CPU core. When you define a value of '0.5', you are requesting half as much CPU time compared to if you asked for '1.0' CPU.", + "Optional": true + }, + { + "Name": "container_config/cpu_core_request", + "Description": "Requests the container's minimal CPU core requirement. Use a positive floating value describing a fraction of 1 CPU core. When you define a value of '0.5', you are requesting half as much CPU time compared to if you asked for '1.0' CPU.", + "Optional": true, + "Default": "1.0" + }, + { + "Name": "container_config/storage_limit", + "Description": "Limits the container's ephemeral storage usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/storage_request", + "Description": "Requests the container's minimal ephemeral storage requirement. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "additional_java_args", + "Description": "Additional args that are passed to the jenkins process.", + "Optional": true, + "Default": "UNSET" + }, + { + "Name": "logging/root", + "Description": "Set the root log level to one of ERROR, WARN, INFO, DEBUG.", + "Optional": true, + "Default": "INFO", + "Validation": { + "Type": "ONE_OF", + "Values": [ + "WARN", + "DEBUG", + "INFO", + "ERROR" + ] + } + } + ], + "ExposedCommands": [ + { + "Name": "upgrade-notification", + "Command": "/upgrade-notification.sh" + }, + { + "Name": "pre-upgrade", + "Command": "/pre-upgrade.sh" + } + ], + "HealthChecks": [ + { + "Type": "tcp", + "Port": 8080 + }, + { + "Type": "state" + } + ] +} \ No newline at end of file diff --git a/controllers/warp/testdata/k8s_config.yaml b/controllers/warp/testdata/k8s_config.yaml index 044d957..710901b 100644 --- a/controllers/warp/testdata/k8s_config.yaml +++ b/controllers/warp/testdata/k8s_config.yaml @@ -14,10 +14,8 @@ data: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -28,6 +26,6 @@ data: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com diff --git a/controllers/warp/testdata/redmine.json b/controllers/warp/testdata/redmine.json new file mode 100644 index 0000000..c1fdda9 --- /dev/null +++ b/controllers/warp/testdata/redmine.json @@ -0,0 +1,128 @@ +{ + "Name": "official/redmine", + "Version": "5.1.3-1", + "DisplayName": "Redmine", + "Description": "Redmine is a flexible project management web application", + "Category": "Development Apps", + "Tags": [ + "warp", + "pm", + "projectmanagement", + "issue", + "task" + ], + "Logo": "https://cloudogu.com/images/dogus/redmine.png", + "Url": "http://www.redmine.org", + "Image": "registry.cloudogu.com/official/redmine", + "Dependencies": [ + { + "type": "dogu", + "name": "postgresql" + }, + { + "type": "dogu", + "name": "cas" + }, + { + "type": "dogu", + "name": "nginx" + }, + { + "type": "dogu", + "name": "postfix" + } + ], + "Configuration": [ + { + "Name": "logging/root", + "Description": "Set the root log level to one of ERROR, WARN, INFO, DEBUG.", + "Optional": true, + "Default": "INFO", + "Validation": { + "Type": "ONE_OF", + "Values": [ + "WARN", + "DEBUG", + "INFO", + "ERROR" + ] + } + }, + { + "Name": "container_config/memory_limit", + "Description": "Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/swap_limit", + "Description": "Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "redmine_dogu_config", + "Description": "Applies default configuration to redmine.", + "Optional": true + } + ], + "Volumes": [ + { + "Name": "files", + "Path": "/usr/share/webapps/redmine/files", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "plugins", + "Path": "/var/tmp/redmine/plugins", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "logs", + "Path": "/usr/share/webapps/redmine/log", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": false + } + ], + "ServiceAccounts": [ + { + "Type": "postgresql" + } + ], + "HealthChecks": [ + { + "Type": "tcp", + "Port": 3000 + }, + { + "Type": "state" + } + ], + "ExposedCommands": [ + { + "Name": "post-upgrade", + "Command": "/post-upgrade.sh" + }, + { + "Name": "upgrade-notification", + "Command": "/upgrade-notification.sh" + }, + { + "Name": "pre-upgrade", + "Command": "/pre-upgrade.sh" + }, + { + "Name": "delete-plugin", + "Command": "/delete-plugin.sh" + } + ] +} \ No newline at end of file diff --git a/controllers/warp/testdata_test.go b/controllers/warp/testdata_test.go new file mode 100644 index 0000000..033b900 --- /dev/null +++ b/controllers/warp/testdata_test.go @@ -0,0 +1,38 @@ +package warp + +import ( + "encoding/json" + "github.com/cloudogu/cesapp-lib/core" + "testing" +) + +func readRedmineDogu(t *testing.T) *core.Dogu { + t.Helper() + dogu := &core.Dogu{} + err := json.Unmarshal(redmineBytes, dogu) + if err != nil { + t.Fatal(err.Error()) + } + + return dogu +} + +func readJenkinsDogu(t *testing.T) *core.Dogu { + t.Helper() + dogu := &core.Dogu{} + err := json.Unmarshal(jenkinsBytes, dogu) + if err != nil { + t.Fatal(err.Error()) + } + + return dogu +} +func parseVersion(t *testing.T, version string) *core.Version { + t.Helper() + v, err := core.ParseVersion(version) + if err != nil { + t.Fatal(err.Error()) + } + + return &v +} diff --git a/controllers/warp/types/dogu_entry.go b/controllers/warp/types/dogu_entry.go index fc34b2b..1f6f8ae 100644 --- a/controllers/warp/types/dogu_entry.go +++ b/controllers/warp/types/dogu_entry.go @@ -1,15 +1,17 @@ package types import ( - "encoding/json" - "fmt" + "github.com/cloudogu/cesapp-lib/core" "github.com/cloudogu/cesapp-lib/registry" - "go.etcd.io/etcd/client/v2" "strings" "github.com/pkg/errors" ) +type WatchConfigurationContext interface { + registry.WatchConfigurationContext +} + type doguEntry struct { Name string DisplayName string @@ -18,25 +20,12 @@ type doguEntry struct { Tags []string } -type WatchConfigurationContext interface { - registry.WatchConfigurationContext -} - // DoguConverter converts dogus from the configuration to a warp menu category object type DoguConverter struct{} -// ReadAndUnmarshalDogu reads the dogu from the configuration. If it has the specific tag (or no tag) it will be -// converted to entry with a category for the warp menu -func (dc *DoguConverter) ReadAndUnmarshalDogu(registry WatchConfigurationContext, key string, tag string) (EntryWithCategory, error) { - doguBytes, err := readDoguAsBytes(registry, key) - if err != nil { - return EntryWithCategory{}, err - } - - doguEntry, err := unmarshalDogu(doguBytes) - if err != nil { - return EntryWithCategory{}, err - } +// CreateEntryWithCategoryFromDogu returns a doguEntry with category if the dogu has the tag specified as parameter. +func (dc *DoguConverter) CreateEntryWithCategoryFromDogu(dogu *core.Dogu, tag string) (EntryWithCategory, error) { + doguEntry := doguEntryFromDogu(dogu) if tag == "" || containsString(doguEntry.Tags, tag) { return mapDoguEntry(doguEntry) @@ -45,31 +34,14 @@ func (dc *DoguConverter) ReadAndUnmarshalDogu(registry WatchConfigurationContext return EntryWithCategory{}, nil } -func readDoguAsBytes(registry WatchConfigurationContext, key string) ([]byte, error) { - version, err := registry.Get(key + "/current") - if err != nil { - // the dogu seems to be unregistered - if isKeyNotFound(err) { - return nil, nil - } - return nil, fmt.Errorf("failed to read key %s/current from etcd: %w", key, err) - } - - dogu, err := registry.Get(key + "/" + version) - if err != nil { - return nil, fmt.Errorf("failed to read %s with version %s: %w", key, version, err) +func doguEntryFromDogu(dogu *core.Dogu) doguEntry { + return doguEntry{ + Name: dogu.Name, + DisplayName: dogu.DisplayName, + Description: dogu.Description, + Category: dogu.Category, + Tags: dogu.Tags, } - - return []byte(dogu), nil -} - -func unmarshalDogu(doguBytes []byte) (doguEntry, error) { - doguEntry := doguEntry{} - err := json.Unmarshal(doguBytes, &doguEntry) - if err != nil { - return doguEntry, fmt.Errorf("failed to unmarshall json from etcd: %w", err) - } - return doguEntry, nil } func mapDoguEntry(entry doguEntry) (EntryWithCategory, error) { @@ -108,10 +80,3 @@ func containsString(slice []string, item string) bool { } return false } - -func isKeyNotFound(err error) bool { - if cErr, ok := err.(client.Error); ok { - return cErr.Code == client.ErrorCodeKeyNotFound - } - return false -} diff --git a/controllers/warp/types/dogu_entry_test.go b/controllers/warp/types/dogu_entry_test.go index 4bd4419..aea3657 100644 --- a/controllers/warp/types/dogu_entry_test.go +++ b/controllers/warp/types/dogu_entry_test.go @@ -1,12 +1,17 @@ package types import ( + _ "embed" + "fmt" + "github.com/cloudogu/cesapp-lib/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v2" "testing" ) +//go:embed testdata/redmine.json +var redmineBytes []byte + func Test_containsString(t *testing.T) { t.Run("success", func(t *testing.T) { // given @@ -46,59 +51,6 @@ func Test_createDoguHref(t *testing.T) { }) } -func Test_isKeyNotFound(t *testing.T) { - t.Run("return true on code key not found", func(t *testing.T) { - // given - err := etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound} - - // when - result := isKeyNotFound(err) - - // then - assert.True(t, result) - }) - - t.Run("return false on wrong error type", func(t *testing.T) { - // given - err := assert.AnError - - // when - result := isKeyNotFound(err) - - // then - assert.False(t, result) - }) - - tests := []struct { - name string - key int - want bool - }{ - {name: "error on !key not found", key: etcdclient.ErrorCodeDirNotEmpty, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeTestFailed, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeNotFile, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeNotDir, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeNodeExist, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeRootROnly, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeUnauthorized, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodePrevValueRequired, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeTTLNaN, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeIndexNaN, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeInvalidField, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeInvalidForm, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeRaftInternal, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeLeaderElect, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeWatcherCleared, want: false}, - {name: "error on !key not found", key: etcdclient.ErrorCodeEventIndexCleared, want: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := etcdclient.Error{Code: tt.key} - assert.Equalf(t, tt.want, isKeyNotFound(err), "isKeyNotFound(%v)") - }) - } -} - func Test_mapDoguEntry(t *testing.T) { t.Run("success", func(t *testing.T) { // given @@ -145,192 +97,60 @@ func Test_mapDoguEntry(t *testing.T) { }) } -func Test_readAndUnmarshalDogu(t *testing.T) { - doguEntry := doguEntry{Name: "official/redmine", DisplayName: "Redmine", Category: "Development Apps", Description: "Redmine"} - doguStr := "{\n \"Name\": \"official/redmine\",\n \"Version\": \"1.0.0-1\",\n \"DisplayName\": \"Redmine\",\n \"Description\": \"Redmine\",\n \"Category\": \"Development Apps\",\n \"Tags\": [\n \"warp\",\n \"pm\",\n \"projectmanagement\",\n \"issue\",\n \"task\"\n ],\n \"Logo\": \"https://cloudogu.com/images/dogus/redmine.png\",\n \"Url\": \"http://www.redmine.org\",\n \"Image\": \"registry.cloudogu.com/official/redmine\",\n \"Dependencies\": [\n {\n \"type\": \"dogu\",\n \"name\": \"postgresql\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"cas\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"nginx\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"postfix\"\n }\n ],\n \"Configuration\": [\n {\n \"Name\": \"logging/root\",\n \"Description\": \"Set the root log level to one of ERROR, WARN, INFO, DEBUG.\",\n \"Optional\": true,\n \"Default\": \"INFO\",\n \"Validation\": {\n \"Type\": \"ONE_OF\",\n \"Values\": [\n \"WARN\",\n \"DEBUG\",\n \"INFO\",\n \"ERROR\"\n ]\n }\n },\n {\n \"Name\": \"container_config/memory_limit\",\n \"Description\": \"Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).\",\n \"Optional\": true,\n \"Validation\": {\n \"Type\": \"BINARY_MEASUREMENT\"\n }\n },\n {\n \"Name\": \"container_config/swap_limit\",\n \"Description\": \"Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.\",\n \"Optional\": true,\n \"Validation\": {\n \"Type\": \"BINARY_MEASUREMENT\"\n }\n },\n {\n \"Name\": \"etcd_redmine_config\",\n \"Description\": \"Applies default configuration to redmine.\",\n \"Optional\": true\n }\n ],\n \"Volumes\": [\n {\n \"Name\": \"files\",\n \"Path\": \"/usr/share/webapps/redmine/files\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": true\n },\n {\n \"Name\": \"plugins\",\n \"Path\": \"/var/tmp/redmine/plugins\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": false\n },\n {\n \"Name\": \"logs\",\n \"Path\": \"/usr/share/webapps/redmine/log\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": false\n }\n ],\n \"ServiceAccounts\": [\n {\n \"Type\": \"postgresql\"\n }\n ],\n \"HealthChecks\": [\n {\n \"Type\": \"tcp\",\n \"Port\": 3000\n },\n {\n \"Type\": \"state\"\n }\n ],\n \"ExposedCommands\": [\n {\n \"Name\": \"post-upgrade\",\n \"Command\": \"/post-upgrade.sh\"\n },\n {\n \"Name\": \"upgrade-notification\",\n \"Command\": \"/upgrade-notification.sh\"\n },\n {\n \"Name\": \"pre-upgrade\",\n \"Command\": \"/pre-upgrade.sh\"\n },\n {\n \"Name\": \"delete-plugin\",\n \"Command\": \"/delete-plugin.sh\"\n }\n ]\n}" - t.Run("success with specific tag (warp)", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return(doguStr, nil) - converter := DoguConverter{} - - // when - entryWithCategory, err := converter.ReadAndUnmarshalDogu(registryMock, "dogu/redmine", "warp") - - // then - require.NoError(t, err) - assert.Equal(t, doguEntry.Category, entryWithCategory.Category) - assert.Equal(t, doguEntry.Description, entryWithCategory.Entry.Title) - assert.Equal(t, doguEntry.DisplayName, entryWithCategory.Entry.DisplayName) - assert.Equal(t, TARGET_SELF, entryWithCategory.Entry.Target) - assert.Equal(t, "/redmine", entryWithCategory.Entry.Href) - }) - - t.Run("success without specific tag", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return(doguStr, nil) - converter := DoguConverter{} - - // when - entryWithCategory, err := converter.ReadAndUnmarshalDogu(registryMock, "dogu/redmine", "") - - // then - require.NoError(t, err) - assert.Equal(t, doguEntry.Category, entryWithCategory.Category) - assert.Equal(t, doguEntry.Description, entryWithCategory.Entry.Title) - assert.Equal(t, doguEntry.DisplayName, entryWithCategory.Entry.DisplayName) - assert.Equal(t, TARGET_SELF, entryWithCategory.Entry.Target) - assert.Equal(t, "/redmine", entryWithCategory.Entry.Href) - }) - - t.Run("failed to read dogu as bytes", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("", assert.AnError) - converter := DoguConverter{} - - // when - _, err := converter.ReadAndUnmarshalDogu(registryMock, "dogu/redmine", "warp") - - // then - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to read key dogu/redmine/current from etcd") - }) - - t.Run("failed to unmarshal dogu", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return("fdsfsdf", nil) - converter := DoguConverter{} - - // when - _, err := converter.ReadAndUnmarshalDogu(registryMock, "dogu/redmine", "warp") - - // then - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to unmarshall json from etcd") - }) - - t.Run("return empty entry with category if the tag is not found", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return(doguStr, nil) - converter := DoguConverter{} - - // when - entryWithCategory, err := converter.ReadAndUnmarshalDogu(registryMock, "dogu/redmine", "dontbethere") - - // then - require.NoError(t, err) - assert.Equal(t, EntryWithCategory{}, entryWithCategory) - }) -} - -func Test_readDoguAsBytes(t *testing.T) { - t.Run("success", func(t *testing.T) { - // given - doguStr := "{\n \"Name\": \"official/redmine\",\n \"Version\": \"1.0.0-1\",\n \"DisplayName\": \"Redmine\",\n \"Description\": \"Redmine is a flexible project management web application\",\n \"Category\": \"Development Apps\",\n \"Tags\": [\n \"warp\",\n \"pm\",\n \"projectmanagement\",\n \"issue\",\n \"task\"\n ],\n \"Logo\": \"https://cloudogu.com/images/dogus/redmine.png\",\n \"Url\": \"http://www.redmine.org\",\n \"Image\": \"registry.cloudogu.com/official/redmine\",\n \"Dependencies\": [\n {\n \"type\": \"dogu\",\n \"name\": \"postgresql\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"cas\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"nginx\"\n },\n {\n \"type\": \"dogu\",\n \"name\": \"postfix\"\n }\n ],\n \"Configuration\": [\n {\n \"Name\": \"logging/root\",\n \"Description\": \"Set the root log level to one of ERROR, WARN, INFO, DEBUG.\",\n \"Optional\": true,\n \"Default\": \"INFO\",\n \"Validation\": {\n \"Type\": \"ONE_OF\",\n \"Values\": [\n \"WARN\",\n \"DEBUG\",\n \"INFO\",\n \"ERROR\"\n ]\n }\n },\n {\n \"Name\": \"container_config/memory_limit\",\n \"Description\": \"Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).\",\n \"Optional\": true,\n \"Validation\": {\n \"Type\": \"BINARY_MEASUREMENT\"\n }\n },\n {\n \"Name\": \"container_config/swap_limit\",\n \"Description\": \"Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.\",\n \"Optional\": true,\n \"Validation\": {\n \"Type\": \"BINARY_MEASUREMENT\"\n }\n },\n {\n \"Name\": \"etcd_redmine_config\",\n \"Description\": \"Applies default configuration to redmine.\",\n \"Optional\": true\n }\n ],\n \"Volumes\": [\n {\n \"Name\": \"files\",\n \"Path\": \"/usr/share/webapps/redmine/files\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": true\n },\n {\n \"Name\": \"plugins\",\n \"Path\": \"/var/tmp/redmine/plugins\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": false\n },\n {\n \"Name\": \"logs\",\n \"Path\": \"/usr/share/webapps/redmine/log\",\n \"Owner\": \"1000\",\n \"Group\": \"1000\",\n \"NeedsBackup\": false\n }\n ],\n \"ServiceAccounts\": [\n {\n \"Type\": \"postgresql\"\n }\n ],\n \"HealthChecks\": [\n {\n \"Type\": \"tcp\",\n \"Port\": 3000\n },\n {\n \"Type\": \"state\"\n }\n ],\n \"ExposedCommands\": [\n {\n \"Name\": \"post-upgrade\",\n \"Command\": \"/post-upgrade.sh\"\n },\n {\n \"Name\": \"upgrade-notification\",\n \"Command\": \"/upgrade-notification.sh\"\n },\n {\n \"Name\": \"pre-upgrade\",\n \"Command\": \"/pre-upgrade.sh\"\n },\n {\n \"Name\": \"delete-plugin\",\n \"Command\": \"/delete-plugin.sh\"\n }\n ]\n}" - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return(doguStr, nil) - - // when - bytes, err := readDoguAsBytes(registryMock, "dogu/redmine") - - // then - require.NoError(t, err) - assert.Equal(t, []byte(doguStr), bytes) - }) - - t.Run("no version should not return an error", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - testErr := etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound} - registryMock.EXPECT().Get("dogu/redmine/current").Return("", testErr) - - // when - bytes, err := readDoguAsBytes(registryMock, "dogu/redmine") - - // then - require.NoError(t, err) - require.Nil(t, bytes) - require.Nil(t, err) - }) - - t.Run("no version should not return an error", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - testErr := etcdclient.Error{Code: etcdclient.ErrorCodeKeyNotFound} - registryMock.EXPECT().Get("dogu/redmine/current").Return("", testErr) - - // when - bytes, err := readDoguAsBytes(registryMock, "dogu/redmine") - - // then - require.NoError(t, err) - require.Nil(t, bytes) - require.Nil(t, err) - }) - - t.Run("failed to get version", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("", assert.AnError) +func TestDoguConverter_CreateEntryWithCategoryFromDogu(t *testing.T) { + redmineDogu := readRedmineDogu(t) - // when - _, err := readDoguAsBytes(registryMock, "dogu/redmine") - - // then - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to read key dogu/redmine/current from etcd") - }) - - t.Run("failed to get dogu with version", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("dogu/redmine/current").Return("1.0.0-1", nil) - registryMock.EXPECT().Get("dogu/redmine/1.0.0-1").Return("", assert.AnError) - - // when - _, err := readDoguAsBytes(registryMock, "dogu/redmine") - - // then - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to read dogu/redmine with version 1.0.0-1") - }) -} - -func Test_unmarshalDogu(t *testing.T) { - t.Run("success", func(t *testing.T) { - // given - doguJsonStr := "{\n \"Name\": \"redmine\",\n \"DisplayName\": \"display\",\n \"Description\": \"desc\",\n \"Category\": \"category\",\n \"Tags\": [\n \"warp\",\n \"test\"\n ]\n}" - - // when - result, err := unmarshalDogu([]byte(doguJsonStr)) - - // then - require.NoError(t, err) - assert.Equal(t, "redmine", result.Name) - assert.Equal(t, "display", result.DisplayName) - assert.Equal(t, "desc", result.Description) - assert.Equal(t, "category", result.Category) - assert.Equal(t, "warp", result.Tags[0]) - assert.Equal(t, "test", result.Tags[1]) - }) - - t.Run("fail on wrong struct", func(t *testing.T) { - // given - doguJsonStr := "fsdfsd" - - // when - _, err := unmarshalDogu([]byte(doguJsonStr)) - - // then - require.Error(t, err) - }) + type args struct { + dogu *core.Dogu + tag string + } + tests := []struct { + name string + args args + want EntryWithCategory + wantErr assert.ErrorAssertionFunc + }{ + { + name: "should create entry with category with correct tag", + args: args{dogu: redmineDogu, tag: "warp"}, + want: EntryWithCategory{Entry: Entry{ + DisplayName: "Redmine", + Href: "/redmine", + Title: "Redmine is a flexible project management web application", + Target: 1, + }, + Category: "Development Apps", + }, + wantErr: assert.NoError, + }, + { + name: "should create entry with category with empty tag", + args: args{dogu: redmineDogu, tag: ""}, + want: EntryWithCategory{Entry: Entry{ + DisplayName: "Redmine", + Href: "/redmine", + Title: "Redmine is a flexible project management web application", + Target: 1, + }, + Category: "Development Apps", + }, + wantErr: assert.NoError, + }, + { + name: "should return empty entry with category on wrong tag", + args: args{dogu: redmineDogu, tag: "wrong tag"}, + want: EntryWithCategory{}, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dc := &DoguConverter{} + got, err := dc.CreateEntryWithCategoryFromDogu(tt.args.dogu, tt.args.tag) + if !tt.wantErr(t, err, fmt.Sprintf("CreateEntryWithCategoryFromDogu(%v, %v)", tt.args.dogu, tt.args.tag)) { + return + } + assert.Equalf(t, tt.want, got, "CreateEntryWithCategoryFromDogu(%v, %v)", tt.args.dogu, tt.args.tag) + }) + } } diff --git a/controllers/warp/types/external_entry.go b/controllers/warp/types/external_entry.go index 2f8a1ab..8cae548 100644 --- a/controllers/warp/types/external_entry.go +++ b/controllers/warp/types/external_entry.go @@ -1,16 +1,16 @@ package types import ( - "encoding/json" "fmt" "github.com/pkg/errors" + "gopkg.in/yaml.v3" ) type externalEntry struct { - DisplayName string - URL string - Description string - Category string + DisplayName string `yaml:"DisplayName"` + URL string `yaml:"URL"` + Description string `yaml:"Description"` + Category string `yaml:"Category"` } // EntryWithCategory is a dto for entries with a Category @@ -23,27 +23,13 @@ type EntryWithCategory struct { type ExternalConverter struct{} // ReadAndUnmarshalExternal reads a specific external link from the configuration and converts it to an entry with a category. -func (ec *ExternalConverter) ReadAndUnmarshalExternal(registry WatchConfigurationContext, key string) (EntryWithCategory, error) { - externalBytes, err := readExternalAsBytes(registry, key) - if err != nil { - return EntryWithCategory{}, nil - } - - return unmarshalExternal(externalBytes) -} - -func readExternalAsBytes(registry WatchConfigurationContext, key string) ([]byte, error) { - resp, err := registry.Get(key) - if err != nil { - return nil, fmt.Errorf("failed to read key %s from etcd: %w", key, err) - } - - return []byte(resp), nil +func (ec *ExternalConverter) ReadAndUnmarshalExternal(value string) (EntryWithCategory, error) { + return unmarshalExternal([]byte(value)) } func unmarshalExternal(externalBytes []byte) (EntryWithCategory, error) { externalEntry := externalEntry{} - err := json.Unmarshal(externalBytes, &externalEntry) + err := yaml.Unmarshal(externalBytes, &externalEntry) if err != nil { return EntryWithCategory{}, fmt.Errorf("failed to unmarshall external: %w", err) } diff --git a/controllers/warp/types/external_entry_test.go b/controllers/warp/types/external_entry_test.go index 42686d2..216494b 100644 --- a/controllers/warp/types/external_entry_test.go +++ b/controllers/warp/types/external_entry_test.go @@ -68,27 +68,10 @@ func Test_mapExternalEntry(t *testing.T) { }) } -func Test_readExternalAsBytes(t *testing.T) { - t.Run("fail on registry get", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("/key").Return("", assert.AnError) - - // when - _, err := readExternalAsBytes(registryMock, "/key") - - // then - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to read key /key from etcd") - }) -} - func Test_readAndUnmarshalExternal(t *testing.T) { t.Run("success", func(t *testing.T) { // given entryStr := "{\n \"DisplayName\": \"display\",\n \"URL\": \"url\",\n \"Description\": \"desc\",\n \"Category\": \"category\"\n}" - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("key").Return(entryStr, nil) expectedEntryWithCategory := EntryWithCategory{ Entry: Entry{ DisplayName: "display", @@ -101,26 +84,12 @@ func Test_readAndUnmarshalExternal(t *testing.T) { externalConverter := ExternalConverter{} // when - result, err := externalConverter.ReadAndUnmarshalExternal(registryMock, "key") + result, err := externalConverter.ReadAndUnmarshalExternal(entryStr) // then require.NoError(t, err) assert.Equal(t, expectedEntryWithCategory, result) }) - - t.Run("return empty category on error", func(t *testing.T) { - // given - registryMock := NewMockWatchConfigurationContext(t) - registryMock.EXPECT().Get("/key").Return("", assert.AnError) - converter := ExternalConverter{} - - // when - entryWithCategory, err := converter.ReadAndUnmarshalExternal(registryMock, "/key") - - // then - require.NoError(t, err) - assert.Equal(t, EntryWithCategory{}, entryWithCategory) - }) } func Test_unmarshalExternal(t *testing.T) { diff --git a/controllers/warp/types/mock_WatchConfigurationContext_test.go b/controllers/warp/types/mock_WatchConfigurationContext_test.go index 5c3cff6..e043859 100644 --- a/controllers/warp/types/mock_WatchConfigurationContext_test.go +++ b/controllers/warp/types/mock_WatchConfigurationContext_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.1. DO NOT EDIT. package types @@ -27,6 +27,10 @@ func (_m *MockWatchConfigurationContext) EXPECT() *MockWatchConfigurationContext func (_m *MockWatchConfigurationContext) Get(key string) (string, error) { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -79,6 +83,10 @@ func (_c *MockWatchConfigurationContext_Get_Call) RunAndReturn(run func(string) func (_m *MockWatchConfigurationContext) GetChildrenPaths(key string) ([]string, error) { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for GetChildrenPaths") + } + var r0 []string var r1 error if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { @@ -165,13 +173,12 @@ func (_c *MockWatchConfigurationContext_Watch_Call) RunAndReturn(run func(contex return _c } -type mockConstructorTestingTNewMockWatchConfigurationContext interface { +// NewMockWatchConfigurationContext creates a new instance of MockWatchConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockWatchConfigurationContext(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockWatchConfigurationContext creates a new instance of MockWatchConfigurationContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockWatchConfigurationContext(t mockConstructorTestingTNewMockWatchConfigurationContext) *MockWatchConfigurationContext { +}) *MockWatchConfigurationContext { mock := &MockWatchConfigurationContext{} mock.Mock.Test(t) diff --git a/controllers/warp/types/testdata/redmine.json b/controllers/warp/types/testdata/redmine.json new file mode 100644 index 0000000..c1fdda9 --- /dev/null +++ b/controllers/warp/types/testdata/redmine.json @@ -0,0 +1,128 @@ +{ + "Name": "official/redmine", + "Version": "5.1.3-1", + "DisplayName": "Redmine", + "Description": "Redmine is a flexible project management web application", + "Category": "Development Apps", + "Tags": [ + "warp", + "pm", + "projectmanagement", + "issue", + "task" + ], + "Logo": "https://cloudogu.com/images/dogus/redmine.png", + "Url": "http://www.redmine.org", + "Image": "registry.cloudogu.com/official/redmine", + "Dependencies": [ + { + "type": "dogu", + "name": "postgresql" + }, + { + "type": "dogu", + "name": "cas" + }, + { + "type": "dogu", + "name": "nginx" + }, + { + "type": "dogu", + "name": "postfix" + } + ], + "Configuration": [ + { + "Name": "logging/root", + "Description": "Set the root log level to one of ERROR, WARN, INFO, DEBUG.", + "Optional": true, + "Default": "INFO", + "Validation": { + "Type": "ONE_OF", + "Values": [ + "WARN", + "DEBUG", + "INFO", + "ERROR" + ] + } + }, + { + "Name": "container_config/memory_limit", + "Description": "Limits the container's memory usage. Use a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte).", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "container_config/swap_limit", + "Description": "Limits the container's swap memory usage. Use zero or a positive integer value followed by one of these units [b,k,m,g] (byte, kibibyte, mebibyte, gibibyte). 0 will disable swapping.", + "Optional": true, + "Validation": { + "Type": "BINARY_MEASUREMENT" + } + }, + { + "Name": "redmine_dogu_config", + "Description": "Applies default configuration to redmine.", + "Optional": true + } + ], + "Volumes": [ + { + "Name": "files", + "Path": "/usr/share/webapps/redmine/files", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "plugins", + "Path": "/var/tmp/redmine/plugins", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": true + }, + { + "Name": "logs", + "Path": "/usr/share/webapps/redmine/log", + "Owner": "1000", + "Group": "1000", + "NeedsBackup": false + } + ], + "ServiceAccounts": [ + { + "Type": "postgresql" + } + ], + "HealthChecks": [ + { + "Type": "tcp", + "Port": 3000 + }, + { + "Type": "state" + } + ], + "ExposedCommands": [ + { + "Name": "post-upgrade", + "Command": "/post-upgrade.sh" + }, + { + "Name": "upgrade-notification", + "Command": "/upgrade-notification.sh" + }, + { + "Name": "pre-upgrade", + "Command": "/pre-upgrade.sh" + }, + { + "Name": "delete-plugin", + "Command": "/delete-plugin.sh" + } + ] +} \ No newline at end of file diff --git a/controllers/warp/types/testdata_test.go b/controllers/warp/types/testdata_test.go new file mode 100644 index 0000000..fece053 --- /dev/null +++ b/controllers/warp/types/testdata_test.go @@ -0,0 +1,18 @@ +package types + +import ( + "encoding/json" + "github.com/cloudogu/cesapp-lib/core" + "testing" +) + +func readRedmineDogu(t *testing.T) *core.Dogu { + t.Helper() + dogu := &core.Dogu{} + err := json.Unmarshal(redmineBytes, dogu) + if err != nil { + t.Fatal(err.Error()) + } + + return dogu +} diff --git a/controllers/warp/warp.go b/controllers/warp/warp.go index 5ae6f15..0ff53dd 100644 --- a/controllers/warp/warp.go +++ b/controllers/warp/warp.go @@ -3,17 +3,16 @@ package warp import ( "context" "fmt" - appsv1 "k8s.io/api/apps/v1" - types2 "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/cloudogu/cesapp-lib/registry" + libconfig "github.com/cloudogu/k8s-registry-lib/config" + "github.com/cloudogu/k8s-registry-lib/dogu" + "github.com/cloudogu/k8s-registry-lib/repository" "github.com/cloudogu/k8s-service-discovery/controllers/config" "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" - etcdclient "go.etcd.io/etcd/client/v2" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + types2 "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/json" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -25,75 +24,133 @@ const ( // Watcher is used to watch a registry and for every change he reads from the registry a specific config path, // build warp menu categories and writes them to a configmap. type Watcher struct { - configuration *config.Configuration - registryToWatch registry.WatchConfigurationContext - k8sClient client.Client - ConfigReader Reader - namespace string - eventRecorder eventRecorder -} - -type eventRecorder interface { - record.EventRecorder -} - -type cesRegistry interface { - registry.Registry -} - -type watchConfigurationContext interface { - registry.WatchConfigurationContext -} - -// Reader is used to fetch warp categories with a configuration -type Reader interface { - Read(configuration *config.Configuration) (types.Categories, error) + configuration *config.Configuration + registryToWatch DoguVersionRegistry + globalConfigRepo GlobalConfigRepository + k8sClient client.Client + ConfigReader Reader + namespace string + eventRecorder eventRecorder } // NewWatcher creates a new Watcher instance to build the warp menu -func NewWatcher(ctx context.Context, k8sClient client.Client, registry cesRegistry, namespace string, recorder eventRecorder) (*Watcher, error) { +func NewWatcher(ctx context.Context, k8sClient client.Client, doguVersionRegistry DoguVersionRegistry, localDoguRepo LocalDoguRepo, namespace string, recorder eventRecorder, globalConfigRepo GlobalConfigRepository) (*Watcher, error) { warpConfig, err := config.ReadConfiguration(ctx, k8sClient, namespace) if err != nil { return nil, fmt.Errorf("failed to Read configuration: %w", err) } reader := &ConfigReader{ - registry: registry.RootConfig(), - configuration: warpConfig, - doguConverter: &types.DoguConverter{}, - externalConverter: &types.ExternalConverter{}, + globalConfigRepo: globalConfigRepo, + doguVersionRegistry: doguVersionRegistry, + localDoguRepo: localDoguRepo, + configuration: warpConfig, + doguConverter: &types.DoguConverter{}, + externalConverter: &types.ExternalConverter{}, } return &Watcher{ - configuration: warpConfig, - registryToWatch: registry.RootConfig(), - k8sClient: k8sClient, - namespace: namespace, - ConfigReader: reader, - eventRecorder: recorder, + configuration: warpConfig, + registryToWatch: doguVersionRegistry, + k8sClient: k8sClient, + namespace: namespace, + ConfigReader: reader, + eventRecorder: recorder, + globalConfigRepo: globalConfigRepo, }, nil } -// Run creates the warp menu and update the menu whenever a relevant etcd key was changed +// Run creates the warp menu and update the menu whenever a relevant configuration key was changed func (w *Watcher) Run(ctx context.Context) error { - warpChannel := make(chan *etcdclient.Response) + // trigger the warp-menu creation once on startup + err := w.execute(ctx) + if err != nil { + ctrl.LoggerFrom(ctx).Error(err, "error creating warp-menu") + } for _, source := range w.configuration.Sources { - go func(source config.Source) { - ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("start etcd watcher for source [%s]", source)) - w.registryToWatch.Watch(ctx, source.Path, true, warpChannel) - ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("stop etcd watcher for source [%s]", source)) - }(source) + if source.Type == "dogus" { + w.startVersionRegistryWatch(ctx) + } else if source.Type == "externals" { + w.startGlobalConfigDirectoryWatch(ctx, source.Path) + } } + return nil +} + +func (w *Watcher) startGlobalConfigDirectoryWatch(ctx context.Context, sourcePath string) { + ctrl.LoggerFrom(ctx).Info(fmt.Sprintf("start global config watcher for source [%s]", sourcePath)) + configKey := libconfig.Key(sourcePath) + + filter := libconfig.DirectoryFilter(configKey) + globalConfigWatchChannel, err := w.globalConfigRepo.Watch(ctx, filter) + if err != nil { + ctrl.LoggerFrom(ctx).Error(err, "failed to create global config watch for path %q", sourcePath) + return + } + + go func() { + w.handleGlobalConfigUpdates(ctx, globalConfigWatchChannel) + }() +} + +func (w *Watcher) handleGlobalConfigUpdates(ctx context.Context, globalConfigWatchChannel <-chan repository.GlobalConfigWatchResult) { + for { + select { + case <-ctx.Done(): + ctrl.LoggerFrom(ctx).Info("context done - stop global config watch for warp generation") + return + case result, open := <-globalConfigWatchChannel: + if !open { + ctrl.LoggerFrom(ctx).Info("global config watch channel canceled - stop watch for warp generation") + return + } + if result.Err != nil { + ctrl.LoggerFrom(ctx).Error(result.Err, "global config watch channel error for warp generation") + continue + } + // Trigger refresh. Content of the result is not needed + err := w.execute(ctx) + if err != nil { + ctrl.LoggerFrom(ctx).Error(err, "failed to update entries from global config in warp menu") + } + } + } +} + +func (w *Watcher) startVersionRegistryWatch(ctx context.Context) { + ctrl.LoggerFrom(ctx).Info("start version registry watcher for source type dogu") + versionChannel, doguVersionWatchError := w.registryToWatch.WatchAllCurrent(ctx) + if doguVersionWatchError != nil { + ctrl.LoggerFrom(ctx).Error(doguVersionWatchError, "failed to create dogu version registry watch") + return + } + + go func() { + w.handleDoguVersionUpdates(ctx, versionChannel) + }() +} + +func (w *Watcher) handleDoguVersionUpdates(ctx context.Context, versionChannel <-chan dogu.CurrentVersionsWatchResult) { for { select { case <-ctx.Done(): - return nil - case <-warpChannel: + ctrl.LoggerFrom(ctx).Info("context done - stop dogu version registry watch for warp generation") + return + case result, open := <-versionChannel: + if !open { + ctrl.LoggerFrom(ctx).Info("dogu version watch channel canceled - stop watch") + return + } + if result.Err != nil { + ctrl.LoggerFrom(ctx).Error(result.Err, "dogu version watch channel error") + continue + } + // Trigger refresh. Content of the result is not needed err := w.execute(ctx) if err != nil { - return err + ctrl.LoggerFrom(ctx).Error(err, "failed to update dogus in warp menu") } } } @@ -106,7 +163,7 @@ func (w *Watcher) execute(ctx context.Context) error { return fmt.Errorf("warp update: failed to get deployment [%s]: %w", "k8s-service-discovery-controller-manager", err) } - categories, err := w.ConfigReader.Read(w.configuration) + categories, err := w.ConfigReader.Read(ctx, w.configuration) if err != nil { w.eventRecorder.Eventf(deployment, corev1.EventTypeWarning, errorOnWarpMenuUpdateEventReason, "Updating warp menu failed: %w", err) return fmt.Errorf("error during read: %w", err) diff --git a/controllers/warp/warp_test.go b/controllers/warp/warp_test.go index efafb74..7a2f94d 100644 --- a/controllers/warp/warp_test.go +++ b/controllers/warp/warp_test.go @@ -3,17 +3,21 @@ package warp import ( "context" _ "embed" + "github.com/cloudogu/k8s-registry-lib/dogu" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/cloudogu/k8s-service-discovery/controllers/config" "github.com/cloudogu/k8s-service-discovery/controllers/warp/types" + "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - etcdclient "go.etcd.io/etcd/client/v2" - v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types2 "k8s.io/apimachinery/pkg/types" "os" - client2 "sigs.k8s.io/controller-runtime/pkg/client" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/yaml" "testing" "time" @@ -43,18 +47,18 @@ func TestNewWatcher(t *testing.T) { t.Run("success", func(t *testing.T) { // given ctx := context.TODO() - client := fake.NewClientBuilder().Build() - err := client.Create(ctx, &k8sConfig) + clientMock := fake.NewClientBuilder().Build() + err := clientMock.Create(ctx, &k8sConfig) require.NoError(t, err) namespace := "test" - mockRegistry := newMockCesRegistry(t) - watchRegistry := newMockWatchConfigurationContext(t) - mockRegistry.EXPECT().RootConfig().Return(watchRegistry) + mockGlobalConfigRepo := NewMockGlobalConfigRepository(t) + versionRegistryMock := NewMockDoguVersionRegistry(t) + doguSpecRepoMock := NewMockLocalDoguRepo(t) err = os.Unsetenv("STAGE") require.NoError(t, err) // when - watcher, err := NewWatcher(ctx, client, mockRegistry, namespace, newMockEventRecorder(t)) + watcher, err := NewWatcher(ctx, clientMock, versionRegistryMock, doguSpecRepoMock, namespace, newMockEventRecorder(t), mockGlobalConfigRepo) // then require.NoError(t, err) @@ -71,10 +75,10 @@ func TestNewWatcher(t *testing.T) { panic(err) } }() - client := fake.NewClientBuilder().Build() + clientMock := fake.NewClientBuilder().Build() // when - _, err = NewWatcher(context.TODO(), client, nil, "test", newMockEventRecorder(t)) + _, err = NewWatcher(context.TODO(), clientMock, nil, nil, "test", nil, nil) // then require.Error(t, err) @@ -82,69 +86,489 @@ func TestNewWatcher(t *testing.T) { }) } +var testNamespace = "test" + func TestWatcher_Run(t *testing.T) { - t.Run("success with 3 sources and one refresh", func(t *testing.T) { + t.Run("success of the initial run", func(t *testing.T) { // given - // prepare deadline for watch - timeout := time.Second * 2 - ctx, cancel := context.WithTimeout(context.TODO(), timeout) - timer := time.NewTimer(timeout) - go func() { - if <-timer.C; true { - cancel() - } + testConfiguration := &config.Configuration{} + k8sClientMock := newMockK8sClient(t) + configReaderMock := NewMockReader(t) + eventRecorderMock := newMockEventRecorder(t) + k8sClientMock.EXPECT().Get(testCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + categories := types.Categories{ + { + Title: "Administration Apps", + Order: 100, + Entries: types.Entries{ + { + DisplayName: "Admin", + Href: "/admin", + Title: "Admin", + Target: 1, + }, + }, + }, + } + configReaderMock.EXPECT().Read(testCtx, testConfiguration).Return(categories, nil) + k8sClientMock.EXPECT().Get(testCtx, client.ObjectKey{Name: config.MenuConfigMap, Namespace: testNamespace}, mock.Anything).RunAndReturn(func(ctx context.Context, name types2.NamespacedName, object client.Object, option ...client.GetOption) error { + menuJsonCm := object.(*corev1.ConfigMap) + menuJsonCm.Data = map[string]string{} + return nil + }) + expectedMenuJsonCm := &corev1.ConfigMap{Data: map[string]string{"menu.json": "[{\"Title\":\"Administration Apps\",\"Order\":100,\"Entries\":[{\"DisplayName\":\"Admin\",\"Href\":\"/admin\",\"Title\":\"Admin\",\"Target\":\"self\"}]}]"}} + k8sClientMock.EXPECT().Update(testCtx, expectedMenuJsonCm).Return(nil) + eventRecorderMock.EXPECT().Event(mock.Anything, corev1.EventTypeNormal, "WarpMenu", "Warp menu updated.") + + sut := Watcher{ + k8sClient: k8sClientMock, + ConfigReader: configReaderMock, + configuration: testConfiguration, + namespace: testNamespace, + eventRecorder: eventRecorderMock, + } + + // when + err := sut.Run(testCtx) + + // then + require.NoError(t, err) + }) + + t.Run("should log error in initial run", func(t *testing.T) { + // given + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().Get(testCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(assert.AnError) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Error(mock.Anything, "error creating warp-menu") - // create the config with 3 sources and an empty menu json configmap - k8sConfig.ResourceVersion = "" - namespace := "test" - deployment := &v1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "k8s-service-discovery-controller-manager", Namespace: namespace}} - client := fake.NewClientBuilder().WithObjects(&k8sConfig, &menuConfigMap, deployment).Build() - err := os.Unsetenv("STAGE") + sut := Watcher{ + k8sClient: k8sClientMock, + namespace: testNamespace, + configuration: &config.Configuration{}, + } + + // when + err := sut.Run(testCtx) + + // then require.NoError(t, err) + }) + + t.Run("success with a dogu source", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + testConfiguration := &config.Configuration{ + Sources: []config.Source{ + { + Path: "/dogu", + Type: "dogus", + Tag: "warp", + }, + }, + } + k8sClientMock := newMockK8sClient(t) + configReaderMock := NewMockReader(t) + eventRecorderMock := newMockEventRecorder(t) + versionRegistryMock := NewMockDoguVersionRegistry(t) + k8sClientMock.EXPECT().Get(cancelCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + categories := types.Categories{ + { + Title: "Administration Apps", + Order: 100, + Entries: types.Entries{ + { + DisplayName: "Admin", + Href: "/admin", + Title: "Admin", + Target: 1, + }, + }, + }, + } + configReaderMock.EXPECT().Read(cancelCtx, testConfiguration).Return(categories, nil) + k8sClientMock.EXPECT().Get(cancelCtx, client.ObjectKey{Name: config.MenuConfigMap, Namespace: testNamespace}, mock.Anything).RunAndReturn(func(ctx context.Context, name types2.NamespacedName, object client.Object, option ...client.GetOption) error { + menuJsonCm := object.(*corev1.ConfigMap) + menuJsonCm.Data = map[string]string{} + return nil + }) + expectedMenuJsonCm := &corev1.ConfigMap{Data: map[string]string{"menu.json": "[{\"Title\":\"Administration Apps\",\"Order\":100,\"Entries\":[{\"DisplayName\":\"Admin\",\"Href\":\"/admin\",\"Title\":\"Admin\",\"Target\":\"self\"}]}]"}} + k8sClientMock.EXPECT().Update(cancelCtx, expectedMenuJsonCm).Return(nil) + eventRecorderMock.EXPECT().Event(mock.Anything, corev1.EventTypeNormal, "WarpMenu", "Warp menu updated.").Times(1) + eventRecorderMock.EXPECT().Event(mock.Anything, corev1.EventTypeNormal, "WarpMenu", "Warp menu updated.").Times(1).Run(func(args mock.Arguments) { + cancelFunc() + }) - // prepare mocks - mockRegistry := newMockCesRegistry(t) - watchRegistry := newMockWatchConfigurationContext(t) - watchEvent := &etcdclient.Response{} - mockRegistry.EXPECT().RootConfig().Return(watchRegistry) - watchRegistry.EXPECT().Watch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(_ context.Context, _ string, _ bool, eventChannel chan *etcdclient.Response) { - eventChannel <- watchEvent - }).Times(3) + resultChannel := make(chan dogu.CurrentVersionsWatchResult) + versionRegistryMock.EXPECT().WatchAllCurrent(cancelCtx).Return(resultChannel, nil) - recorderMock := newMockEventRecorder(t) - recorderMock.EXPECT().Event(mock.IsType(&v1.Deployment{}), "Normal", "WarpMenu", "Warp menu updated.") + sut := Watcher{ + k8sClient: k8sClientMock, + ConfigReader: configReaderMock, + configuration: testConfiguration, + namespace: testNamespace, + eventRecorder: eventRecorderMock, + registryToWatch: versionRegistryMock, + } - watcher, err := NewWatcher(ctx, client, mockRegistry, namespace, recorderMock) + // when + err := sut.Run(cancelCtx) + resultChannel <- dogu.CurrentVersionsWatchResult{} + + // then require.NoError(t, err) + <-cancelCtx.Done() + }) - // prepare result categories - expectedEntry := types.Entry{ - DisplayName: "Redmine", - Href: "/redmine", - Title: "Redmine", - Target: types.TARGET_SELF, + t.Run("success with a config source", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + testConfiguration := &config.Configuration{ + Sources: []config.Source{ + { + Path: "externals", + Type: "externals", + }, + }, } - expectedEntries := types.Entries{expectedEntry} - expectedCategory := &types.Category{ - Title: "Development Apps", - Order: 100, - Entries: expectedEntries, + k8sClientMock := newMockK8sClient(t) + configReaderMock := NewMockReader(t) + eventRecorderMock := newMockEventRecorder(t) + globalConfigMock := NewMockGlobalConfigRepository(t) + k8sClientMock.EXPECT().Get(cancelCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + categories := types.Categories{ + { + Title: "Administration Apps", + Order: 100, + Entries: types.Entries{ + { + DisplayName: "Admin", + Href: "/admin", + Title: "Admin", + Target: 1, + }, + }, + }, } - expectedCategories := types.Categories{expectedCategory} - expectedMenuJSON := "[{\"Title\":\"Development Apps\",\"Order\":100,\"Entries\":[{\"DisplayName\":\"Redmine\",\"Href\":\"/redmine\",\"Title\":\"Redmine\",\"Target\":\"self\"}]}]" + configReaderMock.EXPECT().Read(cancelCtx, testConfiguration).Return(categories, nil) + k8sClientMock.EXPECT().Get(cancelCtx, client.ObjectKey{Name: config.MenuConfigMap, Namespace: testNamespace}, mock.Anything).RunAndReturn(func(ctx context.Context, name types2.NamespacedName, object client.Object, option ...client.GetOption) error { + menuJsonCm := object.(*corev1.ConfigMap) + menuJsonCm.Data = map[string]string{} + return nil + }) + expectedMenuJsonCm := &corev1.ConfigMap{Data: map[string]string{"menu.json": "[{\"Title\":\"Administration Apps\",\"Order\":100,\"Entries\":[{\"DisplayName\":\"Admin\",\"Href\":\"/admin\",\"Title\":\"Admin\",\"Target\":\"self\"}]}]"}} + k8sClientMock.EXPECT().Update(cancelCtx, expectedMenuJsonCm).Return(nil) + eventRecorderMock.EXPECT().Event(mock.Anything, corev1.EventTypeNormal, "WarpMenu", "Warp menu updated.").Times(1) + eventRecorderMock.EXPECT().Event(mock.Anything, corev1.EventTypeNormal, "WarpMenu", "Warp menu updated.").Times(1).Run(func(args mock.Arguments) { + cancelFunc() + }) - readerMock := NewMockReader(t) - readerMock.EXPECT().Read(mock.Anything).Return(expectedCategories, nil) - watcher.ConfigReader = readerMock + resultChannel := make(chan repository.GlobalConfigWatchResult) + globalConfigMock.EXPECT().Watch(cancelCtx, mock.Anything).Return(resultChannel, nil) + + sut := Watcher{ + k8sClient: k8sClientMock, + ConfigReader: configReaderMock, + configuration: testConfiguration, + namespace: testNamespace, + eventRecorder: eventRecorderMock, + globalConfigRepo: globalConfigMock, + } // when - watcher.Run(ctx) + err := sut.Run(cancelCtx) + resultChannel <- repository.GlobalConfigWatchResult{} // then - menuCm := &corev1.ConfigMap{} - err = client.Get(ctx, client2.ObjectKey{Name: "k8s-ces-menu-json", Namespace: "test"}, menuCm) require.NoError(t, err) - assert.Equal(t, expectedMenuJSON, menuCm.Data["menu.json"]) + <-cancelCtx.Done() + }) +} + +func TestWatcher_startGlobalConfigWatch(t *testing.T) { + t.Run("should log error and return on get watch error", func(t *testing.T) { + // given + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "start global config watcher for source [/config/externals]") + mockLogSink.EXPECT().Error(mock.Anything, "failed to create global config watch for path %q", "/config/externals") + + globalConfigMock := NewMockGlobalConfigRepository(t) + globalConfigMock.EXPECT().Watch(mock.Anything, mock.Anything).Return(nil, assert.AnError) + + sut := Watcher{ + globalConfigRepo: globalConfigMock, + } + + // when + sut.startGlobalConfigDirectoryWatch(testCtx, "/config/externals") + }) +} + +func TestWatcher_startVersionRegistryWatch(t *testing.T) { + t.Run("should log error and return on get watch error", func(t *testing.T) { + // given + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "start version registry watcher for source type dogu") + mockLogSink.EXPECT().Error(mock.Anything, "failed to create dogu version registry watch") + + versionRegistryMock := NewMockDoguVersionRegistry(t) + resultChannel := make(chan dogu.CurrentVersionsWatchResult) + versionRegistryMock.EXPECT().WatchAllCurrent(mock.Anything).Return(resultChannel, assert.AnError) + + sut := Watcher{ + registryToWatch: versionRegistryMock, + } + + // when + sut.startVersionRegistryWatch(testCtx) + }) +} + +func TestWatcher_handleGlobalConfigUpdates(t *testing.T) { + t.Run("should return and log if the channel will be closed", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "global config watch channel canceled - stop watch for warp generation").Run(func(level int, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + sut := Watcher{} + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.handleGlobalConfigUpdates(cancelCtx, channel) + }() + close(channel) + <-cancelCtx.Done() + }) + + t.Run("should continue and log error on watch result error", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Error(assert.AnError, "global config watch channel error for warp generation").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + mockLogSink.EXPECT().Info(0, "context done - stop global config watch for warp generation") + + sut := Watcher{} + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.handleGlobalConfigUpdates(cancelCtx, channel) + }() + channel <- repository.GlobalConfigWatchResult{Err: assert.AnError} + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C + }) + + t.Run("should return error on error executing global config update on watch event", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().Get(cancelCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + + configReaderMock := NewMockReader(t) + configReaderMock.EXPECT().Read(cancelCtx, mock.Anything).Return(nil, assert.AnError) + + eventRecoderMock := newMockEventRecorder(t) + eventRecoderMock.EXPECT().Eventf(mock.Anything, corev1.EventTypeWarning, "ErrUpdateWarpMenu", "Updating warp menu failed: %w", assert.AnError) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Error(mock.Anything, "failed to update entries from global config in warp menu").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + mockLogSink.EXPECT().Info(0, "context done - stop global config watch for warp generation") + + sut := Watcher{ + namespace: testNamespace, + k8sClient: k8sClientMock, + ConfigReader: configReaderMock, + eventRecorder: eventRecoderMock, + } + channel := make(chan repository.GlobalConfigWatchResult) + + // when + go func() { + sut.handleGlobalConfigUpdates(cancelCtx, channel) + }() + channel <- repository.GlobalConfigWatchResult{} + <-cancelCtx.Done() + }) +} + +func TestWatcher_handleDoguVersionUpdates(t *testing.T) { + t.Run("should return and log if the channel will be closed", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Info(0, "dogu version watch channel canceled - stop watch").Run(func(level int, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + + sut := Watcher{} + channel := make(chan dogu.CurrentVersionsWatchResult) + + // when + go func() { + sut.handleDoguVersionUpdates(cancelCtx, channel) + }() + close(channel) + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C + }) + + t.Run("should continue and log error on watch result error", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Error(assert.AnError, "dogu version watch channel error").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + mockLogSink.EXPECT().Info(0, "context done - stop dogu version registry watch for warp generation") + + sut := Watcher{} + channel := make(chan dogu.CurrentVersionsWatchResult) + + // when + go func() { + sut.handleDoguVersionUpdates(cancelCtx, channel) + }() + channel <- dogu.CurrentVersionsWatchResult{Err: assert.AnError} + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C + }) + + t.Run("should return error on error executing dogu version update on watch event", func(t *testing.T) { + // given + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + + k8sClientMock := newMockK8sClient(t) + k8sClientMock.EXPECT().Get(cancelCtx, types2.NamespacedName{Name: "k8s-service-discovery-controller-manager", Namespace: testNamespace}, mock.Anything).Return(nil) + + configReaderMock := NewMockReader(t) + configReaderMock.EXPECT().Read(cancelCtx, mock.Anything).Return(nil, assert.AnError) + + eventRecoderMock := newMockEventRecorder(t) + eventRecoderMock.EXPECT().Eventf(mock.Anything, corev1.EventTypeWarning, "ErrUpdateWarpMenu", "Updating warp menu failed: %w", assert.AnError) + + mockLogSink := NewMockLogSink(t) + oldLogFn := log.FromContext + ctrl.LoggerFrom = func(ctx context.Context, keysAndValues ...interface{}) logr.Logger { + return logr.New(mockLogSink) + } + defer func() { + ctrl.LoggerFrom = oldLogFn + }() + mockLogSink.EXPECT().Init(mock.Anything) + mockLogSink.EXPECT().Enabled(mock.Anything).Return(true) + mockLogSink.EXPECT().Error(mock.Anything, "failed to update dogus in warp menu").Run(func(err error, msg string, keysAndValues ...interface{}) { + cancelFunc() + }) + mockLogSink.EXPECT().Info(0, "context done - stop dogu version registry watch for warp generation") + + sut := Watcher{ + namespace: testNamespace, + k8sClient: k8sClientMock, + ConfigReader: configReaderMock, + eventRecorder: eventRecoderMock, + } + channel := make(chan dogu.CurrentVersionsWatchResult) + + // when + go func() { + sut.handleDoguVersionUpdates(cancelCtx, channel) + }() + channel <- dogu.CurrentVersionsWatchResult{} + <-cancelCtx.Done() + // Wait for last log + timer := time.NewTimer(time.Millisecond * 500) + <-timer.C }) } diff --git a/controllers/warpMenuCreator.go b/controllers/warpMenuCreator.go index aaa86a1..26ebf01 100644 --- a/controllers/warpMenuCreator.go +++ b/controllers/warpMenuCreator.go @@ -9,19 +9,23 @@ import ( // warpMenuCreator used to create warp menu type warpMenuCreator struct { - client client.Client - registry cesRegistry - namespace string - eventRecorder eventRecorder + client client.Client + doguVersionRegistry warp.DoguVersionRegistry + localDoguRepo warp.LocalDoguRepo + namespace string + eventRecorder eventRecorder + globalConfig warp.GlobalConfigRepository } // NewWarpMenuCreator initialises a creator object to start the warp menu creation -func NewWarpMenuCreator(client client.Client, registry cesRegistry, namespace string, recorder eventRecorder) *warpMenuCreator { +func NewWarpMenuCreator(client client.Client, doguVersionRegistry warp.DoguVersionRegistry, localDoguRepo warp.LocalDoguRepo, namespace string, recorder eventRecorder, globalConfig warp.GlobalConfigRepository) *warpMenuCreator { return &warpMenuCreator{ - client: client, - registry: registry, - namespace: namespace, - eventRecorder: recorder, + client: client, + doguVersionRegistry: doguVersionRegistry, + localDoguRepo: localDoguRepo, + namespace: namespace, + eventRecorder: recorder, + globalConfig: globalConfig, } } @@ -33,7 +37,7 @@ func (wmc warpMenuCreator) Start(ctx context.Context) error { // CreateWarpMenu reads the warp configuration and starts watchers to refresh the menu.json configmap // in background. func (wmc warpMenuCreator) CreateWarpMenu(ctx context.Context) error { - warpWatcher, err := warp.NewWatcher(ctx, wmc.client, wmc.registry, wmc.namespace, wmc.eventRecorder) + warpWatcher, err := warp.NewWatcher(ctx, wmc.client, wmc.doguVersionRegistry, wmc.localDoguRepo, wmc.namespace, wmc.eventRecorder, wmc.globalConfig) if err != nil { return fmt.Errorf("failed to create warp menu watcher: %w", err) } diff --git a/controllers/warpMenuCreator_test.go b/controllers/warpMenuCreator_test.go index 1d6ff14..8e5b7f2 100644 --- a/controllers/warpMenuCreator_test.go +++ b/controllers/warpMenuCreator_test.go @@ -11,7 +11,7 @@ func TestNewWarpMenuCreator(t *testing.T) { client := fake.NewClientBuilder().Build() // when - underTest := NewWarpMenuCreator(client, nil, "test", newMockEventRecorder(t)) + underTest := NewWarpMenuCreator(client, nil, nil, "test", newMockEventRecorder(t), nil) // then require.NotNil(t, underTest) diff --git a/docs/operations/installing_operator_into_cluster_de.md b/docs/operations/installing_operator_into_cluster_de.md deleted file mode 100644 index 34dbacd..0000000 --- a/docs/operations/installing_operator_into_cluster_de.md +++ /dev/null @@ -1,20 +0,0 @@ -# Installationsanleitung für den k8s-service-discovery - -## Installation von GitHub - -Die Installation von GitHub erfordert die Installations-YAML, die alle benötigten K8s-Ressourcen enthält. In dieser -YAML müssen alle Einträge `{{ .Namespace}}` durch den Ziel-Namespace ersetzt werden. - -```bash -# define version -GITHUB_VERSION=0.0.6 -TARGET_NAMESPACE=my-namespace - -# download yaml -wget https://github.com/cloudogu/k8s-service-discovery/releases/download/v${GITHUB_VERSION}/k8s-dogu-operator_${GITHUB_VERSION}.yaml - -# replace namespace and apply service discovery -sed "s/{{ .Namespace }}/${TARGET_NAMESPACE}/" ${K8S_RESOURCE_YAML} | kubectl --namespace "${TARGET_NAMESPACE}" apply -f - -``` - -Der Operator sollte nun erfolgreich im Cluster gestartet sein. \ No newline at end of file diff --git a/docs/operations/installing_operator_into_cluster_en.md b/docs/operations/installing_operator_into_cluster_en.md deleted file mode 100644 index 777a3b6..0000000 --- a/docs/operations/installing_operator_into_cluster_en.md +++ /dev/null @@ -1,20 +0,0 @@ -# installation instructions for the k8s-service-discovery - -## Installing GitHub - -Installing GitHub requires the installation YAML, which contains all the required K8s resources. In this -YAML, all entries `{ .namespace}}` must be replaced with the target namespace. - -```bash -# define version -GITHUB_VERSION=0.0.6 -TARGET_NAMESPACE=my-namespace - -# download yaml -wget https://github.com/cloudogu/k8s-service-discovery/releases/download/v${GITHUB_VERSION}/k8s-dogu-operator_${GITHUB_VERSION}.yaml - -# replace namespace and apply service discovery -sed "s/{{ .namespace }}/${TARGET_NAMESPACE}/" ${K8S_RESOURCE_YAML} | kubectl --namespace "${TARGET_NAMESPACE}" apply -f - -``` - -The operator should now be successfully started in the cluster. \ No newline at end of file diff --git a/docs/operations/maintenance_mode_de.md b/docs/operations/maintenance_mode_de.md index 272eb52..8d5d3e6 100644 --- a/docs/operations/maintenance_mode_de.md +++ b/docs/operations/maintenance_mode_de.md @@ -8,7 +8,7 @@ Zugriff auf Dogus eine Wartungsseite angezeigt. # Wartungsmodus aktivieren -Um das CES in den Wartungsmodus zu versetzen, muss der folgende String in `/config/_global/maintenance` geschrieben +Um das CES in den Wartungsmodus zu versetzen, muss in der globalen Konfiguration der folgende String in `maintenance` geschrieben werden: ```json @@ -18,8 +18,8 @@ werden: } ``` -Jede Anfrage an den CES wird dann mit dem HTTP-Code 503 (Service Unavailable) beantwortet, bis der Schlüssel im etcd ( -s.o.) gelöscht wird. Dabei wird auf der Seite der Inhalt von `title` und `text` angezeigt. +Jede Anfrage an den CES wird dann mit dem HTTP-Code 503 (Service Unavailable) beantwortet, bis der Schlüssel (s.o.) gelöscht wird. +Dabei wird auf der Seite der Inhalt von `title` und `text` angezeigt. **Hinweis:** Das Aktivieren und Deaktivieren des Wartungsmodus führt zu einem Neustart des Nginx-Static Dogus. Dies sollte jedoch nur wenige Sekunden in Anspruch nehmen. diff --git a/docs/operations/maintenance_mode_en.md b/docs/operations/maintenance_mode_en.md index 6588e15..5e1ffc3 100644 --- a/docs/operations/maintenance_mode_en.md +++ b/docs/operations/maintenance_mode_en.md @@ -8,7 +8,7 @@ returned for each access to a Dogus. # Activate Maintenance Mode -To put the CES into maintenance mode, the following string must be written to `/config/_global/maintenance`: +To put the CES into maintenance mode, the following string in the global configuration must be written to `maintenance`: ```json { @@ -17,8 +17,8 @@ To put the CES into maintenance mode, the following string must be written to `/ } ``` -Each request to the CES is then answered with the HTTP code 503 (Service Unavailable) until the key in the etcd is -either deleted. Thereby the content of `title` and `text` is displayed on the page. +Each request to the CES is then answered with the HTTP code 503 (Service Unavailable) until the key is deleted. +Thereby the content of `title` and `text` is displayed on the page. **Note:** Enabling and disabling maintenance mode will cause the Nginx static dogus to restart. However, this should only take a few seconds. diff --git a/docs/operations/ssl_de.md b/docs/operations/ssl_de.md index b1219ed..5884756 100644 --- a/docs/operations/ssl_de.md +++ b/docs/operations/ssl_de.md @@ -2,10 +2,10 @@ ## Ablage -Das SSL-Zertifikat befindet sich in der Registry unter den folgenden Pfaden: -- `config/_global/certificate/key` -- `config/_global/certificate/server.crt` -- `config/_global/certificate/server.key` +Das SSL-Zertifikat befindet sich in der Registry unter den folgenden Pfaden in der globalen Config: +- `certificate/key` +- `certificate/server.crt` +- `certificate/server.key` ## Ein selbst-signiertes SSL-Zertifikat erneuern diff --git a/docs/operations/ssl_en.md b/docs/operations/ssl_en.md index 285afba..16da8d8 100644 --- a/docs/operations/ssl_en.md +++ b/docs/operations/ssl_en.md @@ -2,10 +2,10 @@ ## Location -The SSL certificate is located in the registry under the following paths: -- `config/_global/certificate/key` -- `config/_global/certificate/server.crt` -- `config/_global/certificate/server.key` +The SSL certificate is located in the registry under the following paths in the global config: +- `certificate/key` +- `certificate/server.crt` +- `certificate/server.key` ## Renew an SSL certificate diff --git a/docs/operations/warp_menu_generation_de.md b/docs/operations/warp_menu_generation_de.md index 1ce5cbf..fd72527 100644 --- a/docs/operations/warp_menu_generation_de.md +++ b/docs/operations/warp_menu_generation_de.md @@ -1,7 +1,7 @@ # Generierung der Einträge des Warp-Menüs Die `k8s-service-discovery` ist zuständig für die Generierung der `menu.json` des Warp-Menüs. -Dazu implementiert sie, ähnlich wie es `ces-confd` gemacht hat, einen Watch auf bestimmte Pfade im Etcd. +Dazu implementiert sie, ähnlich wie es `ces-confd` gemacht hat, einen Watch auf bestimmte Pfade in der globalen Konfiguration und lokalen Dogu-Registry. Bei einer Änderung z.B. einer Dogu-Installation generiert die `k8s-service-discovery` neue Einträge und schreibt diese in die Configmap `k8s-ces-menu-json`. Diese Configmap wird von dem `nginx-ingress` eingebunden und verwendet. @@ -10,7 +10,7 @@ eingebunden und verwendet. ### Quellen -Es ist möglich 3 Arten von Quellen für den Etcd-Watch anzugeben. +Es ist möglich 3 Arten von Quellen für den Watch anzugeben. #### Dogus ```yaml @@ -23,34 +23,68 @@ sources: #### Externe Links ```yaml sources: - - path: /config/nginx/externals + - path: externals type: externals ``` -Externe Links müssen folgender Struktur (JSON-String) im Etcd entsprechen: +Externe Links müssen folgender Struktur (YAML-String) in der globalen Konfiguration entsprechen: +```yaml +cloudogu: | + DisplayName: Cloudogu + Description: Beschreibungstext für Cloudogu Webseite + Category: External Links + URL: https://www.cloudogu.com +``` + +#### Konfiguration für Support-Einträge in der globalen Konfiguration +Die Konfiguration der Support-Einträge erfolgt direkt in der globalen Konfiguration mithilfe der folgenden drei Schlüssel: + - block_warpmenu_support_category + - allowed_warpmenu_support_entries + - disabled_warpmenu_support_entries + +##### Alle Einträge ausblenden +Wenn alle Support-Einträge des warp-menu nicht angezeigt werden sollen, kann dies über die globale Konfiguration `block_warpmenu_support_category` konfiguriert werden. +```shell +# alle Einträge ausblenden +kubectl edit configmap global-config --namespace ecosystem +``` +Edit: +```yaml +data: + config.yaml: + block_warpmenu_support_category: "true" +``` +# keine Einträge ausblenden +```shell +# alle Einträge ausblenden +kubectl edit configmap global-config --namespace ecosystem ``` -{ - "cloudogu": "{ - \"DisplayName\": \"Cloudogu\", - \"Description\": \"Beschreibungstext für Cloudogu Webseite\", - \"Category\": \"External Links\", - \"URL\": \"https://www.cloudogu.com/\" -}" -} +Edit: +```yaml +data: + config.yaml: + block_warpmenu_support_category: "false" ``` -#### Einträge, die ausgeblendet werden sollen +##### Nur einzelne Einträge anzeigen +Wenn alle Support-Einträge des warp-menu ausgeblendet sind, aber trotzen einzelne davon angezeigt werden sollen, kann dies über die globale Konfiguration `allowed_warpmenu_support_entries` konfiguriert werden. +Dort muss ein JSON-Array, mit den anzuzeigenden Einträgen angegeben werden. ```yaml -sources: - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries +allowed_warpmenu_support_entries: '["platform", "aboutCloudoguToken"]' +``` + +> Diese Konfiguration ist nur wirksam, wenn **alle** Einträge ausgeblendet sind (siehe [oben](#alle-einträge-ausblenden)). + +##### Einzelne Einträge ausblenden +Wenn einzelne Einträge im warp-menu nicht gerendert werden sollen, kann dies über die globale Konfiguration `disabled_warpmenu_support_entries` konfiguriert werden. +Dort muss ein JSON-Array, mit den auszublendenden Einträgen angegeben werden. + +```yaml +disabled_warpmenu_support_entries: '["docsCloudoguComUrl", "aboutCloudoguToken"]' ``` -Die Konfiguration beinhaltet außerdem Support-Links, die jedoch mit dem Typ `disabled_support_entries` ausgeblendet -werden können. Dazu muss im angegebenen Pfad ein String-Array im JSON-Format abgelegt werden. Die Einträge entsprechen -den Keys der Links. Zum Beispiel: -`'["docsCloudoguComUrl", "aboutCloudoguToken"]'` +> Diese Konfiguration ist nur wirksam, wenn **nicht** alle Einträge ausgeblendet sind (siehe [oben](#alle-einträge-ausblenden)). ### Order Mit der Kategorie `order` lassen sich die bestimmten Dogu-Kategorien aus der `dogu.json` im Warp-Menü sortieren. @@ -72,10 +106,8 @@ sources: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -86,7 +118,7 @@ support: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com ``` \ No newline at end of file diff --git a/docs/operations/warp_menu_generation_en.md b/docs/operations/warp_menu_generation_en.md index 3d5a965..c4b34d3 100644 --- a/docs/operations/warp_menu_generation_en.md +++ b/docs/operations/warp_menu_generation_en.md @@ -1,7 +1,7 @@ # Generation of the entries of the warp menu The `k8s-service-discovery` is responsible for generating the `menu.json` of the warp menu. -For this it implements, similar to what `ces-confd` did, a watch on certain paths in the etcd. +For this it implements, similar to what `ces-confd` did, a watch on certain paths in the global configuration and the local dogu registry. When changing e.g. a Dogu installation the `k8s-service-discovery` generates new entries and writes them to the configmap `k8s-ces-menu-json`. This configmap is included and used by the `nginx-ingress`. @@ -9,7 +9,7 @@ and writes them to the configmap `k8s-ces-menu-json`. This configmap is included ### Sources -It is possible to specify 3 types of sources for the etcd-watch. +It is possible to specify 3 types of sources for the watch. #### Dogus ```yaml @@ -22,34 +22,74 @@ sources: #### External links ```yaml sources: - - path: /config/nginx/externals + - path: externals type: externals ``` -External links must match the following structure (JSON-String) in the etcd: +External links must match the following structure (YAML-String) in the global configuration: -``` -{ - "cloudogu": "{ - \"DisplayName\": \"Cloudogu\", - \"Description\": \"Beschreibungstext für Cloudogu Webseite\", - \"Category\": \"External Links\", - \"URL\": \"https://www.cloudogu.com/\" -}" -} +```yaml +cloudogu: | + DisplayName: Cloudogu + Description: Beschreibungstext für Cloudogu Webseite + Category: External Links + URL: https://www.cloudogu.com ``` -#### Entries to be hidden +#### Configuration of Support-Entries in the global configuration ```yaml sources: - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries + - path: block_warpmenu_support_category + type: support_entry_config + - path: allowed_warpmenu_support_entries + type: support_entry_config + - path: disabled_warpmenu_support_entries + type: support_entry_config +``` + +##### Hide all entries +If all support entries of the warp-menu are not to be displayed, this can be configured via the global config key `block_warpmenu_support_category`. +```shell +# hide all entries +kubectl edit configmap global-config --namespace ecosystem +``` +Edit: +```yaml +data: + config.yaml: + block_warpmenu_support_category: "false" +``` + +# do not hide any entries +```shell +kubectl edit configmap global-config --namespace ecosystem +``` +Edit: +```yaml +data: + config.yaml: + block_warpmenu_support_category: "false" +``` + +##### Show only individual entries +If all support entries of the warp-menu are hidden, but individual entries should still be displayed, this can be configured via the global configuration key `allowed_warpmenu_support_entries`. +A JSON array with the entries to be displayed must be specified there. + +```yaml +allowed_warpmenu_support_entries: '["platform", "aboutCloudoguToken"]' +``` + +> This configuration is only effective if **all** entries are hidden (see [above](#hide-all-entries)). + +##### Hide individual entries +If individual entries in the warp-menu are not to be rendered, this can be configured via the global configuration key `disabled_warpmenu_support_entries`. +A JSON array with the entries to be hidden must be specified there. + +```yaml +disabled_warpmenu_support_entries: '["docsCloudoguComUrl", "aboutCloudoguToken"]' ``` -The configuration also includes support links, but these can be hidden with the `disabled_support_entries` type. -To do this, a string array in JSON format must be stored in the specified path. The entries correspond to -the keys of the links. For example: -`'["docsCloudoguComUrl", "aboutCloudoguToken"]'` +> This configuration is only effective if **not** all entries are hidden (see [above](#hide-all-entries)). ### Order The `order` category can be used to sort the specific Dogu categories from the `dogu.json` in the warp menu. @@ -71,10 +111,8 @@ sources: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -85,7 +123,7 @@ support: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com ``` diff --git a/go.mod b/go.mod index fe717f1..8d0ab15 100644 --- a/go.mod +++ b/go.mod @@ -1,122 +1,111 @@ module github.com/cloudogu/k8s-service-discovery -go 1.21 +go 1.22.0 + +toolchain go1.22.5 require ( github.com/bombsimon/logrusr/v2 v2.0.1 github.com/cloudogu/cesapp-lib v0.12.2 - github.com/cloudogu/k8s-dogu-operator v0.38.0 - github.com/gin-gonic/gin v1.9.1 - github.com/go-logr/logr v1.2.4 + github.com/cloudogu/k8s-dogu-operator v1.2.0 + github.com/cloudogu/k8s-registry-lib v0.3.1 + github.com/gin-gonic/gin v1.10.0 + github.com/go-logr/logr v1.4.2 github.com/hashicorp/go-multierror v1.1.1 github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.27.10 + github.com/onsi/gomega v1.34.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f - go.etcd.io/etcd/client/v2 v2.305.9 - k8s.io/api v0.28.2 - k8s.io/apimachinery v0.28.2 - k8s.io/client-go v0.28.2 - sigs.k8s.io/controller-runtime v0.16.2 - sigs.k8s.io/yaml v1.3.0 + go.etcd.io/etcd/client/v2 v2.305.15 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/api v0.31.0 + k8s.io/apimachinery v0.31.0 + k8s.io/client-go v0.31.0 + sigs.k8s.io/controller-runtime v0.19.0 + sigs.k8s.io/yaml v1.4.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bytedance/sonic v1.10.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect - github.com/cloudogu/k8s-apply-lib v0.4.2 // indirect - github.com/cloudogu/k8s-host-change v0.3.0 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/bytedance/sonic v1.12.1 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.10.0 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.6+incompatible // indirect - github.com/docker/docker-credential-helpers v0.8.0 // indirect - github.com/eapache/go-resiliency v1.4.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.7.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-logr/zapr v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.4 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/go-containerregistry v0.16.1 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-containerregistry v0.20.2 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.20.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/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - github.com/vbatts/tar-split v0.11.5 // indirect - go.etcd.io/etcd/api/v3 v3.5.9 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.etcd.io/etcd/api/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect - golang.org/x/arch v0.5.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/arch v0.9.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.6.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.2 // indirect - k8s.io/component-base v0.28.2 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 // indirect + k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 7616821..4ecdcc1 100644 --- a/go.sum +++ b/go.sum @@ -1,99 +1,120 @@ -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 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/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= -github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/cloudogu/cesapp-lib v0.0.0-20231023124814-3cbe9eb94ba3 h1:75JipMMrwnHxs6eQK34oOO4jKlJtVM8WWhjXmIgm/wQ= -github.com/cloudogu/cesapp-lib v0.0.0-20231023124814-3cbe9eb94ba3/go.mod h1:PTQqI3xs1ReJMXYE6BGTF33yAfmS4J7P8UiE4AwDMDY= -github.com/cloudogu/cesapp-lib v0.12.1 h1:FBHviZwc3fZB3cMqhK7BqRQD5HZZJcDt6BiG7kAKrTc= -github.com/cloudogu/cesapp-lib v0.12.1/go.mod h1:PTQqI3xs1ReJMXYE6BGTF33yAfmS4J7P8UiE4AwDMDY= +github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= +github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudogu/cesapp-lib v0.12.2 h1:++yK7s69DMCtpIt1nQ2x05cGAe6UH4KnsgEscV7wdq0= github.com/cloudogu/cesapp-lib v0.12.2/go.mod h1:PTQqI3xs1ReJMXYE6BGTF33yAfmS4J7P8UiE4AwDMDY= -github.com/cloudogu/k8s-apply-lib v0.4.2 h1:D5hTYvIZya+tAyGCUGaZ1T83otvpQwzrZXz5JPHQQ5M= -github.com/cloudogu/k8s-apply-lib v0.4.2/go.mod h1:jR/+7q47O5gb++4gVsmEElT8/EJoi+Msw2dVzArTPW0= -github.com/cloudogu/k8s-dogu-operator v0.26.0 h1:W+BrOYTBPC7ju7tANOpdDg8SKujtcsvEo6W42TgkV88= -github.com/cloudogu/k8s-dogu-operator v0.26.0/go.mod h1:Zh8jeUHVIGc+6G91Ay/GASbw6CMUrZd+yNOQaeFWInE= -github.com/cloudogu/k8s-dogu-operator v0.38.0 h1:qumwaQ0PrmpcLX8Clm/b4eIxDVDWbIrcqFf4ecZ36Do= -github.com/cloudogu/k8s-dogu-operator v0.38.0/go.mod h1:edKmkMd/5VJUnbk4ogth0L108CnbIkc3FM7gPbuwUeo= -github.com/cloudogu/k8s-host-change v0.3.0 h1:mbNiT/82yYHGaIg1mDDCpuUvePcOhF3ZHKnDxQ4owb8= -github.com/cloudogu/k8s-host-change v0.3.0/go.mod h1:lQrjNzcYsXkfJVur+EupKf2G6F9q3JLRGQZhksCI3Bc= -github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/cloudogu/k8s-dogu-operator v1.2.0 h1:TZ7pkQ2EBinwZMWY7H0/Bs4xVSHIWnQEbA3sWg2CMyc= +github.com/cloudogu/k8s-dogu-operator v1.2.0/go.mod h1:GnYsLM82oVlf4szJtJ2XQuOf/B5IcRVj8Wk+7jPPNa0= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240902154134-ac5de5082fd2 h1:pu0NewkMER/gXRdNV2kE0c6ae6D2j5kF1gLMu11k+dM= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240902154134-ac5de5082fd2/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240903085344-8243d9b2a921 h1:CvL2tOOEY3wKIZ3bmnvxXHSwL+BO+Nn0Ok2js2U+02k= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240903085344-8243d9b2a921/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240903144847-29a402fef2a4 h1:q+CzYCvPN6Md8Pl0NBSIO+/FFXVTw/9UKlSpjg2/mPY= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240903144847-29a402fef2a4/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904061508-05f892e03923 h1:pqkZfUFgSgfgcly/hi1llGA3GaB3T1jyDx3jhPnFGTk= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904061508-05f892e03923/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904064049-025690531ee0 h1:e85GZ10DOYeRiN8a7InB88P8wERJabf36gSFxhGXYK8= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904064049-025690531ee0/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904095659-19d33e7cb7b8 h1:DXkyNYhuKrfVZGAgPTIfhvXmFu16FgxclOXfItmgeow= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904095659-19d33e7cb7b8/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904125215-38d25f37caf9 h1:iBnsM5N/4RJwLjIf1nNw/TZLyibavvBaWP7AzIDmnzE= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240904125215-38d25f37caf9/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240906114853-a5c3c4c9a088 h1:SHL35qUOd7vaE1VbZp0kn6aMbMwp6vRY6NcP/ufk1qM= +github.com/cloudogu/k8s-registry-lib v0.2.2-0.20240906114853-a5c3c4c9a088/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudogu/k8s-registry-lib v0.3.1 h1:ew+/CupcQUv9HlFWme/TL9EjaxiCc/4L0gVSg9A1b1k= +github.com/cloudogu/k8s-registry-lib v0.3.1/go.mod h1:OHIrWCAOcc4nlmBK8G+vdHHJ8vo5QQvKCKIGTiFwYBo= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= -github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= -github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= -github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0= -github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/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/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= +github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +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/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.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= -github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-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/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-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.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.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= -github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -105,28 +126,27 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= -github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= +github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= 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-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +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/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -141,14 +161,13 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr 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.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -156,25 +175,43 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY= +github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= 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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -182,33 +219,39 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 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/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= +github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +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/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -217,8 +260,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= 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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -226,76 +270,74 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/testcontainers/testcontainers-go/modules/k3s v0.33.0 h1:vKz46Z+vClMc6MNnwpcw8tNjOOprJxWzsn4J+1noTM4= +github.com/testcontainers/testcontainers-go/modules/k3s v0.33.0/go.mod h1:3ePe1rQStxDjBKN05hxN+5Z16hNf+Iu38uIxABmIGk0= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f h1:oqdnd6OGlOUu1InG37hWcCB3a+Jy3fwjylyVboaNMwY= github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f/go.mod h1:X3Dd1SB8Gt1V968NTzpKFjMM6O8ccta2NPC6MprOxZQ= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= -github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +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= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= -go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= -go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= -go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= -go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk= +go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM= +go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA= +go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU= +go.etcd.io/etcd/client/v2 v2.305.15 h1:VG2xbf8Vz1KJh65Ar2V5eDmfkp1bpzkSEHlhJM3usp8= +go.etcd.io/etcd/client/v2 v2.305.15/go.mod h1:Ad5dRjPVb/n5yXgAWQ/hXzuXXkBk0Y658ocuXYaUU48= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +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.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= -golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= +golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= +golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -305,64 +347,47 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= 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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -378,29 +403,26 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= -k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= -k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f h1:eeEUOoGYWhOz7EyXqhlR2zHKNw2mNJ9vzJmub6YN6kk= -k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +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-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= +k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= +k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI= +k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= -sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/k8s/dev-resources/k8s-ces-warp-config.yaml b/k8s/dev-resources/k8s-ces-warp-config.yaml index 20bd3ea..b7c1c5a 100644 --- a/k8s/dev-resources/k8s-ces-warp-config.yaml +++ b/k8s/dev-resources/k8s-ces-warp-config.yaml @@ -2,10 +2,8 @@ sources: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -16,6 +14,6 @@ support: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com diff --git a/k8s/helm/Chart.yaml b/k8s/helm/Chart.yaml index e983475..25e8bf4 100644 --- a/k8s/helm/Chart.yaml +++ b/k8s/helm/Chart.yaml @@ -22,8 +22,3 @@ version: 0.0.0-replaceme # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. appVersion: "0.0.0-replaceme" - -annotations: - # For k8s-etcd it is important to include "prerelease"-versions like "3.5.7-4", so there must be a "-0" after the patch-version. - # see https://helm.sh/docs/chart_best_practices/dependencies/#prerelease-versions for more information - "k8s.cloudogu.com/ces-dependency/k8s-etcd": "^3.5.x-0" \ No newline at end of file diff --git a/k8s/helm/component-patch-tpl.yaml b/k8s/helm/component-patch-tpl.yaml index e464b4f..3dc0eb1 100644 --- a/k8s/helm/component-patch-tpl.yaml +++ b/k8s/helm/component-patch-tpl.yaml @@ -1,7 +1,7 @@ apiVersion: v1 values: images: - serviceDiscovery: cloudogu/k8s-service-discovery:0.15.0 + serviceDiscovery: cloudogu/k8s-service-discovery:0.15.1 kubeRbacProxy: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1 patches: values.yaml: diff --git a/k8s/helm/values.yaml b/k8s/helm/values.yaml index 6c2b645..77d5482 100644 --- a/k8s/helm/values.yaml +++ b/k8s/helm/values.yaml @@ -4,10 +4,8 @@ cesWarpConfig: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -18,9 +16,9 @@ cesWarpConfig: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com kubeRbacProxy: image: repository: gcr.io/kubebuilder/kube-rbac-proxy @@ -35,7 +33,7 @@ kubeRbacProxy: manager: image: repository: cloudogu/k8s-service-discovery - tag: 0.15.0 + tag: 0.15.1 env: logLevel: info stage: production diff --git a/k8s/k8s-ces-warp-config.yaml b/k8s/k8s-ces-warp-config.yaml index 27aa4ef..c142820 100644 --- a/k8s/k8s-ces-warp-config.yaml +++ b/k8s/k8s-ces-warp-config.yaml @@ -14,10 +14,8 @@ data: - path: /dogu type: dogus tag: warp - - path: /config/nginx/externals + - path: externals type: externals - - path: /config/_global/disabled_warpmenu_support_entries - type: disabled_support_entries target: /var/www/html/warp/menu.json order: Development Apps: 100 @@ -28,6 +26,6 @@ data: - identifier: aboutCloudoguToken external: false href: /info/about - - identifier: myCloudogu + - identifier: platform external: true - href: https://my.cloudogu.com/ + href: https://platform.cloudogu.com diff --git a/main.go b/main.go index d08f5ad..2a0968a 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,15 @@ package main import ( "flag" "fmt" - "os" - + "github.com/cloudogu/k8s-registry-lib/dogu" + "github.com/cloudogu/k8s-registry-lib/repository" + "github.com/cloudogu/k8s-service-discovery/controllers/warp" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ginlogrus "github.com/toorop/gin-logrus" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "os" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -22,11 +26,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" // +kubebuilder:scaffold:imports - "github.com/cloudogu/cesapp-lib/registry" "github.com/cloudogu/k8s-dogu-operator/api/v1" "github.com/cloudogu/k8s-service-discovery/controllers" - "github.com/cloudogu/k8s-service-discovery/controllers/cesregistry" "github.com/cloudogu/k8s-service-discovery/controllers/logging" "github.com/cloudogu/k8s-service-discovery/controllers/ssl" ) @@ -91,31 +93,35 @@ func startManager() error { return fmt.Errorf("failed to create ingress class creator: %w", err) } - reg, err := cesregistry.Create(watchNamespace) + clientset, err := getK8sClientSet(k8sManager.GetConfig()) if err != nil { - return fmt.Errorf("failed to create registry: %w", err) + return fmt.Errorf("failed to create k8s client set: %w", err) } + configMapInterface := clientset.CoreV1().ConfigMaps(watchNamespace) + doguVersionRegistry := dogu.NewDoguVersionRegistry(configMapInterface) + localDoguRepo := dogu.NewLocalDoguDescriptorRepository(configMapInterface) + globalConfigRepo := repository.NewGlobalConfigRepository(configMapInterface) - provideSSLAPI(reg) + provideSSLAPI(globalConfigRepo) - if err = handleWarpMenuCreation(k8sManager, reg, watchNamespace, eventRecorder); err != nil { + if err = handleWarpMenuCreation(k8sManager, doguVersionRegistry, localDoguRepo, watchNamespace, eventRecorder, globalConfigRepo); err != nil { return fmt.Errorf("failed to create warp menu creator: %w", err) } - if err = handleSslUpdates(k8sManager, watchNamespace, reg, eventRecorder); err != nil { + if err = handleSslUpdates(k8sManager, watchNamespace, globalConfigRepo, eventRecorder); err != nil { return fmt.Errorf("failed to create ssl certificate updater: %w", err) } - if err = handleSelfsignedCertificateUpdates(k8sManager, watchNamespace, reg, eventRecorder); err != nil { + if err = handleSelfsignedCertificateUpdates(k8sManager, watchNamespace, globalConfigRepo, eventRecorder); err != nil { return fmt.Errorf("failed to create selfsigned certificate updater: %w", err) } - ingressUpdater, err := controllers.NewIngressUpdater(k8sManager.GetClient(), reg.GlobalConfig(), watchNamespace, IngressClassName, eventRecorder) + ingressUpdater, err := controllers.NewIngressUpdater(k8sManager.GetClient(), globalConfigRepo, watchNamespace, IngressClassName, eventRecorder) if err != nil { return fmt.Errorf("failed to create new ingress updater: %w", err) } - if err = handleMaintenanceMode(k8sManager, watchNamespace, ingressUpdater, eventRecorder); err != nil { + if err = handleMaintenanceMode(k8sManager, watchNamespace, ingressUpdater, eventRecorder, globalConfigRepo); err != nil { return err } @@ -130,6 +136,15 @@ func startManager() error { return nil } +func getK8sClientSet(config *rest.Config) (*kubernetes.Clientset, error) { + k8sClientSet, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create k8s client set: %w", err) + } + + return k8sClientSet, nil +} + func readWatchNamespace() (string, error) { watchNamespace, found := os.LookupEnv(namespaceEnvVar) if !found { @@ -140,9 +155,9 @@ func readWatchNamespace() (string, error) { return watchNamespace, nil } -func provideSSLAPI(reg registry.Registry) { +func provideSSLAPI(globalConfigRepo controllers.GlobalConfigRepository) { go func() { - router := createSSLAPIRouter(reg) + router := createSSLAPIRouter(globalConfigRepo) err := router.Run(fmt.Sprintf(":%d", apiPort)) if err != nil { logger.Error(fmt.Errorf("failed to start gin router %w", err), "SSL api error") @@ -206,8 +221,8 @@ func handleIngressClassCreation(k8sManager k8sManager, namespace string, recorde return nil } -func handleWarpMenuCreation(k8sManager k8sManager, registry registry.Registry, namespace string, recorder record.EventRecorder) error { - warpMenuCreator := controllers.NewWarpMenuCreator(k8sManager.GetClient(), registry, namespace, recorder) +func handleWarpMenuCreation(k8sManager k8sManager, doguVersionRegistry warp.DoguVersionRegistry, localDoguRepo warp.LocalDoguRepo, namespace string, recorder record.EventRecorder, globalConfigRepo warp.GlobalConfigRepository) error { + warpMenuCreator := controllers.NewWarpMenuCreator(k8sManager.GetClient(), doguVersionRegistry, localDoguRepo, namespace, recorder, globalConfigRepo) if err := k8sManager.Add(warpMenuCreator); err != nil { return fmt.Errorf("failed to add warp menu creator as runnable to the manager: %w", err) @@ -216,8 +231,8 @@ func handleWarpMenuCreation(k8sManager k8sManager, registry registry.Registry, n return nil } -func handleSslUpdates(k8sManager k8sManager, namespace string, reg registry.Registry, recorder record.EventRecorder) error { - sslUpdater := controllers.NewSslCertificateUpdater(k8sManager.GetClient(), namespace, reg, recorder) +func handleSslUpdates(k8sManager k8sManager, namespace string, globalConfigRepo controllers.GlobalConfigRepository, recorder record.EventRecorder) error { + sslUpdater := controllers.NewSslCertificateUpdater(k8sManager.GetClient(), namespace, globalConfigRepo, recorder) if err := k8sManager.Add(sslUpdater); err != nil { return fmt.Errorf("failed to add ssl certificate updater as runnable to the manager: %w", err) @@ -226,8 +241,8 @@ func handleSslUpdates(k8sManager k8sManager, namespace string, reg registry.Regi return nil } -func handleSelfsignedCertificateUpdates(k8sManager k8sManager, namespace string, reg registry.Registry, recorder record.EventRecorder) error { - selfsignedCertificateUpdater := controllers.NewSelfsignedCertificateUpdater(k8sManager.GetClient(), namespace, reg, recorder) +func handleSelfsignedCertificateUpdates(k8sManager k8sManager, namespace string, globalConfigRepo controllers.GlobalConfigRepository, recorder record.EventRecorder) error { + selfsignedCertificateUpdater := controllers.NewSelfsignedCertificateUpdater(k8sManager.GetClient(), namespace, globalConfigRepo, recorder) if err := k8sManager.Add(selfsignedCertificateUpdater); err != nil { return fmt.Errorf("failed to add selfsigned certificate updater as runnable to the manager: %w", err) @@ -236,8 +251,8 @@ func handleSelfsignedCertificateUpdates(k8sManager k8sManager, namespace string, return nil } -func handleMaintenanceMode(k8sManager k8sManager, namespace string, updater controllers.IngressUpdater, recorder record.EventRecorder) error { - maintenanceModeUpdater, err := controllers.NewMaintenanceModeUpdater(k8sManager.GetClient(), namespace, updater, recorder) +func handleMaintenanceMode(k8sManager k8sManager, namespace string, updater controllers.IngressUpdater, recorder record.EventRecorder, globalConfigRepo *repository.GlobalConfigRepository) error { + maintenanceModeUpdater, err := controllers.NewMaintenanceModeUpdater(k8sManager.GetClient(), namespace, updater, recorder, globalConfigRepo) if err != nil { return fmt.Errorf("failed to create new maintenance updater: %w", err) } @@ -275,10 +290,10 @@ func addChecks(mgr k8sManager) error { return nil } -func createSSLAPIRouter(etcdRegistry registry.Registry) *gin.Engine { +func createSSLAPIRouter(globalConfigRepo controllers.GlobalConfigRepository) *gin.Engine { router := gin.New() router.Use(ginlogrus.Logger(logrus.StandardLogger()), gin.Recovery()) logger.Info("Setup ssl api") - ssl.SetupAPI(router, etcdRegistry.GlobalConfig()) + ssl.SetupAPI(router, globalConfigRepo) return router } diff --git a/main_test.go b/main_test.go index 7a7c987..475556c 100644 --- a/main_test.go +++ b/main_test.go @@ -58,7 +58,7 @@ func Test_startManager(t *testing.T) { // given err := os.Unsetenv("WATCH_NAMESPACE") require.NoError(t, err) - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) oldNewManger := ctrl.NewManager defer func() { ctrl.NewManager = oldNewManger }() ctrl.NewManager = func(config *rest.Config, options manager.Options) (manager.Manager, error) { @@ -95,7 +95,7 @@ func Test_startManager(t *testing.T) { t.Run("fail setup when error on Add", func(t *testing.T) { // given - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) k8sManager.EXPECT().GetClient().Return(client) k8sManager.EXPECT().Add(mock.Anything).Return(assert.AnError) k8sManager.EXPECT().GetEventRecorderFor("k8s-service-discovery-controller-manager").Return(nil) @@ -114,17 +114,20 @@ func Test_startManager(t *testing.T) { assert.ErrorContains(t, err, "failed to create ingress class creator: failed to add ingress class creator as runnable to the manager") }) + skipNameValidation := true + t.Run("fail setup when error on AddHealthzCheck", func(t *testing.T) { // given - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) k8sManager.EXPECT().GetClient().Return(client) k8sManager.EXPECT().Add(mock.Anything).Return(nil) k8sManager.EXPECT().GetEventRecorderFor("k8s-service-discovery-controller-manager").Return(nil) - k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{}) + k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{SkipNameValidation: &skipNameValidation}) k8sManager.EXPECT().GetScheme().Return(scheme) k8sManager.EXPECT().GetLogger().Return(logger) k8sManager.EXPECT().GetCache().Return(nil) k8sManager.EXPECT().AddHealthzCheck(mock.Anything, mock.Anything).Return(assert.AnError) + k8sManager.EXPECT().GetConfig().Return(&rest.Config{}) oldNewManger := ctrl.NewManager defer func() { ctrl.NewManager = oldNewManger }() ctrl.NewManager = func(config *rest.Config, options manager.Options) (manager.Manager, error) { @@ -142,16 +145,17 @@ func Test_startManager(t *testing.T) { t.Run("fail setup when error on AddReadyzCheck", func(t *testing.T) { // given - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) k8sManager.EXPECT().GetClient().Return(client) k8sManager.EXPECT().Add(mock.Anything).Return(nil) k8sManager.EXPECT().GetEventRecorderFor("k8s-service-discovery-controller-manager").Return(nil) - k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{}) + k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{SkipNameValidation: &skipNameValidation}) k8sManager.EXPECT().GetScheme().Return(scheme) k8sManager.EXPECT().GetLogger().Return(logger) k8sManager.EXPECT().GetCache().Return(nil) k8sManager.EXPECT().AddHealthzCheck(mock.Anything, mock.Anything).Return(nil) k8sManager.EXPECT().AddReadyzCheck(mock.Anything, mock.Anything).Return(assert.AnError) + k8sManager.EXPECT().GetConfig().Return(&rest.Config{}) oldNewManger := ctrl.NewManager defer func() { ctrl.NewManager = oldNewManger }() ctrl.NewManager = func(config *rest.Config, options manager.Options) (manager.Manager, error) { @@ -169,17 +173,18 @@ func Test_startManager(t *testing.T) { t.Run("fail setup when error on Start", func(t *testing.T) { // given - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) k8sManager.EXPECT().GetClient().Return(client) k8sManager.EXPECT().Add(mock.Anything).Return(nil) k8sManager.EXPECT().GetEventRecorderFor("k8s-service-discovery-controller-manager").Return(nil) - k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{}) + k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{SkipNameValidation: &skipNameValidation}) k8sManager.EXPECT().GetScheme().Return(scheme) k8sManager.EXPECT().GetLogger().Return(logger) k8sManager.EXPECT().GetCache().Return(nil) k8sManager.EXPECT().AddHealthzCheck(mock.Anything, mock.Anything).Return(nil) k8sManager.EXPECT().AddReadyzCheck(mock.Anything, mock.Anything).Return(nil) k8sManager.EXPECT().Start(mock.Anything).Return(assert.AnError) + k8sManager.EXPECT().GetConfig().Return(&rest.Config{}) oldNewManger := ctrl.NewManager defer func() { ctrl.NewManager = oldNewManger }() ctrl.NewManager = func(config *rest.Config, options manager.Options) (manager.Manager, error) { @@ -197,17 +202,18 @@ func Test_startManager(t *testing.T) { t.Run("should setup successfully", func(t *testing.T) { // given - k8sManager := newMockK8sManager(t) + k8sManager := NewMockManager(t) k8sManager.EXPECT().GetClient().Return(client) k8sManager.EXPECT().Add(mock.Anything).Return(nil) k8sManager.EXPECT().GetEventRecorderFor("k8s-service-discovery-controller-manager").Return(nil) - k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{}) + k8sManager.EXPECT().GetControllerOptions().Return(config.Controller{SkipNameValidation: &skipNameValidation}) k8sManager.EXPECT().GetScheme().Return(scheme) k8sManager.EXPECT().GetLogger().Return(logger) k8sManager.EXPECT().GetCache().Return(nil) k8sManager.EXPECT().AddHealthzCheck(mock.Anything, mock.Anything).Return(nil) k8sManager.EXPECT().AddReadyzCheck(mock.Anything, mock.Anything).Return(nil) k8sManager.EXPECT().Start(mock.Anything).Return(nil) + k8sManager.EXPECT().GetConfig().Return(&rest.Config{}) oldNewManger := ctrl.NewManager defer func() { ctrl.NewManager = oldNewManger }() ctrl.NewManager = func(config *rest.Config, options manager.Options) (manager.Manager, error) { diff --git a/mock_Manager_test.go b/mock_Manager_test.go new file mode 100644 index 0000000..66f6067 --- /dev/null +++ b/mock_Manager_test.go @@ -0,0 +1,827 @@ +// Code generated by mockery v2.30.1. DO NOT EDIT. + +package main + +import ( + cache "sigs.k8s.io/controller-runtime/pkg/cache" + client "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + + config "sigs.k8s.io/controller-runtime/pkg/config" + + context "context" + + healthz "sigs.k8s.io/controller-runtime/pkg/healthz" + + http "net/http" + + logr "github.com/go-logr/logr" + + meta "k8s.io/apimachinery/pkg/api/meta" + + mock "github.com/stretchr/testify/mock" + + record "k8s.io/client-go/tools/record" + + rest "k8s.io/client-go/rest" + + runtime "k8s.io/apimachinery/pkg/runtime" + + webhook "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +// MockManager is an autogenerated mock type for the Manager type +type MockManager struct { + mock.Mock +} + +type MockManager_Expecter struct { + mock *mock.Mock +} + +func (_m *MockManager) EXPECT() *MockManager_Expecter { + return &MockManager_Expecter{mock: &_m.Mock} +} + +// Add provides a mock function with given fields: _a0 +func (_m *MockManager) Add(_a0 manager.Runnable) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(manager.Runnable) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockManager_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' +type MockManager_Add_Call struct { + *mock.Call +} + +// Add is a helper method to define mock.On call +// - _a0 Runnable +func (_e *MockManager_Expecter) Add(_a0 interface{}) *MockManager_Add_Call { + return &MockManager_Add_Call{Call: _e.mock.On("Add", _a0)} +} + +func (_c *MockManager_Add_Call) Run(run func(_a0 manager.Runnable)) *MockManager_Add_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(manager.Runnable)) + }) + return _c +} + +func (_c *MockManager_Add_Call) Return(_a0 error) *MockManager_Add_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_Add_Call) RunAndReturn(run func(manager.Runnable) error) *MockManager_Add_Call { + _c.Call.Return(run) + return _c +} + +// AddHealthzCheck provides a mock function with given fields: name, check +func (_m *MockManager) AddHealthzCheck(name string, check healthz.Checker) error { + ret := _m.Called(name, check) + + var r0 error + if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { + r0 = rf(name, check) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockManager_AddHealthzCheck_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHealthzCheck' +type MockManager_AddHealthzCheck_Call struct { + *mock.Call +} + +// AddHealthzCheck is a helper method to define mock.On call +// - name string +// - check healthz.Checker +func (_e *MockManager_Expecter) AddHealthzCheck(name interface{}, check interface{}) *MockManager_AddHealthzCheck_Call { + return &MockManager_AddHealthzCheck_Call{Call: _e.mock.On("AddHealthzCheck", name, check)} +} + +func (_c *MockManager_AddHealthzCheck_Call) Run(run func(name string, check healthz.Checker)) *MockManager_AddHealthzCheck_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(healthz.Checker)) + }) + return _c +} + +func (_c *MockManager_AddHealthzCheck_Call) Return(_a0 error) *MockManager_AddHealthzCheck_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_AddHealthzCheck_Call) RunAndReturn(run func(string, healthz.Checker) error) *MockManager_AddHealthzCheck_Call { + _c.Call.Return(run) + return _c +} + +// AddMetricsServerExtraHandler provides a mock function with given fields: path, handler +func (_m *MockManager) AddMetricsServerExtraHandler(path string, handler http.Handler) error { + ret := _m.Called(path, handler) + + var r0 error + if rf, ok := ret.Get(0).(func(string, http.Handler) error); ok { + r0 = rf(path, handler) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockManager_AddMetricsServerExtraHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMetricsServerExtraHandler' +type MockManager_AddMetricsServerExtraHandler_Call struct { + *mock.Call +} + +// AddMetricsServerExtraHandler is a helper method to define mock.On call +// - path string +// - handler http.Handler +func (_e *MockManager_Expecter) AddMetricsServerExtraHandler(path interface{}, handler interface{}) *MockManager_AddMetricsServerExtraHandler_Call { + return &MockManager_AddMetricsServerExtraHandler_Call{Call: _e.mock.On("AddMetricsServerExtraHandler", path, handler)} +} + +func (_c *MockManager_AddMetricsServerExtraHandler_Call) Run(run func(path string, handler http.Handler)) *MockManager_AddMetricsServerExtraHandler_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(http.Handler)) + }) + return _c +} + +func (_c *MockManager_AddMetricsServerExtraHandler_Call) Return(_a0 error) *MockManager_AddMetricsServerExtraHandler_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_AddMetricsServerExtraHandler_Call) RunAndReturn(run func(string, http.Handler) error) *MockManager_AddMetricsServerExtraHandler_Call { + _c.Call.Return(run) + return _c +} + +// AddReadyzCheck provides a mock function with given fields: name, check +func (_m *MockManager) AddReadyzCheck(name string, check healthz.Checker) error { + ret := _m.Called(name, check) + + var r0 error + if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { + r0 = rf(name, check) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockManager_AddReadyzCheck_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddReadyzCheck' +type MockManager_AddReadyzCheck_Call struct { + *mock.Call +} + +// AddReadyzCheck is a helper method to define mock.On call +// - name string +// - check healthz.Checker +func (_e *MockManager_Expecter) AddReadyzCheck(name interface{}, check interface{}) *MockManager_AddReadyzCheck_Call { + return &MockManager_AddReadyzCheck_Call{Call: _e.mock.On("AddReadyzCheck", name, check)} +} + +func (_c *MockManager_AddReadyzCheck_Call) Run(run func(name string, check healthz.Checker)) *MockManager_AddReadyzCheck_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(healthz.Checker)) + }) + return _c +} + +func (_c *MockManager_AddReadyzCheck_Call) Return(_a0 error) *MockManager_AddReadyzCheck_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_AddReadyzCheck_Call) RunAndReturn(run func(string, healthz.Checker) error) *MockManager_AddReadyzCheck_Call { + _c.Call.Return(run) + return _c +} + +// Elected provides a mock function with given fields: +func (_m *MockManager) Elected() <-chan struct{} { + ret := _m.Called() + + var r0 <-chan struct{} + if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan struct{}) + } + } + + return r0 +} + +// MockManager_Elected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Elected' +type MockManager_Elected_Call struct { + *mock.Call +} + +// Elected is a helper method to define mock.On call +func (_e *MockManager_Expecter) Elected() *MockManager_Elected_Call { + return &MockManager_Elected_Call{Call: _e.mock.On("Elected")} +} + +func (_c *MockManager_Elected_Call) Run(run func()) *MockManager_Elected_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_Elected_Call) Return(_a0 <-chan struct{}) *MockManager_Elected_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_Elected_Call) RunAndReturn(run func() <-chan struct{}) *MockManager_Elected_Call { + _c.Call.Return(run) + return _c +} + +// GetAPIReader provides a mock function with given fields: +func (_m *MockManager) GetAPIReader() client.Reader { + ret := _m.Called() + + var r0 client.Reader + if rf, ok := ret.Get(0).(func() client.Reader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.Reader) + } + } + + return r0 +} + +// MockManager_GetAPIReader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAPIReader' +type MockManager_GetAPIReader_Call struct { + *mock.Call +} + +// GetAPIReader is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetAPIReader() *MockManager_GetAPIReader_Call { + return &MockManager_GetAPIReader_Call{Call: _e.mock.On("GetAPIReader")} +} + +func (_c *MockManager_GetAPIReader_Call) Run(run func()) *MockManager_GetAPIReader_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetAPIReader_Call) Return(_a0 client.Reader) *MockManager_GetAPIReader_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetAPIReader_Call) RunAndReturn(run func() client.Reader) *MockManager_GetAPIReader_Call { + _c.Call.Return(run) + return _c +} + +// GetCache provides a mock function with given fields: +func (_m *MockManager) GetCache() cache.Cache { + ret := _m.Called() + + var r0 cache.Cache + if rf, ok := ret.Get(0).(func() cache.Cache); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(cache.Cache) + } + } + + return r0 +} + +// MockManager_GetCache_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCache' +type MockManager_GetCache_Call struct { + *mock.Call +} + +// GetCache is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetCache() *MockManager_GetCache_Call { + return &MockManager_GetCache_Call{Call: _e.mock.On("GetCache")} +} + +func (_c *MockManager_GetCache_Call) Run(run func()) *MockManager_GetCache_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetCache_Call) Return(_a0 cache.Cache) *MockManager_GetCache_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetCache_Call) RunAndReturn(run func() cache.Cache) *MockManager_GetCache_Call { + _c.Call.Return(run) + return _c +} + +// GetClient provides a mock function with given fields: +func (_m *MockManager) GetClient() client.Client { + ret := _m.Called() + + var r0 client.Client + if rf, ok := ret.Get(0).(func() client.Client); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.Client) + } + } + + return r0 +} + +// MockManager_GetClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClient' +type MockManager_GetClient_Call struct { + *mock.Call +} + +// GetClient is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetClient() *MockManager_GetClient_Call { + return &MockManager_GetClient_Call{Call: _e.mock.On("GetClient")} +} + +func (_c *MockManager_GetClient_Call) Run(run func()) *MockManager_GetClient_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetClient_Call) Return(_a0 client.Client) *MockManager_GetClient_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetClient_Call) RunAndReturn(run func() client.Client) *MockManager_GetClient_Call { + _c.Call.Return(run) + return _c +} + +// GetConfig provides a mock function with given fields: +func (_m *MockManager) GetConfig() *rest.Config { + ret := _m.Called() + + var r0 *rest.Config + if rf, ok := ret.Get(0).(func() *rest.Config); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rest.Config) + } + } + + return r0 +} + +// MockManager_GetConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConfig' +type MockManager_GetConfig_Call struct { + *mock.Call +} + +// GetConfig is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetConfig() *MockManager_GetConfig_Call { + return &MockManager_GetConfig_Call{Call: _e.mock.On("GetConfig")} +} + +func (_c *MockManager_GetConfig_Call) Run(run func()) *MockManager_GetConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetConfig_Call) Return(_a0 *rest.Config) *MockManager_GetConfig_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetConfig_Call) RunAndReturn(run func() *rest.Config) *MockManager_GetConfig_Call { + _c.Call.Return(run) + return _c +} + +// GetControllerOptions provides a mock function with given fields: +func (_m *MockManager) GetControllerOptions() config.Controller { + ret := _m.Called() + + var r0 config.Controller + if rf, ok := ret.Get(0).(func() config.Controller); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(config.Controller) + } + + return r0 +} + +// MockManager_GetControllerOptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetControllerOptions' +type MockManager_GetControllerOptions_Call struct { + *mock.Call +} + +// GetControllerOptions is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetControllerOptions() *MockManager_GetControllerOptions_Call { + return &MockManager_GetControllerOptions_Call{Call: _e.mock.On("GetControllerOptions")} +} + +func (_c *MockManager_GetControllerOptions_Call) Run(run func()) *MockManager_GetControllerOptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetControllerOptions_Call) Return(_a0 config.Controller) *MockManager_GetControllerOptions_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetControllerOptions_Call) RunAndReturn(run func() config.Controller) *MockManager_GetControllerOptions_Call { + _c.Call.Return(run) + return _c +} + +// GetEventRecorderFor provides a mock function with given fields: name +func (_m *MockManager) GetEventRecorderFor(name string) record.EventRecorder { + ret := _m.Called(name) + + var r0 record.EventRecorder + if rf, ok := ret.Get(0).(func(string) record.EventRecorder); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(record.EventRecorder) + } + } + + return r0 +} + +// MockManager_GetEventRecorderFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEventRecorderFor' +type MockManager_GetEventRecorderFor_Call struct { + *mock.Call +} + +// GetEventRecorderFor is a helper method to define mock.On call +// - name string +func (_e *MockManager_Expecter) GetEventRecorderFor(name interface{}) *MockManager_GetEventRecorderFor_Call { + return &MockManager_GetEventRecorderFor_Call{Call: _e.mock.On("GetEventRecorderFor", name)} +} + +func (_c *MockManager_GetEventRecorderFor_Call) Run(run func(name string)) *MockManager_GetEventRecorderFor_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockManager_GetEventRecorderFor_Call) Return(_a0 record.EventRecorder) *MockManager_GetEventRecorderFor_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetEventRecorderFor_Call) RunAndReturn(run func(string) record.EventRecorder) *MockManager_GetEventRecorderFor_Call { + _c.Call.Return(run) + return _c +} + +// GetFieldIndexer provides a mock function with given fields: +func (_m *MockManager) GetFieldIndexer() client.FieldIndexer { + ret := _m.Called() + + var r0 client.FieldIndexer + if rf, ok := ret.Get(0).(func() client.FieldIndexer); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.FieldIndexer) + } + } + + return r0 +} + +// MockManager_GetFieldIndexer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFieldIndexer' +type MockManager_GetFieldIndexer_Call struct { + *mock.Call +} + +// GetFieldIndexer is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetFieldIndexer() *MockManager_GetFieldIndexer_Call { + return &MockManager_GetFieldIndexer_Call{Call: _e.mock.On("GetFieldIndexer")} +} + +func (_c *MockManager_GetFieldIndexer_Call) Run(run func()) *MockManager_GetFieldIndexer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetFieldIndexer_Call) Return(_a0 client.FieldIndexer) *MockManager_GetFieldIndexer_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetFieldIndexer_Call) RunAndReturn(run func() client.FieldIndexer) *MockManager_GetFieldIndexer_Call { + _c.Call.Return(run) + return _c +} + +// GetHTTPClient provides a mock function with given fields: +func (_m *MockManager) GetHTTPClient() *http.Client { + ret := _m.Called() + + var r0 *http.Client + if rf, ok := ret.Get(0).(func() *http.Client); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*http.Client) + } + } + + return r0 +} + +// MockManager_GetHTTPClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetHTTPClient' +type MockManager_GetHTTPClient_Call struct { + *mock.Call +} + +// GetHTTPClient is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetHTTPClient() *MockManager_GetHTTPClient_Call { + return &MockManager_GetHTTPClient_Call{Call: _e.mock.On("GetHTTPClient")} +} + +func (_c *MockManager_GetHTTPClient_Call) Run(run func()) *MockManager_GetHTTPClient_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetHTTPClient_Call) Return(_a0 *http.Client) *MockManager_GetHTTPClient_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetHTTPClient_Call) RunAndReturn(run func() *http.Client) *MockManager_GetHTTPClient_Call { + _c.Call.Return(run) + return _c +} + +// GetLogger provides a mock function with given fields: +func (_m *MockManager) GetLogger() logr.Logger { + ret := _m.Called() + + var r0 logr.Logger + if rf, ok := ret.Get(0).(func() logr.Logger); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(logr.Logger) + } + + return r0 +} + +// MockManager_GetLogger_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLogger' +type MockManager_GetLogger_Call struct { + *mock.Call +} + +// GetLogger is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetLogger() *MockManager_GetLogger_Call { + return &MockManager_GetLogger_Call{Call: _e.mock.On("GetLogger")} +} + +func (_c *MockManager_GetLogger_Call) Run(run func()) *MockManager_GetLogger_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetLogger_Call) Return(_a0 logr.Logger) *MockManager_GetLogger_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetLogger_Call) RunAndReturn(run func() logr.Logger) *MockManager_GetLogger_Call { + _c.Call.Return(run) + return _c +} + +// GetRESTMapper provides a mock function with given fields: +func (_m *MockManager) GetRESTMapper() meta.RESTMapper { + ret := _m.Called() + + var r0 meta.RESTMapper + if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(meta.RESTMapper) + } + } + + return r0 +} + +// MockManager_GetRESTMapper_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRESTMapper' +type MockManager_GetRESTMapper_Call struct { + *mock.Call +} + +// GetRESTMapper is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetRESTMapper() *MockManager_GetRESTMapper_Call { + return &MockManager_GetRESTMapper_Call{Call: _e.mock.On("GetRESTMapper")} +} + +func (_c *MockManager_GetRESTMapper_Call) Run(run func()) *MockManager_GetRESTMapper_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetRESTMapper_Call) Return(_a0 meta.RESTMapper) *MockManager_GetRESTMapper_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetRESTMapper_Call) RunAndReturn(run func() meta.RESTMapper) *MockManager_GetRESTMapper_Call { + _c.Call.Return(run) + return _c +} + +// GetScheme provides a mock function with given fields: +func (_m *MockManager) GetScheme() *runtime.Scheme { + ret := _m.Called() + + var r0 *runtime.Scheme + if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*runtime.Scheme) + } + } + + return r0 +} + +// MockManager_GetScheme_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetScheme' +type MockManager_GetScheme_Call struct { + *mock.Call +} + +// GetScheme is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetScheme() *MockManager_GetScheme_Call { + return &MockManager_GetScheme_Call{Call: _e.mock.On("GetScheme")} +} + +func (_c *MockManager_GetScheme_Call) Run(run func()) *MockManager_GetScheme_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetScheme_Call) Return(_a0 *runtime.Scheme) *MockManager_GetScheme_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetScheme_Call) RunAndReturn(run func() *runtime.Scheme) *MockManager_GetScheme_Call { + _c.Call.Return(run) + return _c +} + +// GetWebhookServer provides a mock function with given fields: +func (_m *MockManager) GetWebhookServer() webhook.Server { + ret := _m.Called() + + var r0 webhook.Server + if rf, ok := ret.Get(0).(func() webhook.Server); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(webhook.Server) + } + } + + return r0 +} + +// MockManager_GetWebhookServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWebhookServer' +type MockManager_GetWebhookServer_Call struct { + *mock.Call +} + +// GetWebhookServer is a helper method to define mock.On call +func (_e *MockManager_Expecter) GetWebhookServer() *MockManager_GetWebhookServer_Call { + return &MockManager_GetWebhookServer_Call{Call: _e.mock.On("GetWebhookServer")} +} + +func (_c *MockManager_GetWebhookServer_Call) Run(run func()) *MockManager_GetWebhookServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockManager_GetWebhookServer_Call) Return(_a0 webhook.Server) *MockManager_GetWebhookServer_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_GetWebhookServer_Call) RunAndReturn(run func() webhook.Server) *MockManager_GetWebhookServer_Call { + _c.Call.Return(run) + return _c +} + +// Start provides a mock function with given fields: ctx +func (_m *MockManager) Start(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockManager_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type MockManager_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockManager_Expecter) Start(ctx interface{}) *MockManager_Start_Call { + return &MockManager_Start_Call{Call: _e.mock.On("Start", ctx)} +} + +func (_c *MockManager_Start_Call) Run(run func(ctx context.Context)) *MockManager_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockManager_Start_Call) Return(_a0 error) *MockManager_Start_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockManager_Start_Call) RunAndReturn(run func(context.Context) error) *MockManager_Start_Call { + _c.Call.Return(run) + return _c +} + +// NewMockManager creates a new instance of MockManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockManager(t interface { + mock.TestingT + Cleanup(func()) +}) *MockManager { + mock := &MockManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mock_k8sManager_test.go b/mock_k8sManager_test.go deleted file mode 100644 index 01a8801..0000000 --- a/mock_k8sManager_test.go +++ /dev/null @@ -1,786 +0,0 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. - -package main - -import ( - cache "sigs.k8s.io/controller-runtime/pkg/cache" - client "sigs.k8s.io/controller-runtime/pkg/client" - - config "sigs.k8s.io/controller-runtime/pkg/config" - - context "context" - - healthz "sigs.k8s.io/controller-runtime/pkg/healthz" - - http "net/http" - - logr "github.com/go-logr/logr" - - manager "sigs.k8s.io/controller-runtime/pkg/manager" - - meta "k8s.io/apimachinery/pkg/api/meta" - - mock "github.com/stretchr/testify/mock" - - record "k8s.io/client-go/tools/record" - - rest "k8s.io/client-go/rest" - - runtime "k8s.io/apimachinery/pkg/runtime" - - webhook "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// mockK8sManager is an autogenerated mock type for the k8sManager type -type mockK8sManager struct { - mock.Mock -} - -type mockK8sManager_Expecter struct { - mock *mock.Mock -} - -func (_m *mockK8sManager) EXPECT() *mockK8sManager_Expecter { - return &mockK8sManager_Expecter{mock: &_m.Mock} -} - -// Add provides a mock function with given fields: _a0 -func (_m *mockK8sManager) Add(_a0 manager.Runnable) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(manager.Runnable) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockK8sManager_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' -type mockK8sManager_Add_Call struct { - *mock.Call -} - -// Add is a helper method to define mock.On call -// - _a0 manager.Runnable -func (_e *mockK8sManager_Expecter) Add(_a0 interface{}) *mockK8sManager_Add_Call { - return &mockK8sManager_Add_Call{Call: _e.mock.On("Add", _a0)} -} - -func (_c *mockK8sManager_Add_Call) Run(run func(_a0 manager.Runnable)) *mockK8sManager_Add_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(manager.Runnable)) - }) - return _c -} - -func (_c *mockK8sManager_Add_Call) Return(_a0 error) *mockK8sManager_Add_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_Add_Call) RunAndReturn(run func(manager.Runnable) error) *mockK8sManager_Add_Call { - _c.Call.Return(run) - return _c -} - -// AddHealthzCheck provides a mock function with given fields: name, check -func (_m *mockK8sManager) AddHealthzCheck(name string, check healthz.Checker) error { - ret := _m.Called(name, check) - - var r0 error - if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { - r0 = rf(name, check) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockK8sManager_AddHealthzCheck_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHealthzCheck' -type mockK8sManager_AddHealthzCheck_Call struct { - *mock.Call -} - -// AddHealthzCheck is a helper method to define mock.On call -// - name string -// - check healthz.Checker -func (_e *mockK8sManager_Expecter) AddHealthzCheck(name interface{}, check interface{}) *mockK8sManager_AddHealthzCheck_Call { - return &mockK8sManager_AddHealthzCheck_Call{Call: _e.mock.On("AddHealthzCheck", name, check)} -} - -func (_c *mockK8sManager_AddHealthzCheck_Call) Run(run func(name string, check healthz.Checker)) *mockK8sManager_AddHealthzCheck_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(healthz.Checker)) - }) - return _c -} - -func (_c *mockK8sManager_AddHealthzCheck_Call) Return(_a0 error) *mockK8sManager_AddHealthzCheck_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_AddHealthzCheck_Call) RunAndReturn(run func(string, healthz.Checker) error) *mockK8sManager_AddHealthzCheck_Call { - _c.Call.Return(run) - return _c -} - -// AddReadyzCheck provides a mock function with given fields: name, check -func (_m *mockK8sManager) AddReadyzCheck(name string, check healthz.Checker) error { - ret := _m.Called(name, check) - - var r0 error - if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { - r0 = rf(name, check) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockK8sManager_AddReadyzCheck_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddReadyzCheck' -type mockK8sManager_AddReadyzCheck_Call struct { - *mock.Call -} - -// AddReadyzCheck is a helper method to define mock.On call -// - name string -// - check healthz.Checker -func (_e *mockK8sManager_Expecter) AddReadyzCheck(name interface{}, check interface{}) *mockK8sManager_AddReadyzCheck_Call { - return &mockK8sManager_AddReadyzCheck_Call{Call: _e.mock.On("AddReadyzCheck", name, check)} -} - -func (_c *mockK8sManager_AddReadyzCheck_Call) Run(run func(name string, check healthz.Checker)) *mockK8sManager_AddReadyzCheck_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(healthz.Checker)) - }) - return _c -} - -func (_c *mockK8sManager_AddReadyzCheck_Call) Return(_a0 error) *mockK8sManager_AddReadyzCheck_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_AddReadyzCheck_Call) RunAndReturn(run func(string, healthz.Checker) error) *mockK8sManager_AddReadyzCheck_Call { - _c.Call.Return(run) - return _c -} - -// Elected provides a mock function with given fields: -func (_m *mockK8sManager) Elected() <-chan struct{} { - ret := _m.Called() - - var r0 <-chan struct{} - if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan struct{}) - } - } - - return r0 -} - -// mockK8sManager_Elected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Elected' -type mockK8sManager_Elected_Call struct { - *mock.Call -} - -// Elected is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) Elected() *mockK8sManager_Elected_Call { - return &mockK8sManager_Elected_Call{Call: _e.mock.On("Elected")} -} - -func (_c *mockK8sManager_Elected_Call) Run(run func()) *mockK8sManager_Elected_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_Elected_Call) Return(_a0 <-chan struct{}) *mockK8sManager_Elected_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_Elected_Call) RunAndReturn(run func() <-chan struct{}) *mockK8sManager_Elected_Call { - _c.Call.Return(run) - return _c -} - -// GetAPIReader provides a mock function with given fields: -func (_m *mockK8sManager) GetAPIReader() client.Reader { - ret := _m.Called() - - var r0 client.Reader - if rf, ok := ret.Get(0).(func() client.Reader); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Reader) - } - } - - return r0 -} - -// mockK8sManager_GetAPIReader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAPIReader' -type mockK8sManager_GetAPIReader_Call struct { - *mock.Call -} - -// GetAPIReader is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetAPIReader() *mockK8sManager_GetAPIReader_Call { - return &mockK8sManager_GetAPIReader_Call{Call: _e.mock.On("GetAPIReader")} -} - -func (_c *mockK8sManager_GetAPIReader_Call) Run(run func()) *mockK8sManager_GetAPIReader_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetAPIReader_Call) Return(_a0 client.Reader) *mockK8sManager_GetAPIReader_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetAPIReader_Call) RunAndReturn(run func() client.Reader) *mockK8sManager_GetAPIReader_Call { - _c.Call.Return(run) - return _c -} - -// GetCache provides a mock function with given fields: -func (_m *mockK8sManager) GetCache() cache.Cache { - ret := _m.Called() - - var r0 cache.Cache - if rf, ok := ret.Get(0).(func() cache.Cache); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cache.Cache) - } - } - - return r0 -} - -// mockK8sManager_GetCache_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCache' -type mockK8sManager_GetCache_Call struct { - *mock.Call -} - -// GetCache is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetCache() *mockK8sManager_GetCache_Call { - return &mockK8sManager_GetCache_Call{Call: _e.mock.On("GetCache")} -} - -func (_c *mockK8sManager_GetCache_Call) Run(run func()) *mockK8sManager_GetCache_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetCache_Call) Return(_a0 cache.Cache) *mockK8sManager_GetCache_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetCache_Call) RunAndReturn(run func() cache.Cache) *mockK8sManager_GetCache_Call { - _c.Call.Return(run) - return _c -} - -// GetClient provides a mock function with given fields: -func (_m *mockK8sManager) GetClient() client.Client { - ret := _m.Called() - - var r0 client.Client - if rf, ok := ret.Get(0).(func() client.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Client) - } - } - - return r0 -} - -// mockK8sManager_GetClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClient' -type mockK8sManager_GetClient_Call struct { - *mock.Call -} - -// GetClient is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetClient() *mockK8sManager_GetClient_Call { - return &mockK8sManager_GetClient_Call{Call: _e.mock.On("GetClient")} -} - -func (_c *mockK8sManager_GetClient_Call) Run(run func()) *mockK8sManager_GetClient_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetClient_Call) Return(_a0 client.Client) *mockK8sManager_GetClient_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetClient_Call) RunAndReturn(run func() client.Client) *mockK8sManager_GetClient_Call { - _c.Call.Return(run) - return _c -} - -// GetConfig provides a mock function with given fields: -func (_m *mockK8sManager) GetConfig() *rest.Config { - ret := _m.Called() - - var r0 *rest.Config - if rf, ok := ret.Get(0).(func() *rest.Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rest.Config) - } - } - - return r0 -} - -// mockK8sManager_GetConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConfig' -type mockK8sManager_GetConfig_Call struct { - *mock.Call -} - -// GetConfig is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetConfig() *mockK8sManager_GetConfig_Call { - return &mockK8sManager_GetConfig_Call{Call: _e.mock.On("GetConfig")} -} - -func (_c *mockK8sManager_GetConfig_Call) Run(run func()) *mockK8sManager_GetConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetConfig_Call) Return(_a0 *rest.Config) *mockK8sManager_GetConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetConfig_Call) RunAndReturn(run func() *rest.Config) *mockK8sManager_GetConfig_Call { - _c.Call.Return(run) - return _c -} - -// GetControllerOptions provides a mock function with given fields: -func (_m *mockK8sManager) GetControllerOptions() config.Controller { - ret := _m.Called() - - var r0 config.Controller - if rf, ok := ret.Get(0).(func() config.Controller); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(config.Controller) - } - - return r0 -} - -// mockK8sManager_GetControllerOptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetControllerOptions' -type mockK8sManager_GetControllerOptions_Call struct { - *mock.Call -} - -// GetControllerOptions is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetControllerOptions() *mockK8sManager_GetControllerOptions_Call { - return &mockK8sManager_GetControllerOptions_Call{Call: _e.mock.On("GetControllerOptions")} -} - -func (_c *mockK8sManager_GetControllerOptions_Call) Run(run func()) *mockK8sManager_GetControllerOptions_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetControllerOptions_Call) Return(_a0 config.Controller) *mockK8sManager_GetControllerOptions_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetControllerOptions_Call) RunAndReturn(run func() config.Controller) *mockK8sManager_GetControllerOptions_Call { - _c.Call.Return(run) - return _c -} - -// GetEventRecorderFor provides a mock function with given fields: name -func (_m *mockK8sManager) GetEventRecorderFor(name string) record.EventRecorder { - ret := _m.Called(name) - - var r0 record.EventRecorder - if rf, ok := ret.Get(0).(func(string) record.EventRecorder); ok { - r0 = rf(name) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(record.EventRecorder) - } - } - - return r0 -} - -// mockK8sManager_GetEventRecorderFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEventRecorderFor' -type mockK8sManager_GetEventRecorderFor_Call struct { - *mock.Call -} - -// GetEventRecorderFor is a helper method to define mock.On call -// - name string -func (_e *mockK8sManager_Expecter) GetEventRecorderFor(name interface{}) *mockK8sManager_GetEventRecorderFor_Call { - return &mockK8sManager_GetEventRecorderFor_Call{Call: _e.mock.On("GetEventRecorderFor", name)} -} - -func (_c *mockK8sManager_GetEventRecorderFor_Call) Run(run func(name string)) *mockK8sManager_GetEventRecorderFor_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *mockK8sManager_GetEventRecorderFor_Call) Return(_a0 record.EventRecorder) *mockK8sManager_GetEventRecorderFor_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetEventRecorderFor_Call) RunAndReturn(run func(string) record.EventRecorder) *mockK8sManager_GetEventRecorderFor_Call { - _c.Call.Return(run) - return _c -} - -// GetFieldIndexer provides a mock function with given fields: -func (_m *mockK8sManager) GetFieldIndexer() client.FieldIndexer { - ret := _m.Called() - - var r0 client.FieldIndexer - if rf, ok := ret.Get(0).(func() client.FieldIndexer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.FieldIndexer) - } - } - - return r0 -} - -// mockK8sManager_GetFieldIndexer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFieldIndexer' -type mockK8sManager_GetFieldIndexer_Call struct { - *mock.Call -} - -// GetFieldIndexer is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetFieldIndexer() *mockK8sManager_GetFieldIndexer_Call { - return &mockK8sManager_GetFieldIndexer_Call{Call: _e.mock.On("GetFieldIndexer")} -} - -func (_c *mockK8sManager_GetFieldIndexer_Call) Run(run func()) *mockK8sManager_GetFieldIndexer_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetFieldIndexer_Call) Return(_a0 client.FieldIndexer) *mockK8sManager_GetFieldIndexer_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetFieldIndexer_Call) RunAndReturn(run func() client.FieldIndexer) *mockK8sManager_GetFieldIndexer_Call { - _c.Call.Return(run) - return _c -} - -// GetHTTPClient provides a mock function with given fields: -func (_m *mockK8sManager) GetHTTPClient() *http.Client { - ret := _m.Called() - - var r0 *http.Client - if rf, ok := ret.Get(0).(func() *http.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*http.Client) - } - } - - return r0 -} - -// mockK8sManager_GetHTTPClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetHTTPClient' -type mockK8sManager_GetHTTPClient_Call struct { - *mock.Call -} - -// GetHTTPClient is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetHTTPClient() *mockK8sManager_GetHTTPClient_Call { - return &mockK8sManager_GetHTTPClient_Call{Call: _e.mock.On("GetHTTPClient")} -} - -func (_c *mockK8sManager_GetHTTPClient_Call) Run(run func()) *mockK8sManager_GetHTTPClient_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetHTTPClient_Call) Return(_a0 *http.Client) *mockK8sManager_GetHTTPClient_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetHTTPClient_Call) RunAndReturn(run func() *http.Client) *mockK8sManager_GetHTTPClient_Call { - _c.Call.Return(run) - return _c -} - -// GetLogger provides a mock function with given fields: -func (_m *mockK8sManager) GetLogger() logr.Logger { - ret := _m.Called() - - var r0 logr.Logger - if rf, ok := ret.Get(0).(func() logr.Logger); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(logr.Logger) - } - - return r0 -} - -// mockK8sManager_GetLogger_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLogger' -type mockK8sManager_GetLogger_Call struct { - *mock.Call -} - -// GetLogger is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetLogger() *mockK8sManager_GetLogger_Call { - return &mockK8sManager_GetLogger_Call{Call: _e.mock.On("GetLogger")} -} - -func (_c *mockK8sManager_GetLogger_Call) Run(run func()) *mockK8sManager_GetLogger_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetLogger_Call) Return(_a0 logr.Logger) *mockK8sManager_GetLogger_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetLogger_Call) RunAndReturn(run func() logr.Logger) *mockK8sManager_GetLogger_Call { - _c.Call.Return(run) - return _c -} - -// GetRESTMapper provides a mock function with given fields: -func (_m *mockK8sManager) GetRESTMapper() meta.RESTMapper { - ret := _m.Called() - - var r0 meta.RESTMapper - if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(meta.RESTMapper) - } - } - - return r0 -} - -// mockK8sManager_GetRESTMapper_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRESTMapper' -type mockK8sManager_GetRESTMapper_Call struct { - *mock.Call -} - -// GetRESTMapper is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetRESTMapper() *mockK8sManager_GetRESTMapper_Call { - return &mockK8sManager_GetRESTMapper_Call{Call: _e.mock.On("GetRESTMapper")} -} - -func (_c *mockK8sManager_GetRESTMapper_Call) Run(run func()) *mockK8sManager_GetRESTMapper_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetRESTMapper_Call) Return(_a0 meta.RESTMapper) *mockK8sManager_GetRESTMapper_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetRESTMapper_Call) RunAndReturn(run func() meta.RESTMapper) *mockK8sManager_GetRESTMapper_Call { - _c.Call.Return(run) - return _c -} - -// GetScheme provides a mock function with given fields: -func (_m *mockK8sManager) GetScheme() *runtime.Scheme { - ret := _m.Called() - - var r0 *runtime.Scheme - if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*runtime.Scheme) - } - } - - return r0 -} - -// mockK8sManager_GetScheme_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetScheme' -type mockK8sManager_GetScheme_Call struct { - *mock.Call -} - -// GetScheme is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetScheme() *mockK8sManager_GetScheme_Call { - return &mockK8sManager_GetScheme_Call{Call: _e.mock.On("GetScheme")} -} - -func (_c *mockK8sManager_GetScheme_Call) Run(run func()) *mockK8sManager_GetScheme_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetScheme_Call) Return(_a0 *runtime.Scheme) *mockK8sManager_GetScheme_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetScheme_Call) RunAndReturn(run func() *runtime.Scheme) *mockK8sManager_GetScheme_Call { - _c.Call.Return(run) - return _c -} - -// GetWebhookServer provides a mock function with given fields: -func (_m *mockK8sManager) GetWebhookServer() webhook.Server { - ret := _m.Called() - - var r0 webhook.Server - if rf, ok := ret.Get(0).(func() webhook.Server); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(webhook.Server) - } - } - - return r0 -} - -// mockK8sManager_GetWebhookServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWebhookServer' -type mockK8sManager_GetWebhookServer_Call struct { - *mock.Call -} - -// GetWebhookServer is a helper method to define mock.On call -func (_e *mockK8sManager_Expecter) GetWebhookServer() *mockK8sManager_GetWebhookServer_Call { - return &mockK8sManager_GetWebhookServer_Call{Call: _e.mock.On("GetWebhookServer")} -} - -func (_c *mockK8sManager_GetWebhookServer_Call) Run(run func()) *mockK8sManager_GetWebhookServer_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *mockK8sManager_GetWebhookServer_Call) Return(_a0 webhook.Server) *mockK8sManager_GetWebhookServer_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_GetWebhookServer_Call) RunAndReturn(run func() webhook.Server) *mockK8sManager_GetWebhookServer_Call { - _c.Call.Return(run) - return _c -} - -// Start provides a mock function with given fields: ctx -func (_m *mockK8sManager) Start(ctx context.Context) error { - ret := _m.Called(ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockK8sManager_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' -type mockK8sManager_Start_Call struct { - *mock.Call -} - -// Start is a helper method to define mock.On call -// - ctx context.Context -func (_e *mockK8sManager_Expecter) Start(ctx interface{}) *mockK8sManager_Start_Call { - return &mockK8sManager_Start_Call{Call: _e.mock.On("Start", ctx)} -} - -func (_c *mockK8sManager_Start_Call) Run(run func(ctx context.Context)) *mockK8sManager_Start_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *mockK8sManager_Start_Call) Return(_a0 error) *mockK8sManager_Start_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockK8sManager_Start_Call) RunAndReturn(run func(context.Context) error) *mockK8sManager_Start_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTnewMockK8sManager interface { - mock.TestingT - Cleanup(func()) -} - -// newMockK8sManager creates a new instance of mockK8sManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func newMockK8sManager(t mockConstructorTestingTnewMockK8sManager) *mockK8sManager { - mock := &mockK8sManager{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -}