diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..0e0eed2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Kubebuilder DevContainer", + "image": "docker.io/golang:1.23", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/git:1": {} + }, + + "runArgs": ["--network=host"], + + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "ms-kubernetes-tools.vscode-kubernetes-tools", + "ms-azuretools.vscode-docker" + ] + } + }, + + "onCreateCommand": "bash .devcontainer/post-install.sh" +} + diff --git a/.devcontainer/post-install.sh b/.devcontainer/post-install.sh new file mode 100644 index 0000000..265c43e --- /dev/null +++ b/.devcontainer/post-install.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -x + +curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 +chmod +x ./kind +mv ./kind /usr/local/bin/kind + +curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/amd64 +chmod +x kubebuilder +mv kubebuilder /usr/local/bin/ + +KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt) +curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl" +chmod +x kubectl +mv kubectl /usr/local/bin/kubectl + +docker network create -d=bridge --subnet=172.19.0.0/24 kind + +kind version +kubebuilder version +docker --version +go version +kubectl version --client diff --git a/.dockerignore b/.dockerignore index 0f04682..a3aab7a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,3 @@ # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file # Ignore build and test binaries. bin/ -testbin/ diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..ceab75a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Run linter + uses: golangci/golangci-lint-action@v6 + with: + version: v1.63.4 diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml new file mode 100644 index 0000000..7b3855b --- /dev/null +++ b/.github/workflows/test-e2e.yml @@ -0,0 +1,37 @@ +name: E2E Tests + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + test-e2e: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install the latest version of kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + - name: Verify kind installation + run: kind version + + - name: Create kind cluster + run: kind create cluster + + - name: Running Test e2e + run: | + go mod tidy + make test-e2e diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 5a2018d..4d73c19 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -7,16 +7,18 @@ on: branches: [ "main" ] jobs: - - build: + test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Clone the code + uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.23 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod - - name: Run test suite - run: make test + - name: Running Tests + run: | + go mod tidy + make test diff --git a/.gitignore b/.gitignore index 37e4f1d..ada68ff 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,8 @@ *.dll *.so *.dylib - -bin/ +bin/* +Dockerfile.cross # Test binary, built with `go test -c` *.test @@ -13,8 +13,15 @@ bin/ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ +# Go workspace file +go.work -.vscode/ +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..6b29746 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,47 @@ +run: + timeout: 5m + allow-parallel-runners: true + +issues: + # don't skip warning about doc comments + # don't exclude the default set of lint + exclude-use-default: false + # restore some of the defaults + # (fill in the rest as needed) + exclude-rules: + - path: "api/*" + linters: + - lll + - path: "internal/*" + linters: + - dupl + - lll +linters: + disable-all: true + enable: + - dupl + - errcheck + - copyloopvar + - ginkgolinter + - goconst + - gocyclo + - gofmt + - goimports + - gosimple + - govet + - ineffassign + - lll + - misspell + - nakedret + - prealloc + - revive + - staticcheck + - typecheck + - unconvert + - unparam + - unused + +linters-settings: + revive: + rules: + - name: comment-spacings diff --git a/Dockerfile b/Dockerfile index fc736d2..e4b6528 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ # Build the manager binary -FROM golang:1.23 as builder +FROM docker.io/golang:1.23 AS builder +ARG TARGETOS +ARG TARGETARCH WORKDIR /workspace # Copy the Go Modules manifests @@ -10,14 +12,17 @@ COPY go.sum go.sum RUN go mod download # Copy the go source -COPY main.go main.go -COPY apis/ apis/ -COPY controllers/ controllers/ +COPY cmd/main.go cmd/main.go +COPY api/ api/ COPY helpers/ helpers/ COPY internal/ internal/ # Build -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go +# the GOARCH has not a default value to allow the binary be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details diff --git a/Makefile b/Makefile index f8d3333..458c529 100644 --- a/Makefile +++ b/Makefile @@ -46,10 +46,11 @@ ifeq ($(USE_IMAGE_DIGESTS), true) BUNDLE_GEN_FLAGS += --use-image-digests endif +# Set the Operator SDK version to use. By default, what is installed on the system is used. +# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. +OPERATOR_SDK_VERSION ?= v1.40.0 # Image URL to use all building/pushing image targets IMG ?= $(IMAGE_TAG_BASE):v$(VERSION) -# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.31.0 # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -58,6 +59,12 @@ else GOBIN=$(shell go env GOBIN) endif +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker + # 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. SHELL = /usr/bin/env bash -o pipefail @@ -70,7 +77,7 @@ all: build # The help target prints out all targets with their descriptions organized # beneath their categories. The categories are represented by '##@' and the -# target descriptions by '##'. The awk commands is responsible for reading the +# target descriptions by '##'. The awk command is responsible for reading the # entire set of makefiles included in this invocation, looking for lines of the # file as xyz: ## something, and then pretty-format the target and help. Then, # if there's a line with ##@ something, that gets pretty-printed as a category. @@ -102,47 +109,73 @@ vet: ## Run go vet against code. go vet ./... .PHONY: test -test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +test: manifests generate fmt vet setup-envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out + +# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'. +# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. +# CertManager is installed by default; skip with: +# - CERT_MANAGER_INSTALL_SKIP=true +.PHONY: test-e2e +test-e2e: manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. + go test ./test/e2e/ -v -ginkgo.v + +.PHONY: lint +lint: golangci-lint ## Run golangci-lint linter + $(GOLANGCI_LINT) run + +.PHONY: lint-fix +lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes + $(GOLANGCI_LINT) run --fix + +.PHONY: lint-config +lint-config: golangci-lint ## Verify golangci-lint linter configuration + $(GOLANGCI_LINT) config verify ##@ Build .PHONY: build -build: generate fmt vet ## Build manager binary. - go build -o bin/manager main.go +build: manifests generate fmt vet ## Build manager binary. + go build -o bin/manager cmd/main.go .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go + go run ./cmd/main.go -# If you wish built the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. +# If you wish to build the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ .PHONY: docker-build -docker-build: test ## Build docker image with the manager. - docker build -t ${IMG} . +docker-build: ## Build docker image with the manager. + $(CONTAINER_TOOL) build -t ${IMG} . .PHONY: docker-push docker-push: ## Push docker image with the manager. - docker push ${IMG} + $(CONTAINER_TOOL) push ${IMG} -# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple +# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ -# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> than the export will fail) -# To properly provided solutions that supports more than one platform you should use this option. +# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/ +# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=> then the export will fail) +# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option. PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le .PHONY: docker-buildx -docker-buildx: test ## Build and push docker image for the manager for cross-platform support +docker-buildx: ## Build and push docker image for the manager for cross-platform support # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - docker buildx create --name project-v3-builder - docker buildx use project-v3-builder - - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross - - docker buildx rm project-v3-builder + - $(CONTAINER_TOOL) buildx create --name synapse-operator-builder + $(CONTAINER_TOOL) buildx use synapse-operator-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm synapse-operator-builder rm Dockerfile.cross +.PHONY: build-installer +build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. + mkdir -p dist + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default > dist/install.yaml + ##@ Deployment ifndef ignore-not-found @@ -151,27 +184,27 @@ endif .PHONY: install install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | kubectl apply -f - + $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - .PHONY: uninstall uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - .PHONY: deploy deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | kubectl apply -f - + $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - .PHONY: undeploy -undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - +undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - .PHONY: manifest-package manifest-package: manifests kustomize ## Generate full manifest file for easy controller deployment cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} $(KUSTOMIZE) build config/default | tee install/synapse-operator.yaml -##@ Build Dependencies +##@ Dependencies ## Location to install dependencies to LOCALBIN ?= $(shell pwd)/bin @@ -179,47 +212,100 @@ $(LOCALBIN): mkdir -p $(LOCALBIN) ## Tool Binaries +KUBECTL ?= kubectl +KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint ## Tool Versions -KUSTOMIZE_VERSION ?= v5.4.3 -CONTROLLER_TOOLS_VERSION ?= v0.16.1 +KUSTOMIZE_VERSION ?= v5.6.0 +CONTROLLER_TOOLS_VERSION ?= v0.17.2 +#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20) +ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}') +#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) +ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}') +GOLANGCI_LINT_VERSION ?= v1.63.4 -KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. $(KUSTOMIZE): $(LOCALBIN) - test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) .PHONY: controller-gen controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. $(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) + +.PHONY: setup-envtest +setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory. + @echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..." + @$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \ + echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \ + exit 1; \ + } .PHONY: envtest -envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. $(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) + +.PHONY: golangci-lint +golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. +$(GOLANGCI_LINT): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f "$(1)-$(3)" ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +rm -f $(1) || true ;\ +GOBIN=$(LOCALBIN) go install $${package} ;\ +mv $(1) $(1)-$(3) ;\ +} ;\ +ln -sf $(1)-$(3) $(1) +endef + +.PHONY: operator-sdk +OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk +operator-sdk: ## Download operator-sdk locally if necessary. +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (, $(shell which operator-sdk 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPERATOR_SDK)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which operator-sdk) +endif +endif .PHONY: bundle -bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files. - operator-sdk generate kustomize manifests -q +bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) - operator-sdk bundle validate ./bundle + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) + $(OPERATOR_SDK) bundle validate ./bundle .PHONY: bundle-build bundle-build: ## Build the bundle image. - docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + $(CONTAINER_TOOL) build -f bundle.Dockerfile -t $(BUNDLE_IMG) . .PHONY: bundle-push bundle-push: ## Push the bundle image. $(MAKE) docker-push IMG=$(BUNDLE_IMG) .PHONY: opm -OPM = ./bin/opm +OPM = $(LOCALBIN)/opm opm: ## Download opm locally if necessary. ifeq (,$(wildcard $(OPM))) ifeq (,$(shell which opm 2>/dev/null)) @@ -227,7 +313,7 @@ ifeq (,$(shell which opm 2>/dev/null)) set -e ;\ mkdir -p $(dir $(OPM)) ;\ OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ - curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.55.0/$${OS}-$${ARCH}-opm ;\ chmod +x $(OPM) ;\ } else @@ -252,7 +338,7 @@ endif # https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator .PHONY: catalog-build catalog-build: opm ## Build a catalog image. - $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + $(OPM) index add --container-tool $(CONTAINER_TOOL) --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) # Push the catalog image. .PHONY: catalog-push diff --git a/PROJECT b/PROJECT index 50b2f08..1b9b2af 100644 --- a/PROJECT +++ b/PROJECT @@ -1,6 +1,10 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: opdev.io layout: -- go.kubebuilder.io/v3 +- go.kubebuilder.io/v4 multigroup: true plugins: manifests.sdk.operatorframework.io/v2: {} @@ -15,7 +19,7 @@ resources: domain: opdev.io group: synapse kind: Synapse - path: github.com/opdev/synapse-operator/apis/synapse/v1alpha1 + path: github.com/opdev/synapse-operator/api/synapse/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -24,7 +28,7 @@ resources: domain: opdev.io group: synapse kind: MautrixSignal - path: github.com/opdev/synapse-operator/apis/synapse/v1alpha1 + path: github.com/opdev/synapse-operator/api/synapse/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -33,6 +37,6 @@ resources: domain: opdev.io group: synapse kind: Heisenbridge - path: github.com/opdev/synapse-operator/apis/synapse/v1alpha1 + path: github.com/opdev/synapse-operator/api/synapse/v1alpha1 version: v1alpha1 version: "3" diff --git a/apis/synapse/v1alpha1/groupversion_info.go b/api/synapse/v1alpha1/groupversion_info.go similarity index 95% rename from apis/synapse/v1alpha1/groupversion_info.go rename to api/synapse/v1alpha1/groupversion_info.go index 21968b9..67fd459 100644 --- a/apis/synapse/v1alpha1/groupversion_info.go +++ b/api/synapse/v1alpha1/groupversion_info.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package v1alpha1 contains API Schema definitions for the synapse v1alpha1 API group +// Package v1alpha1 contains API Schema definitions for the synapse v1alpha1 API group. // +kubebuilder:object:generate=true // +groupName=synapse.opdev.io package v1alpha1 @@ -25,10 +25,10 @@ import ( ) var ( - // GroupVersion is group version used to register these objects + // GroupVersion is group version used to register these objects. GroupVersion = schema.GroupVersion{Group: "synapse.opdev.io", Version: "v1alpha1"} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} // AddToScheme adds the types in this group-version to the given scheme. diff --git a/apis/synapse/v1alpha1/heisenbridge_types.go b/api/synapse/v1alpha1/heisenbridge_types.go similarity index 93% rename from apis/synapse/v1alpha1/heisenbridge_types.go rename to api/synapse/v1alpha1/heisenbridge_types.go index 55fc976..2656700 100644 --- a/apis/synapse/v1alpha1/heisenbridge_types.go +++ b/api/synapse/v1alpha1/heisenbridge_types.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -69,7 +69,7 @@ type HeisenbridgeConfigMap struct { Namespace string `json:"namespace,omitempty"` } -// HeisenbridgeStatus defines the observed state of Heisenbridge +// HeisenbridgeStatus defines the observed state of Heisenbridge. type HeisenbridgeStatus struct { // State of the Heisenbridge instance State string `json:"state,omitempty"` @@ -78,10 +78,10 @@ type HeisenbridgeStatus struct { Reason string `json:"reason,omitempty"` } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status -// Heisenbridge is the Schema for the heisenbridges API +// Heisenbridge is the Schema for the heisenbridges API. type Heisenbridge struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -91,9 +91,9 @@ type Heisenbridge struct { Status HeisenbridgeStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true -// HeisenbridgeList contains a list of Heisenbridge +// HeisenbridgeList contains a list of Heisenbridge. type HeisenbridgeList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/apis/synapse/v1alpha1/mautrixsignal_types.go b/api/synapse/v1alpha1/mautrixsignal_types.go similarity index 93% rename from apis/synapse/v1alpha1/mautrixsignal_types.go rename to api/synapse/v1alpha1/mautrixsignal_types.go index 30e0048..951fcfb 100644 --- a/apis/synapse/v1alpha1/mautrixsignal_types.go +++ b/api/synapse/v1alpha1/mautrixsignal_types.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -60,7 +60,7 @@ type MautrixSignalConfigMap struct { Namespace string `json:"namespace,omitempty"` } -// MautrixSignalStatus defines the observed state of MautrixSignal +// MautrixSignalStatus defines the observed state of MautrixSignal. type MautrixSignalStatus struct { // State of the MautrixSignal instance State string `json:"state,omitempty"` @@ -81,10 +81,10 @@ type MautrixSignalStatusSynapse struct { ServerName string `json:"serverName,omitempty"` } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status -// MautrixSignal is the Schema for the mautrixsignals API +// MautrixSignal is the Schema for the mautrixsignals API. type MautrixSignal struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -94,9 +94,9 @@ type MautrixSignal struct { Status MautrixSignalStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true -// MautrixSignalList contains a list of MautrixSignal +// MautrixSignalList contains a list of MautrixSignal. type MautrixSignalList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/apis/synapse/v1alpha1/synapse_types.go b/api/synapse/v1alpha1/synapse_types.go similarity index 94% rename from apis/synapse/v1alpha1/synapse_types.go rename to api/synapse/v1alpha1/synapse_types.go index 9e4b34e..9241b92 100644 --- a/apis/synapse/v1alpha1/synapse_types.go +++ b/api/synapse/v1alpha1/synapse_types.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// SynapseSpec defines the desired state of Synapse +// SynapseSpec defines the desired state of Synapse. type SynapseSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file @@ -82,7 +82,7 @@ type SynapseHomeserverValues struct { ReportStats bool `json:"reportStats"` } -// SynapseStatus defines the observed state of Synapse +// SynapseStatus defines the observed state of Synapse. type SynapseStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file @@ -157,10 +157,10 @@ type SynapseStatusHomeserverConfiguration struct { ReportStats bool `json:"reportStats,omitempty"` } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status -// Synapse is the Schema for the synapses API +// Synapse is the Schema for the synapses API. type Synapse struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -170,9 +170,9 @@ type Synapse struct { Status SynapseStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true -// SynapseList contains a list of Synapse +// SynapseList contains a list of Synapse. type SynapseList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/apis/synapse/v1alpha1/zz_generated.deepcopy.go b/api/synapse/v1alpha1/zz_generated.deepcopy.go similarity index 99% rename from apis/synapse/v1alpha1/zz_generated.deepcopy.go rename to api/synapse/v1alpha1/zz_generated.deepcopy.go index b4defae..bfcfc76 100644 --- a/apis/synapse/v1alpha1/zz_generated.deepcopy.go +++ b/api/synapse/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 967926e..d3e6a7d 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -6,9 +6,9 @@ LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=synapse-operator LABEL operators.operatorframework.io.bundle.channels.v1=alpha -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.40.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 -LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 +LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 # Labels for testing. LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 diff --git a/bundle/manifests/synapse-operator-controller-manager-metrics-service_v1_service.yaml b/bundle/manifests/synapse-operator-controller-manager-metrics-service_v1_service.yaml index e3a2abf..687fc34 100644 --- a/bundle/manifests/synapse-operator-controller-manager-metrics-service_v1_service.yaml +++ b/bundle/manifests/synapse-operator-controller-manager-metrics-service_v1_service.yaml @@ -3,6 +3,8 @@ kind: Service metadata: creationTimestamp: null labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator control-plane: controller-manager name: synapse-operator-controller-manager-metrics-service spec: @@ -10,8 +12,9 @@ spec: - name: https port: 8443 protocol: TCP - targetPort: https + targetPort: 8443 selector: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager status: loadBalancer: {} diff --git a/bundle/manifests/synapse-operator-manager-config_v1_configmap.yaml b/bundle/manifests/synapse-operator-manager-config_v1_configmap.yaml deleted file mode 100644 index 2a723cb..0000000 --- a/bundle/manifests/synapse-operator-manager-config_v1_configmap.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -data: - controller_manager_config.yaml: | - apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 - kind: ControllerManagerConfig - health: - healthProbeBindAddress: :8081 - metrics: - bindAddress: 127.0.0.1:8080 - webhook: - port: 9443 - leaderElection: - leaderElect: true - resourceName: 8d311e9b.opdev.io -kind: ConfigMap -metadata: - name: synapse-operator-manager-config diff --git a/bundle/manifests/synapse-operator-synapse-heisenbridge-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-heisenbridge-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..0e1513c --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-heisenbridge-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-heisenbridge-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-heisenbridge-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..a29d6a1 --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-heisenbridge-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,27 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-heisenbridge-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-heisenbridge-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..414e92c --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-heisenbridge-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-mautrixsignal-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-mautrixsignal-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..906a281 --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-mautrixsignal-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-mautrixsignal-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-mautrixsignal-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..18e4373 --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-mautrixsignal-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,27 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-mautrixsignal-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-mautrixsignal-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..8eab005 --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-mautrixsignal-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get diff --git a/bundle/manifests/synapse-operator-synapse-synapse-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/synapse-operator-synapse-synapse-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml new file mode 100644 index 0000000..a9d5e74 --- /dev/null +++ b/bundle/manifests/synapse-operator-synapse-synapse-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get diff --git a/config/rbac/synapse_editor_role.yaml b/bundle/manifests/synapse-operator-synapse-synapse-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml similarity index 62% rename from config/rbac/synapse_editor_role.yaml rename to bundle/manifests/synapse-operator-synapse-synapse-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml index dc72581..91687a4 100644 --- a/config/rbac/synapse_editor_role.yaml +++ b/bundle/manifests/synapse-operator-synapse-synapse-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -1,8 +1,11 @@ -# permissions for end users to edit synapses. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: synapse-editor-role + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-editor-role rules: - apiGroups: - synapse.opdev.io diff --git a/config/rbac/synapse_viewer_role.yaml b/bundle/manifests/synapse-operator-synapse-synapse-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml similarity index 58% rename from config/rbac/synapse_viewer_role.yaml rename to bundle/manifests/synapse-operator-synapse-synapse-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml index b84cd70..e195e39 100644 --- a/config/rbac/synapse_viewer_role.yaml +++ b/bundle/manifests/synapse-operator-synapse-synapse-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -1,8 +1,11 @@ -# permissions for end users to view synapses. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: synapse-viewer-role + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-viewer-role rules: - apiGroups: - synapse.opdev.io diff --git a/bundle/manifests/synapse-operator.clusterserviceversion.yaml b/bundle/manifests/synapse-operator.clusterserviceversion.yaml index 0a70b28..ced25c1 100644 --- a/bundle/manifests/synapse-operator.clusterserviceversion.yaml +++ b/bundle/manifests/synapse-operator.clusterserviceversion.yaml @@ -9,11 +9,8 @@ metadata: "kind": "Heisenbridge", "metadata": { "labels": { - "app.kubernetes.io/created-by": "synapse-operator", - "app.kubernetes.io/instance": "heisenbridge-sample", "app.kubernetes.io/managed-by": "kustomize", - "app.kubernetes.io/name": "heisenbridge", - "app.kubernetes.io/part-of": "synapse-operator" + "app.kubernetes.io/name": "synapse-operator" }, "name": "heisenbridge-sample" }, @@ -28,11 +25,8 @@ metadata: "kind": "MautrixSignal", "metadata": { "labels": { - "app.kubernetes.io/created-by": "synapse-operator", - "app.kubernetes.io/instance": "mautrixsignal-sample", "app.kubernetes.io/managed-by": "kustomize", - "app.kubernetes.io/name": "mautrixsignal", - "app.kubernetes.io/part-of": "synapse-operator" + "app.kubernetes.io/name": "synapse-operator" }, "name": "mautrixsignal-sample" }, @@ -46,6 +40,10 @@ metadata: "apiVersion": "synapse.opdev.io/v1alpha1", "kind": "Synapse", "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "kustomize", + "app.kubernetes.io/name": "synapse-operator" + }, "name": "synapse-sample" }, "spec": { @@ -62,12 +60,12 @@ metadata: capabilities: Basic Install categories: Developer Tools containerImage: quay.io/opdev/synapse-operator - createdAt: "2025-05-16T15:21:27Z" + createdAt: "2025-07-07T13:42:07Z" description: Deploys and manages the lifecycle of Synapse servers and their associated components (bridges, databases, ...). Synapse is the reference Matrix homeserver implementation. - operators.operatorframework.io/builder: operator-sdk-v1.29.0 - operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 + operators.operatorframework.io/builder: operator-sdk-v1.40.0 + operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 repository: https://github.com/opdev/synapse-operator name: synapse-operator.v0.6.1 namespace: placeholder @@ -75,17 +73,17 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: Heisenbridge is the Schema for the heisenbridges API + - description: Heisenbridge is the Schema for the heisenbridges API. displayName: Heisenbridge kind: Heisenbridge name: heisenbridges.synapse.opdev.io version: v1alpha1 - - description: MautrixSignal is the Schema for the mautrixsignals API + - description: MautrixSignal is the Schema for the mautrixsignals API. displayName: Mautrix Signal kind: MautrixSignal name: mautrixsignals.synapse.opdev.io version: v1alpha1 - - description: Synapse is the Schema for the synapses API + - description: Synapse is the Schema for the synapses API. displayName: Synapse kind: Synapse name: synapses.synapse.opdev.io @@ -102,9 +100,12 @@ spec: clusterPermissions: - rules: - apiGroups: - - apps + - "" resources: - - deployments + - configmaps + - persistentvolumeclaims + - serviceaccounts + - services verbs: - create - delete @@ -114,12 +115,9 @@ spec: - update - watch - apiGroups: - - "" + - apps resources: - - configmaps - - persistentvolumeclaims - - serviceaccounts - - services + - deployments verbs: - create - delete @@ -152,6 +150,14 @@ spec: - patch - update - watch + - apiGroups: + - security.openshift.io + resourceNames: + - anyuid + resources: + - securitycontextconstraints + verbs: + - use - apiGroups: - synapse.opdev.io resources: @@ -199,36 +205,30 @@ spec: serviceAccountName: synapse-operator-controller-manager deployments: - label: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator control-plane: controller-manager name: synapse-operator-controller-manager spec: replicas: 1 selector: matchLabels: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager strategy: {} template: metadata: + annotations: + kubectl.kubernetes.io/default-container: manager labels: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager spec: containers: - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=10 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - protocol: TCP - resources: {} - - args: - - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 + - --metrics-bind-address=:8443 - --leader-elect + - --health-probe-bind-address=:8081 command: - /manager image: quay.io/opdev/synapse-operator:v0.6.1 @@ -247,15 +247,20 @@ spec: periodSeconds: 10 resources: limits: - cpu: 200m - memory: 100Mi + cpu: 500m + memory: 128Mi requests: - cpu: 100m - memory: 20Mi + cpu: 10m + memory: 64Mi securityContext: allowPrivilegeEscalation: false + capabilities: + drop: + - ALL securityContext: runAsNonRoot: true + seccompProfile: + type: RuntimeDefault serviceAccountName: synapse-operator-controller-manager terminationGracePeriodSeconds: 10 permissions: diff --git a/bundle/manifests/synapse.opdev.io_heisenbridges.yaml b/bundle/manifests/synapse.opdev.io_heisenbridges.yaml index 20ed8b8..e933047 100644 --- a/bundle/manifests/synapse.opdev.io_heisenbridges.yaml +++ b/bundle/manifests/synapse.opdev.io_heisenbridges.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 creationTimestamp: null name: heisenbridges.synapse.opdev.io spec: @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Heisenbridge is the Schema for the heisenbridges API + description: Heisenbridge is the Schema for the heisenbridges API. properties: apiVersion: description: |- @@ -87,7 +87,7 @@ spec: - synapse type: object status: - description: HeisenbridgeStatus defines the observed state of Heisenbridge + description: HeisenbridgeStatus defines the observed state of Heisenbridge. properties: reason: description: Reason for the current Heisenbridge State diff --git a/bundle/manifests/synapse.opdev.io_mautrixsignals.yaml b/bundle/manifests/synapse.opdev.io_mautrixsignals.yaml index b7ad54b..f0e342b 100644 --- a/bundle/manifests/synapse.opdev.io_mautrixsignals.yaml +++ b/bundle/manifests/synapse.opdev.io_mautrixsignals.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 creationTimestamp: null name: mautrixsignals.synapse.opdev.io spec: @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: MautrixSignal is the Schema for the mautrixsignals API + description: MautrixSignal is the Schema for the mautrixsignals API. properties: apiVersion: description: |- @@ -78,7 +78,7 @@ spec: - synapse type: object status: - description: MautrixSignalStatus defines the observed state of MautrixSignal + description: MautrixSignalStatus defines the observed state of MautrixSignal. properties: isOpenshift: default: false diff --git a/bundle/manifests/synapse.opdev.io_synapses.yaml b/bundle/manifests/synapse.opdev.io_synapses.yaml index 76f04e1..2b00b0a 100644 --- a/bundle/manifests/synapse.opdev.io_synapses.yaml +++ b/bundle/manifests/synapse.opdev.io_synapses.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 creationTimestamp: null name: synapses.synapse.opdev.io spec: @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Synapse is the Schema for the synapses API + description: Synapse is the Schema for the synapses API. properties: apiVersion: description: |- @@ -37,7 +37,7 @@ spec: metadata: type: object spec: - description: SynapseSpec defines the desired state of Synapse + description: SynapseSpec defines the desired state of Synapse. properties: createNewPostgreSQL: default: false @@ -99,7 +99,7 @@ spec: - homeserver type: object status: - description: SynapseStatus defines the observed state of Synapse + description: SynapseStatus defines the observed state of Synapse. properties: bridges: description: Information on the bridges deployed alongside Synapse diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index cac84db..ad84c73 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -5,9 +5,9 @@ annotations: operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: synapse-operator operators.operatorframework.io.bundle.channels.v1: alpha - operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.40.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 - operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 + operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4 # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 diff --git a/bundle/tests/scorecard/config.yaml b/bundle/tests/scorecard/config.yaml index 89bdfbe..f7368a4 100644 --- a/bundle/tests/scorecard/config.yaml +++ b/bundle/tests/scorecard/config.yaml @@ -8,7 +8,7 @@ stages: - entrypoint: - scorecard-test - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: basic test: basic-check-spec-test @@ -18,7 +18,7 @@ stages: - entrypoint: - scorecard-test - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-bundle-validation-test @@ -28,7 +28,7 @@ stages: - entrypoint: - scorecard-test - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-crds-have-validation-test @@ -38,7 +38,7 @@ stages: - entrypoint: - scorecard-test - olm-crds-have-resources - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-crds-have-resources-test @@ -48,7 +48,7 @@ stages: - entrypoint: - scorecard-test - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-spec-descriptors-test @@ -58,7 +58,7 @@ stages: - entrypoint: - scorecard-test - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-status-descriptors-test diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..a610bee --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,263 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + "path/filepath" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/certwatcher" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + pgov1beta1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" + + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" + heisenbridgecontroller "github.com/opdev/synapse-operator/internal/controller/synapse/heisenbridge" + mautrixsignalcontroller "github.com/opdev/synapse-operator/internal/controller/synapse/mautrixsignal" + synapsecontroller "github.com/opdev/synapse-operator/internal/controller/synapse/synapse" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(synapsev1alpha1.AddToScheme(scheme)) + utilruntime.Must(pgov1beta1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +// nolint:gocyclo +func main() { + var metricsAddr string + var metricsCertPath, metricsCertName, metricsCertKey string + var webhookCertPath, webhookCertName, webhookCertKey string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.") + flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.") + flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.") + flag.StringVar(&metricsCertPath, "metrics-cert-path", "", + "The directory that contains the metrics server certificate.") + flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") + flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + // Create watchers for metrics and webhooks certificates + var metricsCertWatcher, webhookCertWatcher *certwatcher.CertWatcher + + // Initial webhook TLS options + webhookTLSOpts := tlsOpts + + if len(webhookCertPath) > 0 { + setupLog.Info("Initializing webhook certificate watcher using provided certificates", + "webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey) + + var err error + webhookCertWatcher, err = certwatcher.New( + filepath.Join(webhookCertPath, webhookCertName), + filepath.Join(webhookCertPath, webhookCertKey), + ) + if err != nil { + setupLog.Error(err, "Failed to initialize webhook certificate watcher") + os.Exit(1) + } + + webhookTLSOpts = append(webhookTLSOpts, func(config *tls.Config) { + config.GetCertificate = webhookCertWatcher.GetCertificate + }) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: webhookTLSOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + } + + // If the certificate is not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + // + // TODO(user): If you enable certManager, uncomment the following lines: + // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates + // managed by cert-manager for the metrics server. + // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification. + if len(metricsCertPath) > 0 { + setupLog.Info("Initializing metrics certificate watcher using provided certificates", + "metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey) + + var err error + metricsCertWatcher, err = certwatcher.New( + filepath.Join(metricsCertPath, metricsCertName), + filepath.Join(metricsCertPath, metricsCertKey), + ) + if err != nil { + setupLog.Error(err, "to initialize metrics certificate watcher", "error", err) + os.Exit(1) + } + + metricsServerOptions.TLSOpts = append(metricsServerOptions.TLSOpts, func(config *tls.Config) { + config.GetCertificate = metricsCertWatcher.GetCertificate + }) + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "8d311e9b.opdev.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (&synapsecontroller.SynapseReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Synapse") + os.Exit(1) + } + if err = (&mautrixsignalcontroller.MautrixSignalReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "MautrixSignal") + os.Exit(1) + } + if err = (&heisenbridgecontroller.HeisenbridgeReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Heisenbridge") + os.Exit(1) + } + // +kubebuilder:scaffold:builder + + if metricsCertWatcher != nil { + setupLog.Info("Adding metrics certificate watcher to manager") + if err := mgr.Add(metricsCertWatcher); err != nil { + setupLog.Error(err, "unable to add metrics certificate watcher to manager") + os.Exit(1) + } + } + + if webhookCertWatcher != nil { + setupLog.Info("Adding webhook certificate watcher to manager") + if err := mgr.Add(webhookCertWatcher); err != nil { + setupLog.Error(err, "unable to add webhook certificate watcher to manager") + os.Exit(1) + } + } + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/config/crd/bases/synapse.opdev.io_heisenbridges.yaml b/config/crd/bases/synapse.opdev.io_heisenbridges.yaml index 9478ff5..e37ad9e 100644 --- a/config/crd/bases/synapse.opdev.io_heisenbridges.yaml +++ b/config/crd/bases/synapse.opdev.io_heisenbridges.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: heisenbridges.synapse.opdev.io spec: group: synapse.opdev.io @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Heisenbridge is the Schema for the heisenbridges API + description: Heisenbridge is the Schema for the heisenbridges API. properties: apiVersion: description: |- @@ -87,7 +87,7 @@ spec: - synapse type: object status: - description: HeisenbridgeStatus defines the observed state of Heisenbridge + description: HeisenbridgeStatus defines the observed state of Heisenbridge. properties: reason: description: Reason for the current Heisenbridge State diff --git a/config/crd/bases/synapse.opdev.io_mautrixsignals.yaml b/config/crd/bases/synapse.opdev.io_mautrixsignals.yaml index ba97964..71f96e0 100644 --- a/config/crd/bases/synapse.opdev.io_mautrixsignals.yaml +++ b/config/crd/bases/synapse.opdev.io_mautrixsignals.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: mautrixsignals.synapse.opdev.io spec: group: synapse.opdev.io @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: MautrixSignal is the Schema for the mautrixsignals API + description: MautrixSignal is the Schema for the mautrixsignals API. properties: apiVersion: description: |- @@ -78,7 +78,7 @@ spec: - synapse type: object status: - description: MautrixSignalStatus defines the observed state of MautrixSignal + description: MautrixSignalStatus defines the observed state of MautrixSignal. properties: isOpenshift: default: false diff --git a/config/crd/bases/synapse.opdev.io_synapses.yaml b/config/crd/bases/synapse.opdev.io_synapses.yaml index c4240a5..a1261a1 100644 --- a/config/crd/bases/synapse.opdev.io_synapses.yaml +++ b/config/crd/bases/synapse.opdev.io_synapses.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: synapses.synapse.opdev.io spec: group: synapse.opdev.io @@ -17,7 +17,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Synapse is the Schema for the synapses API + description: Synapse is the Schema for the synapses API. properties: apiVersion: description: |- @@ -37,7 +37,7 @@ spec: metadata: type: object spec: - description: SynapseSpec defines the desired state of Synapse + description: SynapseSpec defines the desired state of Synapse. properties: createNewPostgreSQL: default: false @@ -94,7 +94,7 @@ spec: - homeserver type: object status: - description: SynapseStatus defines the observed state of Synapse + description: SynapseStatus defines the observed state of Synapse. properties: bridges: description: Information on the bridges deployed alongside Synapse diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4438c1a..bb4ec5c 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,7 +5,7 @@ resources: - bases/synapse.opdev.io_synapses.yaml - bases/synapse.opdev.io_mautrixsignals.yaml - bases/synapse.opdev.io_heisenbridges.yaml -#+kubebuilder:scaffold:crdkustomizeresource +# +kubebuilder:scaffold:crdkustomizeresource patches: - path: patches/oneofhomeserver_in_synapses.yaml @@ -15,21 +15,11 @@ patches: kind: CustomResourceDefinition name: synapses.synapse.opdev.io -patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD -#- patches/webhook_in_synapses.yaml -#- patches/webhook_in_mautrixsignals.yaml -#- patches/webhook_in_heisenbridges.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_synapses.yaml -#- patches/cainjection_in_mautrixsignals.yaml -#- patches/cainjection_in_heisenbridges.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch +# +kubebuilder:scaffold:crdkustomizewebhookpatch +# [WEBHOOK] To enable webhook, uncomment the following section # the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: -- kustomizeconfig.yaml +#configurations: +#- kustomizeconfig.yaml diff --git a/config/crd/patches/cainjection_in_synapse_heisenbridges.yaml b/config/crd/patches/cainjection_in_synapse_heisenbridges.yaml deleted file mode 100644 index d048b0c..0000000 --- a/config/crd/patches/cainjection_in_synapse_heisenbridges.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: heisenbridges.synapse.opdev.io diff --git a/config/crd/patches/cainjection_in_synapse_mautrixsignals.yaml b/config/crd/patches/cainjection_in_synapse_mautrixsignals.yaml deleted file mode 100644 index 4bff4e0..0000000 --- a/config/crd/patches/cainjection_in_synapse_mautrixsignals.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: mautrixsignals.synapse.opdev.io diff --git a/config/crd/patches/cainjection_in_synapses.yaml b/config/crd/patches/cainjection_in_synapses.yaml deleted file mode 100644 index a24d9a9..0000000 --- a/config/crd/patches/cainjection_in_synapses.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: synapses.synapse.opdev.io diff --git a/config/crd/patches/webhook_in_synapse_heisenbridges.yaml b/config/crd/patches/webhook_in_synapse_heisenbridges.yaml deleted file mode 100644 index c889d34..0000000 --- a/config/crd/patches/webhook_in_synapse_heisenbridges.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: heisenbridges.synapse.opdev.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_synapse_mautrixsignals.yaml b/config/crd/patches/webhook_in_synapse_mautrixsignals.yaml deleted file mode 100644 index 4f3fadd..0000000 --- a/config/crd/patches/webhook_in_synapse_mautrixsignals.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: mautrixsignals.synapse.opdev.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_synapses.yaml b/config/crd/patches/webhook_in_synapses.yaml deleted file mode 100644 index 8989744..0000000 --- a/config/crd/patches/webhook_in_synapses.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: synapses.synapse.opdev.io -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/default/cert_metrics_manager_patch.yaml b/config/default/cert_metrics_manager_patch.yaml new file mode 100644 index 0000000..d975015 --- /dev/null +++ b/config/default/cert_metrics_manager_patch.yaml @@ -0,0 +1,30 @@ +# This patch adds the args, volumes, and ports to allow the manager to use the metrics-server certs. + +# Add the volumeMount for the metrics-server certs +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + mountPath: /tmp/k8s-metrics-server/metrics-certs + name: metrics-certs + readOnly: true + +# Add the --metrics-cert-path argument for the metrics server +- op: add + path: /spec/template/spec/containers/0/args/- + value: --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs + +# Add the metrics-server certs volume configuration +- op: add + path: /spec/template/spec/volumes/- + value: + name: metrics-certs + secret: + secretName: metrics-server-cert + optional: false + items: + - key: ca.crt + path: ca.crt + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index c63ecd3..dac0359 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -9,10 +9,12 @@ namespace: synapse-operator-system namePrefix: synapse-operator- # Labels to add to all resources and selectors. -#commonLabels: -# someName: someValue +#labels: +#- includeSelectors: true +# pairs: +# someName: someValue -bases: +resources: - ../crd - ../rbac - ../manager @@ -23,52 +25,210 @@ bases: #- ../certmanager # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. #- ../prometheus +# [METRICS] Expose the controller manager metrics service. +- metrics_service.yaml +# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy. +# Only Pod(s) running a namespace labeled with 'metrics: enabled' will be able to gather the metrics. +# Only CR(s) which requires webhooks and are applied on namespaces labeled with 'webhooks: enabled' will +# be able to communicate with the Webhook Server. +#- ../network-policy -patchesStrategicMerge: -# Protect the /metrics endpoint by putting it behind auth. -# If you want your controller-manager to expose the /metrics -# endpoint w/o any authn/z, please comment the following line. -- manager_auth_proxy_patch.yaml +# Uncomment the patches line if you enable Metrics +patches: +# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. +# More info: https://book.kubebuilder.io/reference/metrics +- path: manager_metrics_patch.yaml + target: + kind: Deployment -# Mount the controller config file for loading manager configurations -# through a ComponentConfig type -#- manager_config_patch.yaml +# Uncomment the patches line if you enable Metrics and CertManager +# [METRICS-WITH-CERTS] To enable metrics protected with certManager, uncomment the following line. +# This patch will protect the metrics with certManager self-signed certs. +#- path: cert_metrics_manager_patch.yaml +# target: +# kind: Deployment # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -#- manager_webhook_patch.yaml +#- path: manager_webhook_patch.yaml +# target: +# kind: Deployment -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. -# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. -# 'CERTMANAGER' needs to be enabled to use ca injection -#- webhookcainjection_patch.yaml - -# the following config is for teaching kustomize how to do var substitution -vars: # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -# fieldref: -# fieldpath: metadata.namespace -#- name: CERTIFICATE_NAME -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -#- name: SERVICE_NAMESPACE # namespace of the service -# objref: -# kind: Service -# version: v1 -# name: webhook-service -# fieldref: -# fieldpath: metadata.namespace -#- name: SERVICE_NAME -# objref: -# kind: Service -# version: v1 -# name: webhook-service +# Uncomment the following replacements to add the cert-manager CA injection annotations +#replacements: +# - source: # Uncomment the following block to enable certificates for metrics +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.name +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - select: # Uncomment the following to set the Service name for TLS config in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 0 +# create: true +# +# - source: +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.namespace +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true +# - select: # Uncomment the following to set the Service namespace for TLS in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have any webhook +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # Name of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - source: +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.namespace # Namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have a DefaultingWebhook (--defaulting ) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have a ConversionWebhook (--conversion) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionns +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionname diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml deleted file mode 100644 index 4e2232f..0000000 --- a/config/default/manager_auth_proxy_patch.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# This patch inject a sidecar container which is a HTTP proxy for the -# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: kube-rbac-proxy - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - protocol: TCP - name: https - - name: manager - args: - - "--health-probe-bind-address=:8081" - - "--metrics-bind-address=127.0.0.1:8080" - - "--leader-elect" diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml deleted file mode 100644 index 6c40015..0000000 --- a/config/default/manager_config_patch.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: manager - args: - - "--config=controller_manager_config.yaml" - volumeMounts: - - name: manager-config - mountPath: /controller_manager_config.yaml - subPath: controller_manager_config.yaml - volumes: - - name: manager-config - configMap: - name: manager-config diff --git a/config/default/manager_metrics_patch.yaml b/config/default/manager_metrics_patch.yaml new file mode 100644 index 0000000..2aaef65 --- /dev/null +++ b/config/default/manager_metrics_patch.yaml @@ -0,0 +1,4 @@ +# This patch adds the args to allow exposing the metrics endpoint using HTTPS +- op: add + path: /spec/template/spec/containers/0/args/0 + value: --metrics-bind-address=:8443 diff --git a/config/rbac/auth_proxy_service.yaml b/config/default/metrics_service.yaml similarity index 63% rename from config/rbac/auth_proxy_service.yaml rename to config/default/metrics_service.yaml index 71f1797..947c2ef 100644 --- a/config/rbac/auth_proxy_service.yaml +++ b/config/default/metrics_service.yaml @@ -3,6 +3,8 @@ kind: Service metadata: labels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: controller-manager-metrics-service namespace: system spec: @@ -10,6 +12,7 @@ spec: - name: https port: 8443 protocol: TCP - targetPort: https + targetPort: 8443 selector: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator diff --git a/config/manager/controller_manager_config.yaml b/config/manager/controller_manager_config.yaml deleted file mode 100644 index 19a8075..0000000 --- a/config/manager/controller_manager_config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 -kind: ControllerManagerConfig -health: - healthProbeBindAddress: :8081 -metrics: - bindAddress: 127.0.0.1:8080 -webhook: - port: 9443 -leaderElection: - leaderElect: true - resourceName: 8d311e9b.opdev.io diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 710cdd2..40ed78d 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,13 +1,5 @@ resources: - manager.yaml - -generatorOptions: - disableNameSuffixHash: true - -configMapGenerator: -- files: - - controller_manager_config.yaml - name: manager-config apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 2026244..bee787a 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -3,6 +3,8 @@ kind: Namespace metadata: labels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: system --- apiVersion: apps/v1 @@ -12,27 +14,63 @@ metadata: namespace: system labels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize spec: selector: matchLabels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator replicas: 1 template: metadata: + annotations: + kubectl.kubernetes.io/default-container: manager labels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator spec: + # TODO(user): Uncomment the following code to configure the nodeAffinity expression + # according to the platforms which are supported by your solution. + # It is considered best practice to support multiple architectures. You can + # build your manager image using the makefile target docker-buildx. + # affinity: + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/arch + # operator: In + # values: + # - amd64 + # - arm64 + # - ppc64le + # - s390x + # - key: kubernetes.io/os + # operator: In + # values: + # - linux securityContext: + # Projects are configured by default to adhere to the "restricted" Pod Security Standards. + # This ensures that deployments meet the highest security requirements for Kubernetes. + # For more details, see: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted runAsNonRoot: true + seccompProfile: + type: RuntimeDefault containers: - command: - /manager args: - - --leader-elect + - --leader-elect + - --health-probe-bind-address=:8081 image: controller:latest name: manager + ports: [] securityContext: allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" livenessProbe: httpGet: path: /healthz @@ -45,12 +83,16 @@ spec: port: 8081 initialDelaySeconds: 5 periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: limits: - cpu: 200m - memory: 100Mi + cpu: 500m + memory: 128Mi requests: - cpu: 100m - memory: 20Mi + cpu: 10m + memory: 64Mi + volumeMounts: [] + volumes: [] serviceAccountName: controller-manager terminationGracePeriodSeconds: 10 diff --git a/config/manifests/bases/synapse-operator.clusterserviceversion.yaml b/config/manifests/bases/synapse-operator.clusterserviceversion.yaml index 13d8e78..4bc8bd0 100644 --- a/config/manifests/bases/synapse-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/synapse-operator.clusterserviceversion.yaml @@ -16,17 +16,17 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: Heisenbridge is the Schema for the heisenbridges API + - description: Heisenbridge is the Schema for the heisenbridges API. displayName: Heisenbridge kind: Heisenbridge name: heisenbridges.synapse.opdev.io version: v1alpha1 - - description: MautrixSignal is the Schema for the mautrixsignals API + - description: MautrixSignal is the Schema for the mautrixsignals API. displayName: Mautrix Signal kind: MautrixSignal name: mautrixsignals.synapse.opdev.io version: v1alpha1 - - description: Synapse is the Schema for the synapses API + - description: Synapse is the Schema for the synapses API. displayName: Synapse kind: Synapse name: synapses.synapse.opdev.io diff --git a/config/manifests/kustomization.yaml b/config/manifests/kustomization.yaml index a33b56f..ec32e73 100644 --- a/config/manifests/kustomization.yaml +++ b/config/manifests/kustomization.yaml @@ -9,7 +9,7 @@ resources: # [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. # Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. # These patches remove the unnecessary "cert" volume and its manager container volumeMount. -#patchesJson6902: +#patches: #- target: # group: apps # version: v1 @@ -20,7 +20,8 @@ resources: # # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. # # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. # - op: remove -# path: /spec/template/spec/containers/1/volumeMounts/0 + +# path: /spec/template/spec/containers/0/volumeMounts/0 # # Remove the "cert" volume, since OLM will create and mount a set of certs. # # Update the indices in this path if adding or removing volumes in the manager's Deployment. # - op: remove diff --git a/config/network-policy/allow-metrics-traffic.yaml b/config/network-policy/allow-metrics-traffic.yaml new file mode 100644 index 0000000..648a6c8 --- /dev/null +++ b/config/network-policy/allow-metrics-traffic.yaml @@ -0,0 +1,27 @@ +# This NetworkPolicy allows ingress traffic +# with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those +# namespaces are able to gather data from the metrics endpoint. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: allow-metrics-traffic + namespace: system +spec: + podSelector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: synapse-operator + policyTypes: + - Ingress + ingress: + # This allows ingress traffic from any namespace with the label metrics: enabled + - from: + - namespaceSelector: + matchLabels: + metrics: enabled # Only from namespaces with this label + ports: + - port: 8443 + protocol: TCP diff --git a/config/network-policy/kustomization.yaml b/config/network-policy/kustomization.yaml new file mode 100644 index 0000000..ec0fb5e --- /dev/null +++ b/config/network-policy/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- allow-metrics-traffic.yaml diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml index ed13716..fdc5481 100644 --- a/config/prometheus/kustomization.yaml +++ b/config/prometheus/kustomization.yaml @@ -1,2 +1,11 @@ resources: - monitor.yaml + +# [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus +# to securely reference certificates created and managed by cert-manager. +# Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml +# to mount the "metrics-server-cert" secret in the Manager Deployment. +#patches: +# - path: monitor_tls_patch.yaml +# target: +# kind: ServiceMonitor diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml index d19136a..4fe7f8d 100644 --- a/config/prometheus/monitor.yaml +++ b/config/prometheus/monitor.yaml @@ -1,20 +1,27 @@ - # Prometheus Monitor Service (Metrics) apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: labels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: controller-manager-metrics-monitor namespace: system spec: endpoints: - path: /metrics - port: https + port: https # Ensure this is the name of the port that exposes HTTPS metrics scheme: https bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token tlsConfig: + # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables + # certificate verification, exposing the system to potential man-in-the-middle attacks. + # For production environments, it is recommended to use cert-manager for automatic TLS certificate management. + # To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml, + # which securely references the certificate from the 'metrics-server-cert' secret. insecureSkipVerify: true selector: matchLabels: control-plane: controller-manager + app.kubernetes.io/name: synapse-operator diff --git a/config/prometheus/monitor_tls_patch.yaml b/config/prometheus/monitor_tls_patch.yaml new file mode 100644 index 0000000..5bf84ce --- /dev/null +++ b/config/prometheus/monitor_tls_patch.yaml @@ -0,0 +1,19 @@ +# Patch for Prometheus ServiceMonitor to enable secure TLS configuration +# using certificates managed by cert-manager +- op: replace + path: /spec/endpoints/0/tlsConfig + value: + # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize + serverName: SERVICE_NAME.SERVICE_NAMESPACE.svc + insecureSkipVerify: false + ca: + secret: + name: metrics-server-cert + key: ca.crt + cert: + secret: + name: metrics-server-cert + key: tls.crt + keySecret: + name: metrics-server-cert + key: tls.key diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 731832a..3b6e644 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -9,10 +9,26 @@ resources: - role_binding.yaml - leader_election_role.yaml - leader_election_role_binding.yaml -# Comment the following 4 lines if you want to disable -# the auth proxy (https://github.com/brancz/kube-rbac-proxy) -# which protects your /metrics endpoint. -- auth_proxy_service.yaml -- auth_proxy_role.yaml -- auth_proxy_role_binding.yaml -- auth_proxy_client_clusterrole.yaml +# The following RBAC configurations are used to protect +# the metrics endpoint with authn/authz. These configurations +# ensure that only authorized users and service accounts +# can access the metrics endpoint. Comment the following +# permissions if you want to disable this protection. +# More info: https://book.kubebuilder.io/reference/metrics.html +- metrics_auth_role.yaml +- metrics_auth_role_binding.yaml +- metrics_reader_role.yaml +# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the {{ .ProjectName }} itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. +- synapse_heisenbridge_admin_role.yaml +- synapse_heisenbridge_editor_role.yaml +- synapse_heisenbridge_viewer_role.yaml +- synapse_mautrixsignal_admin_role.yaml +- synapse_mautrixsignal_editor_role.yaml +- synapse_mautrixsignal_viewer_role.yaml +- synapse_synapse_admin_role.yaml +- synapse_synapse_editor_role.yaml +- synapse_synapse_viewer_role.yaml + diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml index 4190ec8..7224f45 100644 --- a/config/rbac/leader_election_role.yaml +++ b/config/rbac/leader_election_role.yaml @@ -2,6 +2,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: leader-election-role rules: - apiGroups: diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml index 1d1321e..872f0aa 100644 --- a/config/rbac/leader_election_role_binding.yaml +++ b/config/rbac/leader_election_role_binding.yaml @@ -1,6 +1,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: leader-election-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/metrics_auth_role.yaml similarity index 90% rename from config/rbac/auth_proxy_role.yaml rename to config/rbac/metrics_auth_role.yaml index 80e1857..32d2e4e 100644 --- a/config/rbac/auth_proxy_role.yaml +++ b/config/rbac/metrics_auth_role.yaml @@ -1,7 +1,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: proxy-role + name: metrics-auth-role rules: - apiGroups: - authentication.k8s.io diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/metrics_auth_role_binding.yaml similarity index 79% rename from config/rbac/auth_proxy_role_binding.yaml rename to config/rbac/metrics_auth_role_binding.yaml index ec7acc0..e775d67 100644 --- a/config/rbac/auth_proxy_role_binding.yaml +++ b/config/rbac/metrics_auth_role_binding.yaml @@ -1,11 +1,11 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: proxy-rolebinding + name: metrics-auth-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: proxy-role + name: metrics-auth-role subjects: - kind: ServiceAccount name: controller-manager diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/metrics_reader_role.yaml similarity index 100% rename from config/rbac/auth_proxy_client_clusterrole.yaml rename to config/rbac/metrics_reader_role.yaml diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 9f0c1ac..8593fd9 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -5,9 +5,12 @@ metadata: name: manager-role rules: - apiGroups: - - apps + - "" resources: - - deployments + - configmaps + - persistentvolumeclaims + - serviceaccounts + - services verbs: - create - delete @@ -17,12 +20,9 @@ rules: - update - watch - apiGroups: - - "" + - apps resources: - - configmaps - - persistentvolumeclaims - - serviceaccounts - - services + - deployments verbs: - create - delete diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml index 2070ede..c1b12fe 100644 --- a/config/rbac/role_binding.yaml +++ b/config/rbac/role_binding.yaml @@ -1,6 +1,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml index 7cd6025..c654fda 100644 --- a/config/rbac/service_account.yaml +++ b/config/rbac/service_account.yaml @@ -1,5 +1,8 @@ apiVersion: v1 kind: ServiceAccount metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: controller-manager namespace: system diff --git a/config/rbac/synapse_heisenbridge_admin_role.yaml b/config/rbac/synapse_heisenbridge_admin_role.yaml new file mode 100644 index 0000000..859ca6d --- /dev/null +++ b/config/rbac/synapse_heisenbridge_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over synapse.opdev.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: synapse-heisenbridge-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get diff --git a/config/rbac/synapse_heisenbridge_editor_role.yaml b/config/rbac/synapse_heisenbridge_editor_role.yaml index 8bd42d4..05d61ec 100644 --- a/config/rbac/synapse_heisenbridge_editor_role.yaml +++ b/config/rbac/synapse_heisenbridge_editor_role.yaml @@ -1,15 +1,17 @@ -# permissions for end users to edit heisenbridges. +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the synapse.opdev.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: heisenbridge-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: synapse-operator - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - name: heisenbridge-editor-role + name: synapse-heisenbridge-editor-role rules: - apiGroups: - synapse.opdev.io diff --git a/config/rbac/synapse_heisenbridge_viewer_role.yaml b/config/rbac/synapse_heisenbridge_viewer_role.yaml index 223501c..ff657e6 100644 --- a/config/rbac/synapse_heisenbridge_viewer_role.yaml +++ b/config/rbac/synapse_heisenbridge_viewer_role.yaml @@ -1,15 +1,17 @@ -# permissions for end users to view heisenbridges. +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to synapse.opdev.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: heisenbridge-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: synapse-operator - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - name: heisenbridge-viewer-role + name: synapse-heisenbridge-viewer-role rules: - apiGroups: - synapse.opdev.io diff --git a/config/rbac/synapse_mautrixsignal_admin_role.yaml b/config/rbac/synapse_mautrixsignal_admin_role.yaml new file mode 100644 index 0000000..381488e --- /dev/null +++ b/config/rbac/synapse_mautrixsignal_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over synapse.opdev.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: synapse-mautrixsignal-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get diff --git a/config/rbac/synapse_mautrixsignal_editor_role.yaml b/config/rbac/synapse_mautrixsignal_editor_role.yaml index edacdf5..69ef842 100644 --- a/config/rbac/synapse_mautrixsignal_editor_role.yaml +++ b/config/rbac/synapse_mautrixsignal_editor_role.yaml @@ -1,15 +1,17 @@ -# permissions for end users to edit mautrixsignals. +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the synapse.opdev.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: mautrixsignal-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: synapse-operator - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - name: mautrixsignal-editor-role + name: synapse-mautrixsignal-editor-role rules: - apiGroups: - synapse.opdev.io diff --git a/config/rbac/synapse_mautrixsignal_viewer_role.yaml b/config/rbac/synapse_mautrixsignal_viewer_role.yaml index d86d935..09c623d 100644 --- a/config/rbac/synapse_mautrixsignal_viewer_role.yaml +++ b/config/rbac/synapse_mautrixsignal_viewer_role.yaml @@ -1,15 +1,17 @@ -# permissions for end users to view mautrixsignals. +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to synapse.opdev.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: mautrixsignal-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: synapse-operator - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - name: mautrixsignal-viewer-role + name: synapse-mautrixsignal-viewer-role rules: - apiGroups: - synapse.opdev.io diff --git a/config/rbac/synapse_synapse_admin_role.yaml b/config/rbac/synapse_synapse_admin_role.yaml new file mode 100644 index 0000000..e41a99a --- /dev/null +++ b/config/rbac/synapse_synapse_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over synapse.opdev.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: synapse-synapse-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get diff --git a/config/rbac/synapse_synapse_editor_role.yaml b/config/rbac/synapse_synapse_editor_role.yaml new file mode 100644 index 0000000..13e7a09 --- /dev/null +++ b/config/rbac/synapse_synapse_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the synapse.opdev.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: synapse-synapse-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get diff --git a/config/rbac/synapse_synapse_viewer_role.yaml b/config/rbac/synapse_synapse_viewer_role.yaml new file mode 100644 index 0000000..350579a --- /dev/null +++ b/config/rbac/synapse_synapse_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project synapse-operator itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to synapse.opdev.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize + name: synapse-synapse-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 00091a4..49ab6f3 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,6 +1,6 @@ -## Append samples you want in your CSV to this file as resources ## +## Append samples of your project ## resources: - synapse_v1alpha1_synapse.yaml - synapse_v1alpha1_mautrixsignal.yaml - synapse_v1alpha1_heisenbridge.yaml -#+kubebuilder:scaffold:manifestskustomizesamples +# +kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/synapse_v1alpha1_heisenbridge.yaml b/config/samples/synapse_v1alpha1_heisenbridge.yaml index e30d004..046de69 100644 --- a/config/samples/synapse_v1alpha1_heisenbridge.yaml +++ b/config/samples/synapse_v1alpha1_heisenbridge.yaml @@ -2,11 +2,8 @@ apiVersion: synapse.opdev.io/v1alpha1 kind: Heisenbridge metadata: labels: - app.kubernetes.io/name: heisenbridge - app.kubernetes.io/instance: heisenbridge-sample - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: synapse-operator name: heisenbridge-sample spec: synapse: diff --git a/config/samples/synapse_v1alpha1_mautrixsignal.yaml b/config/samples/synapse_v1alpha1_mautrixsignal.yaml index 49e45cc..2954b74 100644 --- a/config/samples/synapse_v1alpha1_mautrixsignal.yaml +++ b/config/samples/synapse_v1alpha1_mautrixsignal.yaml @@ -2,11 +2,8 @@ apiVersion: synapse.opdev.io/v1alpha1 kind: MautrixSignal metadata: labels: - app.kubernetes.io/name: mautrixsignal - app.kubernetes.io/instance: mautrixsignal-sample - app.kubernetes.io/part-of: synapse-operator + app.kubernetes.io/name: synapse-operator app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: synapse-operator name: mautrixsignal-sample spec: synapse: diff --git a/config/samples/synapse_v1alpha1_synapse.yaml b/config/samples/synapse_v1alpha1_synapse.yaml index 1031cae..3296dec 100644 --- a/config/samples/synapse_v1alpha1_synapse.yaml +++ b/config/samples/synapse_v1alpha1_synapse.yaml @@ -1,6 +1,9 @@ apiVersion: synapse.opdev.io/v1alpha1 kind: Synapse metadata: + labels: + app.kubernetes.io/name: synapse-operator + app.kubernetes.io/managed-by: kustomize name: synapse-sample spec: createNewPostgreSQL: false diff --git a/config/scorecard/kustomization.yaml b/config/scorecard/kustomization.yaml index 50cd2d0..54e8aa5 100644 --- a/config/scorecard/kustomization.yaml +++ b/config/scorecard/kustomization.yaml @@ -1,16 +1,18 @@ resources: - bases/config.yaml -patchesJson6902: +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patches: - path: patches/basic.config.yaml target: group: scorecard.operatorframework.io - version: v1alpha3 kind: Configuration name: config + version: v1alpha3 - path: patches/olm.config.yaml target: group: scorecard.operatorframework.io - version: v1alpha3 kind: Configuration name: config -#+kubebuilder:scaffold:patchesJson6902 + version: v1alpha3 +# +kubebuilder:scaffold:patches diff --git a/config/scorecard/patches/basic.config.yaml b/config/scorecard/patches/basic.config.yaml index c04db31..f7e0ed4 100644 --- a/config/scorecard/patches/basic.config.yaml +++ b/config/scorecard/patches/basic.config.yaml @@ -4,7 +4,7 @@ entrypoint: - scorecard-test - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: basic test: basic-check-spec-test diff --git a/config/scorecard/patches/olm.config.yaml b/config/scorecard/patches/olm.config.yaml index 122f703..85895c9 100644 --- a/config/scorecard/patches/olm.config.yaml +++ b/config/scorecard/patches/olm.config.yaml @@ -4,7 +4,7 @@ entrypoint: - scorecard-test - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-bundle-validation-test @@ -14,7 +14,7 @@ entrypoint: - scorecard-test - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-crds-have-validation-test @@ -24,7 +24,7 @@ entrypoint: - scorecard-test - olm-crds-have-resources - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-crds-have-resources-test @@ -34,7 +34,7 @@ entrypoint: - scorecard-test - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-spec-descriptors-test @@ -44,7 +44,7 @@ entrypoint: - scorecard-test - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.12.0 + image: quay.io/operator-framework/scorecard-test:v1.40.0 labels: suite: olm test: olm-status-descriptors-test diff --git a/controllers/synapse/heisenbridge/heisenbridge_test.go b/controllers/synapse/heisenbridge/heisenbridge_test.go deleted file mode 100644 index ee7785d..0000000 --- a/controllers/synapse/heisenbridge/heisenbridge_test.go +++ /dev/null @@ -1,5 +0,0 @@ -// -//This file contains unit tests for the heisenbridge package -// - -package heisenbridge diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_test.go b/controllers/synapse/mautrixsignal/mautrixsignal_test.go deleted file mode 100644 index 1f56e37..0000000 --- a/controllers/synapse/mautrixsignal/mautrixsignal_test.go +++ /dev/null @@ -1,5 +0,0 @@ -// -//This file contains unit tests for the mautrixsignal package -// - -package mautrixsignal diff --git a/go.mod b/go.mod index 82a7207..eeae1ff 100644 --- a/go.mod +++ b/go.mod @@ -2,78 +2,102 @@ module github.com/opdev/synapse-operator go 1.23.0 -toolchain go1.23.4 +godebug default=go1.23 require ( + dario.cat/mergo v1.0.2 github.com/crunchydata/postgres-operator v1.3.3-0.20220202164906-1c3cc3597c95 - github.com/imdario/mergo v0.3.16 - github.com/onsi/ginkgo/v2 v2.22.2 - github.com/onsi/gomega v1.36.2 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 github.com/opdev/subreconciler v0.0.0-20230302151718-c4c8b5ec17c5 - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.32.1 k8s.io/apiextensions-apiserver v0.32.1 k8s.io/apimachinery v0.32.1 k8s.io/client-go v0.32.1 - sigs.k8s.io/controller-runtime v0.20.0 + sigs.k8s.io/controller-runtime v0.20.4 ) require ( + cel.dev/expr v0.18.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.12.1 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/cel-go v0.22.0 // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20250121033306-997b0b79cac0 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.7.7 // 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/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.29.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.7.0 // indirect + golang.org/x/tools v0.26.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/protobuf v1.36.3 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiserver v0.32.1 // indirect + k8s.io/component-base v0.32.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect - k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 7df0e26..cc48352 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,52 @@ +cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo= +cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crunchydata/postgres-operator v1.3.3-0.20220202164906-1c3cc3597c95 h1:lsrJP13Tvx+gBc0ox7GncEAgf6U+cgnRdXrvOG5QYok= github.com/crunchydata/postgres-operator v1.3.3-0.20220202164906-1c3cc3597c95/go.mod h1:NhNMzmVvvdtwj28qJTd6bYztWth1xRATvBI9yuGIHCc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= -github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +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/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +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.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= @@ -36,36 +57,39 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= +github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/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-20250121033306-997b0b79cac0 h1:EinjE47mmVVsxcjIwVKQWNY+3P+5R2BhkbULjhEDThc= -github.com/google/pprof v0.0.0-20250121033306-997b0b79cac0/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +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= +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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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= @@ -73,10 +97,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/opdev/subreconciler v0.0.0-20230302151718-c4c8b5ec17c5 h1:ObusmubWjKaOZZkfeF2CfxQEvLPo4ReV2NsBrnAbBIE= github.com/opdev/subreconciler v0.0.0-20230302151718-c4c8b5ec17c5/go.mod h1:E4wuRlHBNn/V04QINCioS7538YoaODQA8Phmooz18lU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -84,26 +108,52 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.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= @@ -113,48 +163,56 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 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/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -162,8 +220,7 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= @@ -174,19 +231,25 @@ k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+ k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto= k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apiserver v0.32.1 h1:oo0OozRos66WFq87Zc5tclUX2r0mymoVHRq8JmR7Aak= +k8s.io/apiserver v0.32.1/go.mod h1:UcB9tWjBY7aryeI5zAgzVJB/6k7E97bkr1RgqDz0jPw= k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= +k8s.io/component-base v0.32.1 h1:/5IfJ0dHIKBWysGV0yKTFfacZ5yNV1sulPh3ilJjRZk= +k8s.io/component-base v0.32.1/go.mod h1:j1iMMHi/sqAHeG5z+O9BFNCF698a1u0186zkjMZQ28w= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= -k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= -k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.20.0 h1:jjkMo29xEXH+02Md9qaVXfEIaMESSpy3TBWPrsfQkQs= -sigs.k8s.io/controller-runtime v0.20.0/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 45dbbbb..221dcbe 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/helpers/reconcile/reconcile.go b/helpers/reconcile/reconcile.go index dd3b529..5117f9b 100644 --- a/helpers/reconcile/reconcile.go +++ b/helpers/reconcile/reconcile.go @@ -3,10 +3,10 @@ package reconcile import ( "context" - "github.com/imdario/mergo" + "dario.cat/mergo" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" @@ -31,7 +31,7 @@ func ReconcileResource( desired client.Object, current client.Object, ) error { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) log.Info( "Reconciling child resource", "Kind", desired.GetObjectKind().GroupVersionKind().Kind, diff --git a/helpers/utils/bridge_utils.go b/helpers/utils/bridge_utils.go index 9445ceb..c65484f 100644 --- a/helpers/utils/bridge_utils.go +++ b/helpers/utils/bridge_utils.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,12 +23,12 @@ import ( "strings" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" ) const synapseBridgeFinalizer = "synapse.opdev.io/finalizer" @@ -89,9 +89,12 @@ func FetchSynapseInstance( // TriggerSynapseReconciliation returns a function of type subreconciler.FnWithRequest // Bridges should trigger the reconciliation of their associated Synapse server // so that Synapse can add the bridge as an application service in its configuration. -func TriggerSynapseReconciliation(kubeClient client.Client, resource Bridge) func(context.Context, ctrl.Request) (*ctrl.Result, error) { +func TriggerSynapseReconciliation( + kubeClient client.Client, + resource Bridge, +) func(context.Context, ctrl.Request) (*ctrl.Result, error) { return func(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) if r, err := GetResource(ctx, kubeClient, req, resource); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -119,7 +122,7 @@ func TriggerSynapseReconciliation(kubeClient client.Client, resource Bridge) fun // so that Synapse can remove the bridge from the list of application services in its configuration. func HandleDelete(kubeClient client.Client, resource Bridge) func(context.Context, ctrl.Request) (*ctrl.Result, error) { return func(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) if r, err := GetResource(ctx, kubeClient, req, resource); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -162,7 +165,7 @@ func HandleDelete(kubeClient client.Client, resource Bridge) func(context.Contex // AddFinalizer returns a function of type subreconciler.FnWithRequest func AddFinalizer(kubeClient client.Client, resource Bridge) func(context.Context, ctrl.Request) (*ctrl.Result, error) { return func(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) if r, err := GetResource(ctx, kubeClient, req, resource); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/helpers/utils/configmap_utils.go b/helpers/utils/configmap_utils.go index 2791629..874bfee 100644 --- a/helpers/utils/configmap_utils.go +++ b/helpers/utils/configmap_utils.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( "context" "errors" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" diff --git a/helpers/utils/synapse_utils.go b/helpers/utils/synapse_utils.go index 8376ca5..1cc6e26 100644 --- a/helpers/utils/synapse_utils.go +++ b/helpers/utils/synapse_utils.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import ( "time" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -31,7 +31,7 @@ import ( "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" ) func GetResource( @@ -40,7 +40,7 @@ func GetResource( req ctrl.Request, resource client.Object, ) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) if err := kubeClient.Get(ctx, req.NamespacedName, resource); err != nil { if k8serrors.IsNotFound(err) { @@ -68,7 +68,12 @@ func GetResource( return subreconciler.ContinueReconciling() } -func UpdateResourceStatus(ctx context.Context, kubeClient client.Client, resource client.Object, current client.Object) error { +func UpdateResourceStatus( + ctx context.Context, + kubeClient client.Client, + resource client.Object, + current client.Object, +) error { if err := kubeClient.Get( ctx, types.NamespacedName{Name: resource.GetName(), Namespace: resource.GetNamespace()}, @@ -88,9 +93,13 @@ func UpdateResourceStatus(ctx context.Context, kubeClient client.Client, resourc // be called in the main reconciliation loop. // // It creates a copy of the user-provided ConfigMap. -func CopyInputConfigMap(kubeClient client.Client, runtimeScheme *runtime.Scheme, resource client.Object) func(context.Context, ctrl.Request) (*ctrl.Result, error) { +func CopyInputConfigMap( + kubeClient client.Client, + runtimeScheme *runtime.Scheme, + resource client.Object, +) func(context.Context, ctrl.Request) (*ctrl.Result, error) { return func(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) if r, err := GetResource(ctx, kubeClient, req, resource); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -120,7 +129,7 @@ func CopyInputConfigMap(kubeClient client.Client, runtimeScheme *runtime.Scheme, objectMeta := reconcile.SetObjectMeta(resource.GetName(), resource.GetNamespace(), map[string]string{}) - desiredConfigMap, err := configMapForCopy(ctx, objectMeta, kubeClient, resource, runtimeScheme) + desiredConfigMap, err := configMapForCopy(objectMeta, kubeClient, resource, runtimeScheme) if err != nil { return subreconciler.RequeueWithError(err) } @@ -142,7 +151,6 @@ func CopyInputConfigMap(kubeClient client.Client, runtimeScheme *runtime.Scheme, // The ConfigMap returned by configMapForCopy is a copy of the user-defined // ConfigMap. func configMapForCopy( - ctx context.Context, objectMeta metav1.ObjectMeta, kubeClient client.Client, resource client.Object, @@ -174,22 +182,23 @@ func configMapForCopy( } func SetFailedState(ctx context.Context, kubeClient client.Client, resource client.Object, reason string) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) var err error + const failed = "FAILED" switch v := resource.(type) { case *synapsev1alpha1.Synapse: - v.Status.State = "FAILED" + v.Status.State = failed v.Status.Reason = reason err = UpdateResourceStatus(ctx, kubeClient, v, &synapsev1alpha1.Synapse{}) case *synapsev1alpha1.Heisenbridge: - v.Status.State = "FAILED" + v.Status.State = failed v.Status.Reason = reason err = UpdateResourceStatus(ctx, kubeClient, v, &synapsev1alpha1.Heisenbridge{}) case *synapsev1alpha1.MautrixSignal: - v.Status.State = "FAILED" + v.Status.State = failed v.Status.Reason = reason err = UpdateResourceStatus(ctx, kubeClient, v, &synapsev1alpha1.MautrixSignal{}) diff --git a/helpers/utils/tests_utils.go b/helpers/utils/tests_utils.go index bac42ed..1ee3d32 100644 --- a/helpers/utils/tests_utils.go +++ b/helpers/utils/tests_utils.go @@ -10,7 +10,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + "github.com/opdev/synapse-operator/api/synapse/v1alpha1" ) // Helper function for struct construction requiring a boolean pointer diff --git a/helpers/utils/utils.go b/helpers/utils/utils.go index 893c6ce..0ddba8a 100644 --- a/helpers/utils/utils.go +++ b/helpers/utils/utils.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ limitations under the License. package utils -import "gopkg.in/yaml.v2" +import "gopkg.in/yaml.v3" func ConvertStructToMap(in interface{}) (map[string]interface{}, error) { var intermediate []byte diff --git a/install/synapse-operator.yaml b/install/synapse-operator.yaml index ad3bc3e..ed539ae 100644 --- a/install/synapse-operator.yaml +++ b/install/synapse-operator.yaml @@ -2,6 +2,8 @@ apiVersion: v1 kind: Namespace metadata: labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator control-plane: controller-manager name: synapse-operator-system --- @@ -9,7 +11,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: heisenbridges.synapse.opdev.io spec: group: synapse.opdev.io @@ -23,7 +25,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Heisenbridge is the Schema for the heisenbridges API + description: Heisenbridge is the Schema for the heisenbridges API. properties: apiVersion: description: |- @@ -93,7 +95,7 @@ spec: - synapse type: object status: - description: HeisenbridgeStatus defines the observed state of Heisenbridge + description: HeisenbridgeStatus defines the observed state of Heisenbridge. properties: reason: description: Reason for the current Heisenbridge State @@ -114,7 +116,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: mautrixsignals.synapse.opdev.io spec: group: synapse.opdev.io @@ -128,7 +130,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: MautrixSignal is the Schema for the mautrixsignals API + description: MautrixSignal is the Schema for the mautrixsignals API. properties: apiVersion: description: |- @@ -189,7 +191,7 @@ spec: - synapse type: object status: - description: MautrixSignalStatus defines the observed state of MautrixSignal + description: MautrixSignalStatus defines the observed state of MautrixSignal. properties: isOpenshift: default: false @@ -221,7 +223,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.17.2 name: synapses.synapse.opdev.io spec: group: synapse.opdev.io @@ -235,7 +237,7 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Synapse is the Schema for the synapses API + description: Synapse is the Schema for the synapses API. properties: apiVersion: description: |- @@ -255,7 +257,7 @@ spec: metadata: type: object spec: - description: SynapseSpec defines the desired state of Synapse + description: SynapseSpec defines the desired state of Synapse. properties: createNewPostgreSQL: default: false @@ -317,7 +319,7 @@ spec: - homeserver type: object status: - description: SynapseStatus defines the observed state of Synapse + description: SynapseStatus defines the observed state of Synapse. properties: bridges: description: Information on the bridges deployed alongside Synapse @@ -397,12 +399,18 @@ spec: apiVersion: v1 kind: ServiceAccount metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator name: synapse-operator-controller-manager namespace: synapse-operator-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator name: synapse-operator-leader-election-role namespace: synapse-operator-system rules: @@ -444,9 +452,12 @@ metadata: name: synapse-operator-manager-role rules: - apiGroups: - - apps + - "" resources: - - deployments + - configmaps + - persistentvolumeclaims + - serviceaccounts + - services verbs: - create - delete @@ -456,12 +467,9 @@ rules: - update - watch - apiGroups: - - "" + - apps resources: - - configmaps - - persistentvolumeclaims - - serviceaccounts - - services + - deployments verbs: - create - delete @@ -537,6 +545,24 @@ rules: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + name: synapse-operator-metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: name: synapse-operator-metrics-reader rules: @@ -548,24 +574,222 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: synapse-operator-proxy-role + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-admin-role rules: - apiGroups: - - authentication.k8s.io + - synapse.opdev.io resources: - - tokenreviews + - heisenbridges + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges verbs: - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - - authorization.k8s.io + - synapse.opdev.io resources: - - subjectaccessreviews + - heisenbridges/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-heisenbridge-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - heisenbridges/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-mautrixsignal-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - mautrixsignals/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-admin-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - '*' +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-editor-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses verbs: - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator + name: synapse-operator-synapse-synapse-viewer-role +rules: +- apiGroups: + - synapse.opdev.io + resources: + - synapses + verbs: + - get + - list + - watch +- apiGroups: + - synapse.opdev.io + resources: + - synapses/status + verbs: + - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator name: synapse-operator-leader-election-rolebinding namespace: synapse-operator-system roleRef: @@ -580,6 +804,9 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator name: synapse-operator-manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io @@ -593,39 +820,22 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: synapse-operator-proxy-rolebinding + name: synapse-operator-metrics-auth-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: synapse-operator-proxy-role + name: synapse-operator-metrics-auth-role subjects: - kind: ServiceAccount name: synapse-operator-controller-manager namespace: synapse-operator-system --- apiVersion: v1 -data: - controller_manager_config.yaml: | - apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 - kind: ControllerManagerConfig - health: - healthProbeBindAddress: :8081 - metrics: - bindAddress: 127.0.0.1:8080 - webhook: - port: 9443 - leaderElection: - leaderElect: true - resourceName: 8d311e9b.opdev.io -kind: ConfigMap -metadata: - name: synapse-operator-manager-config - namespace: synapse-operator-system ---- -apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator control-plane: controller-manager name: synapse-operator-controller-manager-metrics-service namespace: synapse-operator-system @@ -634,14 +844,17 @@ spec: - name: https port: 8443 protocol: TCP - targetPort: https + targetPort: 8443 selector: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager --- apiVersion: apps/v1 kind: Deployment metadata: labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: synapse-operator control-plane: controller-manager name: synapse-operator-controller-manager namespace: synapse-operator-system @@ -649,28 +862,21 @@ spec: replicas: 1 selector: matchLabels: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager template: metadata: + annotations: + kubectl.kubernetes.io/default-container: manager labels: + app.kubernetes.io/name: synapse-operator control-plane: controller-manager spec: containers: - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=10 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - protocol: TCP - - args: - - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 + - --metrics-bind-address=:8443 - --leader-elect + - --health-probe-bind-address=:8081 command: - /manager image: quay.io/opdev/synapse-operator:v0.6.1 @@ -681,6 +887,7 @@ spec: initialDelaySeconds: 15 periodSeconds: 20 name: manager + ports: [] readinessProbe: httpGet: path: /readyz @@ -689,14 +896,21 @@ spec: periodSeconds: 10 resources: limits: - cpu: 200m - memory: 100Mi + cpu: 500m + memory: 128Mi requests: - cpu: 100m - memory: 20Mi + cpu: 10m + memory: 64Mi securityContext: allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volumeMounts: [] securityContext: runAsNonRoot: true + seccompProfile: + type: RuntimeDefault serviceAccountName: synapse-operator-controller-manager terminationGracePeriodSeconds: 10 + volumes: [] diff --git a/controllers/synapse/heisenbridge/heisenbridge_configmap.go b/internal/controller/synapse/heisenbridge/heisenbridge_configmap.go similarity index 92% rename from controllers/synapse/heisenbridge/heisenbridge_configmap.go rename to internal/controller/synapse/heisenbridge/heisenbridge_configmap.go index 43c66c1..6f6e2fb 100644 --- a/controllers/synapse/heisenbridge/heisenbridge_configmap.go +++ b/internal/controller/synapse/heisenbridge/heisenbridge_configmap.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -37,7 +37,10 @@ import ( // // It reconciles the heisenbridge ConfigMap to its desired state. It is called // only if the user hasn't provided its own ConfigMap for heisenbridge -func (r *HeisenbridgeReconciler) reconcileHeisenbridgeConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *HeisenbridgeReconciler) reconcileHeisenbridgeConfigMap( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { h := &synapsev1alpha1.Heisenbridge{} if r, err := utils.GetResource(ctx, r.Client, req, h); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -72,7 +75,10 @@ func (r *HeisenbridgeReconciler) configMapForHeisenbridge(h *synapsev1alpha1.Hei HeisenbridgeFQDN: utils.ComputeFQDN(h.Name, h.Namespace), } - cm, err := templates.ResourceFromTemplate[configmapExtraValues, corev1.ConfigMap](&extraValues, "heisenbridge_configmap") + cm, err := templates.ResourceFromTemplate[configmapExtraValues, corev1.ConfigMap]( + &extraValues, + "heisenbridge_configmap", + ) if err != nil { return nil, fmt.Errorf("could not get template: %v", err) } @@ -90,7 +96,10 @@ func (r *HeisenbridgeReconciler) configMapForHeisenbridge(h *synapsev1alpha1.Hei // // Following the previous copy of the user-provided ConfigMap, it edits the // content of the copy to ensure that heisenbridge is correctly configured. -func (r *HeisenbridgeReconciler) configureHeisenbridgeConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *HeisenbridgeReconciler) configureHeisenbridgeConfigMap( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { h := &synapsev1alpha1.Heisenbridge{} if r, err := utils.GetResource(ctx, r.Client, req, h); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/controllers/synapse/heisenbridge/heisenbridge_controller.go b/internal/controller/synapse/heisenbridge/heisenbridge_controller.go similarity index 88% rename from controllers/synapse/heisenbridge/heisenbridge_controller.go rename to internal/controller/synapse/heisenbridge/heisenbridge_controller.go index efe014c..a981934 100644 --- a/controllers/synapse/heisenbridge/heisenbridge_controller.go +++ b/internal/controller/synapse/heisenbridge/heisenbridge_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -34,9 +34,9 @@ type HeisenbridgeReconciler struct { Scheme *runtime.Scheme } -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges/finalizers,verbs=update +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=heisenbridges/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -46,7 +46,7 @@ type HeisenbridgeReconciler struct { // the user. // // For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/reconcile func (r *HeisenbridgeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var h synapsev1alpha1.Heisenbridge // The Heisenbridge object being reconciled if r, err := utils.GetResource(ctx, r.Client, req, &h); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -107,5 +107,6 @@ func (r *HeisenbridgeReconciler) Reconcile(ctx context.Context, req ctrl.Request func (r *HeisenbridgeReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&synapsev1alpha1.Heisenbridge{}). + Named("synapse-heisenbridge"). Complete(r) } diff --git a/controllers/synapse/heisenbridge/heisenbridge_controller_test.go b/internal/controller/synapse/heisenbridge/heisenbridge_controller_test.go similarity index 90% rename from controllers/synapse/heisenbridge/heisenbridge_controller_test.go rename to internal/controller/synapse/heisenbridge/heisenbridge_controller_test.go index ce80202..3749e70 100644 --- a/controllers/synapse/heisenbridge/heisenbridge_controller_test.go +++ b/internal/controller/synapse/heisenbridge/heisenbridge_controller_test.go @@ -1,7 +1,24 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package heisenbridge import ( "context" + "os" "path/filepath" "strconv" @@ -10,7 +27,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -25,7 +42,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/metrics/server" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -36,7 +53,7 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L HeisenbridgeNamespace = "default" InputConfigMapName = "test-configmap" - // Name and namespace of the Heisenbridge instance refered by the Heisenbridge Bridge + // Name and namespace of the Heisenbridge instance referred by the Heisenbridge Bridge SynapseName = "test-synapse" SynapseNamespace = "default" SynapseServerName = "my.matrix.host" @@ -58,13 +75,18 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L // Common function to start envTest var startenvTest = func() { + // Retrieve the first found binary directory to allow running tests from IDEs + if getFirstFoundEnvTestBinaryDir() != "" { + testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() + } + cfg, err := testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) Expect(synapsev1alpha1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) - //+kubebuilder:scaffold:scheme + // +kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) @@ -104,8 +126,8 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_heisenbridges.yaml"), - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_heisenbridges.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), }, ErrorIfCRDPathMissing: true, } @@ -281,7 +303,6 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L }, } Expect(k8sClient.Create(ctx, synapse)).Should(Succeed()) - k8sClient.Get(ctx, synapseLookupKey, synapse) By("Verifying that the Synapse object was created") Eventually(func() bool { @@ -386,7 +407,6 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L var heisenbridgeYaml string = "" const heisenbridgeFQDN = HeisenbridgeName + "." + HeisenbridgeNamespace + ".svc.cluster.local" - const synapseFQDN = SynapseName + "." + SynapseNamespace + ".svc.cluster.local" const heisenbridgePort = 9898 var createHeisenbridgeConfigMap = func() { @@ -615,3 +635,26 @@ var _ = Describe("Integration tests for the Heisenbridge controller", Ordered, L }) }) }) + +// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. +// ENVTEST-based tests depend on specific binaries, usually located in paths set by +// controller-runtime. When running tests directly (e.g., via an IDE) without using +// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. +// +// This function streamlines the process by finding the required binaries, similar to +// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are +// properly set up, run 'make setup-envtest' beforehand. +func getFirstFoundEnvTestBinaryDir() string { + basePath := filepath.Join("..", "..", "..", "..", "bin", "k8s") + entries, err := os.ReadDir(basePath) + if err != nil { + logf.Log.Error(err, "Failed to read directory", "path", basePath) + return "" + } + for _, entry := range entries { + if entry.IsDir() { + return filepath.Join(basePath, entry.Name()) + } + } + return "" +} diff --git a/controllers/synapse/heisenbridge/heisenbridge_deployment.go b/internal/controller/synapse/heisenbridge/heisenbridge_deployment.go similarity index 89% rename from controllers/synapse/heisenbridge/heisenbridge_deployment.go rename to internal/controller/synapse/heisenbridge/heisenbridge_deployment.go index 45584d0..3cb744b 100644 --- a/controllers/synapse/heisenbridge/heisenbridge_deployment.go +++ b/internal/controller/synapse/heisenbridge/heisenbridge_deployment.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -40,7 +40,10 @@ func labelsForHeisenbridge(name string) map[string]string { // be called in the main reconciliation loop. // // It reconciles the Deployment for Heisenbridge to its desired state. -func (r *HeisenbridgeReconciler) reconcileHeisenbridgeDeployment(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *HeisenbridgeReconciler) reconcileHeisenbridgeDeployment( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { h := &synapsev1alpha1.Heisenbridge{} if r, err := utils.GetResource(ctx, r.Client, req, h); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -64,7 +67,9 @@ func (r *HeisenbridgeReconciler) reconcileHeisenbridgeDeployment(ctx context.Con } // deploymentForHeisenbridge returns a Heisenbridge Deployment object -func (r *HeisenbridgeReconciler) deploymentForHeisenbridge(h *synapsev1alpha1.Heisenbridge) (*appsv1.Deployment, error) { +func (r *HeisenbridgeReconciler) deploymentForHeisenbridge( + h *synapsev1alpha1.Heisenbridge, +) (*appsv1.Deployment, error) { type deploymentExtraValues struct { synapsev1alpha1.Heisenbridge Labels map[string]string @@ -77,7 +82,10 @@ func (r *HeisenbridgeReconciler) deploymentForHeisenbridge(h *synapsev1alpha1.He Command: r.craftHeisenbridgeCommad(*h), } - dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment](&extraValues, "heisenbridge_deployment") + dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment]( + &extraValues, + "heisenbridge_deployment", + ) if err != nil { return nil, fmt.Errorf("could not get template: %v", err) } diff --git a/controllers/synapse/heisenbridge/heisenbridge_service.go b/internal/controller/synapse/heisenbridge/heisenbridge_service.go similarity index 91% rename from controllers/synapse/heisenbridge/heisenbridge_service.go rename to internal/controller/synapse/heisenbridge/heisenbridge_service.go index 1352385..f311c2c 100644 --- a/controllers/synapse/heisenbridge/heisenbridge_service.go +++ b/internal/controller/synapse/heisenbridge/heisenbridge_service.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -34,7 +34,10 @@ import ( // called in the main reconciliation loop. // // It reconciles the Service for Heisenbridge to its desired state. -func (r *HeisenbridgeReconciler) reconcileHeisenbridgeService(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *HeisenbridgeReconciler) reconcileHeisenbridgeService( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { h := &synapsev1alpha1.Heisenbridge{} if r, err := utils.GetResource(ctx, r.Client, req, h); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/internal/controller/synapse/heisenbridge/heisenbridge_test.go b/internal/controller/synapse/heisenbridge/heisenbridge_test.go new file mode 100644 index 0000000..a927a8a --- /dev/null +++ b/internal/controller/synapse/heisenbridge/heisenbridge_test.go @@ -0,0 +1,5 @@ +// +// This file contains unit tests for the heisenbridge package +// + +package heisenbridge diff --git a/controllers/synapse/heisenbridge/suite_test.go b/internal/controller/synapse/heisenbridge/suite_test.go similarity index 94% rename from controllers/synapse/heisenbridge/suite_test.go rename to internal/controller/synapse/heisenbridge/suite_test.go index fdee86a..91ab54f 100644 --- a/controllers/synapse/heisenbridge/suite_test.go +++ b/internal/controller/synapse/heisenbridge/suite_test.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - //+kubebuilder:scaffold:imports + // +kubebuilder:scaffold:imports ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_configmap.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_configmap.go similarity index 87% rename from controllers/synapse/mautrixsignal/mautrixsignal_configmap.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_configmap.go index 4974158..1820bd7 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_configmap.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_configmap.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -39,7 +39,10 @@ import ( // It reconciles the mautrix-signal ConfigMap to its desired state. It is // called only if the user hasn't provided its own ConfigMap for // mautrix-signal. -func (r *MautrixSignalReconciler) reconcileMautrixSignalConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalConfigMap( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -63,7 +66,9 @@ func (r *MautrixSignalReconciler) reconcileMautrixSignalConfigMap(ctx context.Co } // configMapForSynapse returns a synapse ConfigMap object -func (r *MautrixSignalReconciler) configMapForMautrixSignal(ms *synapsev1alpha1.MautrixSignal) (*corev1.ConfigMap, error) { +func (r *MautrixSignalReconciler) configMapForMautrixSignal( + ms *synapsev1alpha1.MautrixSignal, +) (*corev1.ConfigMap, error) { synapseName := ms.Spec.Synapse.Name synapseNamespace := utils.ComputeNamespace(ms.Namespace, ms.Spec.Synapse.Namespace) @@ -79,7 +84,10 @@ func (r *MautrixSignalReconciler) configMapForMautrixSignal(ms *synapsev1alpha1. MautrixsignalFQDN: utils.ComputeFQDN(ms.Name, ms.Namespace), } - cm, err := templates.ResourceFromTemplate[configmapExtraValues, corev1.ConfigMap](&extraValues, "mautrixsignal_configmap") + cm, err := templates.ResourceFromTemplate[configmapExtraValues, corev1.ConfigMap]( + &extraValues, + "mautrixsignal_configmap", + ) if err != nil { return nil, fmt.Errorf("could not get template: %v", err) } @@ -97,7 +105,9 @@ func (r *MautrixSignalReconciler) configMapForMautrixSignal(ms *synapsev1alpha1. // // Following the previous copy of the user-provided ConfigMap, it edits the // content of the copy to ensure that mautrix-signal is correctly configured. -func (r *MautrixSignalReconciler) configureMautrixSignalConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) configureMautrixSignalConfigMap( + ctx context.Context, req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -140,7 +150,7 @@ func (r *MautrixSignalReconciler) updateMautrixSignalData( synapseServerName := ms.Status.Synapse.ServerName // Update the homeserver section so that the bridge can reach Synapse - configHomeserver, ok := config["homeserver"].(map[interface{}]interface{}) + configHomeserver, ok := config["homeserver"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'homeserver' section") return err @@ -150,7 +160,7 @@ func (r *MautrixSignalReconciler) updateMautrixSignalData( config["homeserver"] = configHomeserver // Update the appservice section so that Synapse can reach the bridge - configAppservice, ok := config["appservice"].(map[interface{}]interface{}) + configAppservice, ok := config["appservice"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'appservice' section") return err @@ -159,7 +169,7 @@ func (r *MautrixSignalReconciler) updateMautrixSignalData( config["appservice"] = configAppservice // Update the path to the signal socket path - configSignal, ok := config["signal"].(map[interface{}]interface{}) + configSignal, ok := config["signal"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'signal' section") return err @@ -168,7 +178,7 @@ func (r *MautrixSignalReconciler) updateMautrixSignalData( config["signal"] = configSignal // Update persmissions to use the correct domain name - configBridge, ok := config["bridge"].(map[interface{}]interface{}) + configBridge, ok := config["bridge"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'bridge' section") return err @@ -181,17 +191,17 @@ func (r *MautrixSignalReconciler) updateMautrixSignalData( config["bridge"] = configBridge // Update the path to the log file - configLogging, ok := config["logging"].(map[interface{}]interface{}) + configLogging, ok := config["logging"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'logging' section") return err } - configLoggingHandlers, ok := configLogging["handlers"].(map[interface{}]interface{}) + configLoggingHandlers, ok := configLogging["handlers"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'logging/handlers' section") return err } - configLoggingHandlersFile, ok := configLoggingHandlers["file"].(map[interface{}]interface{}) + configLoggingHandlersFile, ok := configLoggingHandlers["file"].(map[string]interface{}) if !ok { err := errors.New("cannot parse mautrix-signal config.yaml: error parsing 'logging/handlers/file' section") return err diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_controller.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_controller.go similarity index 88% rename from controllers/synapse/mautrixsignal/mautrixsignal_controller.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_controller.go index 8a08ebe..45f7de5 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_controller.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ import ( "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -35,9 +35,9 @@ type MautrixSignalReconciler struct { Scheme *runtime.Scheme } -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals/finalizers,verbs=update +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=mautrixsignals/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -47,7 +47,7 @@ type MautrixSignalReconciler struct { // the user. // // For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/reconcile func (r *MautrixSignalReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var ms synapsev1alpha1.MautrixSignal // The mautrix-signal object being reconciled if r, err := utils.GetResource(ctx, r.Client, req, &ms); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -115,8 +115,11 @@ func (r *MautrixSignalReconciler) Reconcile(ctx context.Context, req ctrl.Reques return subreconciler.Evaluate(subreconciler.DoNotRequeue()) } -func (r *MautrixSignalReconciler) buildMautrixSignalStatus(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) +func (r *MautrixSignalReconciler) buildMautrixSignalStatus( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { + log := logf.FromContext(ctx) ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -157,5 +160,6 @@ func (r *MautrixSignalReconciler) buildMautrixSignalStatus(ctx context.Context, func (r *MautrixSignalReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&synapsev1alpha1.MautrixSignal{}). + Named("synapse-mautrixsignal"). Complete(r) } diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_controller_test.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_controller_test.go similarity index 89% rename from controllers/synapse/mautrixsignal/mautrixsignal_controller_test.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_controller_test.go index 15c7da4..88e7eea 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_controller_test.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_controller_test.go @@ -1,7 +1,24 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package mautrixsignal import ( "context" + "os" "path/filepath" "strconv" @@ -10,7 +27,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -26,7 +43,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/metrics/server" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -37,7 +54,7 @@ var _ = Describe("Integration tests for the MautrixSignal controller", Ordered, MautrixSignalNamespace = "default" InputConfigMapName = "test-configmap" - // Name and namespace of the MautrixSignal instance refered by the MautrixSignal Bridge + // Name and namespace of the MautrixSignal instance referred by the MautrixSignal Bridge SynapseName = "test-synapse" SynapseNamespace = "default" SynapseServerName = "my.matrix.host" @@ -59,13 +76,18 @@ var _ = Describe("Integration tests for the MautrixSignal controller", Ordered, // Common function to start envTest var startenvTest = func() { + // Retrieve the first found binary directory to allow running tests from IDEs + if getFirstFoundEnvTestBinaryDir() != "" { + testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() + } + cfg, err := testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) Expect(synapsev1alpha1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) - //+kubebuilder:scaffold:scheme + // +kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) @@ -105,8 +127,8 @@ var _ = Describe("Integration tests for the MautrixSignal controller", Ordered, By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_mautrixsignals.yaml"), - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_mautrixsignals.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), }, ErrorIfCRDPathMissing: true, } @@ -289,7 +311,6 @@ var _ = Describe("Integration tests for the MautrixSignal controller", Ordered, }, } Expect(k8sClient.Create(ctx, synapse)).Should(Succeed()) - k8sClient.Get(ctx, synapseLookupKey, synapse) // Manually populating the status as the Synapse controller is not running synapse.Status = synapsev1alpha1.SynapseStatus{ HomeserverConfiguration: synapsev1alpha1.SynapseStatusHomeserverConfiguration{ @@ -550,36 +571,37 @@ logging: g.Expect(yaml.Unmarshal([]byte(ConfigMapdata), config)).Should(Succeed()) By("Verifying that the homeserver configuration has been updated") - configHomeserver, ok := config["homeserver"].(map[interface{}]interface{}) + configHomeserver, ok := config["homeserver"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) g.Expect(configHomeserver["address"]).To(Equal("http://" + synapseFQDN + ":8008")) g.Expect(configHomeserver["domain"]).To(Equal(SynapseServerName)) By("Verifying that the appservice configuration has been updated") - configAppservice, ok := config["appservice"].(map[interface{}]interface{}) + expectedConfigAppServiceAddress := "http://" + mautrixsignalFQDN + ":" + strconv.Itoa(mautrixsignalPort) + configAppservice, ok := config["appservice"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) - g.Expect(configAppservice["address"]).To(Equal("http://" + mautrixsignalFQDN + ":" + strconv.Itoa(mautrixsignalPort))) + g.Expect(configAppservice["address"]).To(Equal(expectedConfigAppServiceAddress)) By("Verifying that the signal configuration has been updated") - configSignal, ok := config["signal"].(map[interface{}]interface{}) + configSignal, ok := config["signal"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) g.Expect(configSignal["socket_path"]).To(Equal("/signald/signald.sock")) By("Verifying that the permissions have been updated") - configBridge, ok := config["bridge"].(map[interface{}]interface{}) + configBridge, ok := config["bridge"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) - configBridgePermissions, ok := configBridge["permissions"].(map[interface{}]interface{}) + configBridgePermissions, ok := configBridge["permissions"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) g.Expect(configBridgePermissions).Should(HaveKeyWithValue("*", "relay")) g.Expect(configBridgePermissions).Should(HaveKeyWithValue(SynapseServerName, "user")) g.Expect(configBridgePermissions).Should(HaveKeyWithValue("@admin:"+SynapseServerName, "admin")) By("Verifying that the log configuration file path have been updated") - configLogging, ok := config["logging"].(map[interface{}]interface{}) + configLogging, ok := config["logging"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) - configLoggingHandlers, ok := configLogging["handlers"].(map[interface{}]interface{}) + configLoggingHandlers, ok := configLogging["handlers"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) - configLoggingHandlersFile, ok := configLoggingHandlers["file"].(map[interface{}]interface{}) + configLoggingHandlersFile, ok := configLoggingHandlers["file"].(map[string]interface{}) g.Expect(ok).Should(BeTrue()) g.Expect(configLoggingHandlersFile["filename"]).To(Equal("/data/mautrix-signal.log")) }, timeout, interval).Should(Succeed()) @@ -721,3 +743,26 @@ logging: }) }) }) + +// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. +// ENVTEST-based tests depend on specific binaries, usually located in paths set by +// controller-runtime. When running tests directly (e.g., via an IDE) without using +// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. +// +// This function streamlines the process by finding the required binaries, similar to +// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are +// properly set up, run 'make setup-envtest' beforehand. +func getFirstFoundEnvTestBinaryDir() string { + basePath := filepath.Join("..", "..", "..", "..", "bin", "k8s") + entries, err := os.ReadDir(basePath) + if err != nil { + logf.Log.Error(err, "Failed to read directory", "path", basePath) + return "" + } + for _, entry := range entries { + if entry.IsDir() { + return filepath.Join(basePath, entry.Name()) + } + } + return "" +} diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_deployment.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_deployment.go similarity index 87% rename from controllers/synapse/mautrixsignal/mautrixsignal_deployment.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_deployment.go index 1108ddd..7cfbe3b 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_deployment.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_deployment.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -40,7 +40,10 @@ func labelsForMautrixSignal(name string) map[string]string { // to be called in the main reconciliation loop. // // It reconciles the Deployment for mautrix-signal to its desired state. -func (r *MautrixSignalReconciler) reconcileMautrixSignalDeployment(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalDeployment( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -64,7 +67,9 @@ func (r *MautrixSignalReconciler) reconcileMautrixSignalDeployment(ctx context.C } // deploymentForMautrixSignal returns a Deployment object for the mautrix-signal bridge -func (r *MautrixSignalReconciler) deploymentForMautrixSignal(ms *synapsev1alpha1.MautrixSignal) (*appsv1.Deployment, error) { +func (r *MautrixSignalReconciler) deploymentForMautrixSignal( + ms *synapsev1alpha1.MautrixSignal, +) (*appsv1.Deployment, error) { type deploymentExtraValues struct { synapsev1alpha1.MautrixSignal Labels map[string]string @@ -75,7 +80,10 @@ func (r *MautrixSignalReconciler) deploymentForMautrixSignal(ms *synapsev1alpha1 Labels: labelsForMautrixSignal(ms.Name), } - dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment](&extraValues, "mautrixsignal_deployment") + dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment]( + &extraValues, + "mautrixsignal_deployment", + ) if err != nil { return nil, fmt.Errorf("could not get template: %v", err) } diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_pvc.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_pvc.go similarity index 87% rename from controllers/synapse/mautrixsignal/mautrixsignal_pvc.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_pvc.go index c731c9c..d2d85fa 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_pvc.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_pvc.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -34,7 +34,10 @@ import ( // called in the main reconciliation loop. // // It reconciles the PVC for mautrix-signal to its desired state. -func (r *MautrixSignalReconciler) reconcileMautrixSignalPVC(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalPVC( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -58,7 +61,9 @@ func (r *MautrixSignalReconciler) reconcileMautrixSignalPVC(ctx context.Context, } // persistentVolumeClaimForMautrixSignal returns a mautrix-signal PVC object -func (r *MautrixSignalReconciler) persistentVolumeClaimForMautrixSignal(ms *synapsev1alpha1.MautrixSignal) (*corev1.PersistentVolumeClaim, error) { +func (r *MautrixSignalReconciler) persistentVolumeClaimForMautrixSignal( + ms *synapsev1alpha1.MautrixSignal, +) (*corev1.PersistentVolumeClaim, error) { pvc, err := templates.ResourceFromTemplate[synapsev1alpha1.MautrixSignal, corev1.PersistentVolumeClaim](ms, "pvc") if err != nil { return nil, fmt.Errorf("could not get template: %v", err) diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_service.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_service.go similarity index 94% rename from controllers/synapse/mautrixsignal/mautrixsignal_service.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_service.go index 801606a..f1418cd 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_service.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_service.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -34,7 +34,10 @@ import ( // be called in the main reconciliation loop. // // It reconciles the Service for mautrix-signal to its desired state. -func (r *MautrixSignalReconciler) reconcileMautrixSignalService(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalService( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/controllers/synapse/mautrixsignal/mautrixsignal_serviceaccount.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_serviceaccount.go similarity index 89% rename from controllers/synapse/mautrixsignal/mautrixsignal_serviceaccount.go rename to internal/controller/synapse/mautrixsignal/mautrixsignal_serviceaccount.go index dad2c6f..d22f35c 100644 --- a/controllers/synapse/mautrixsignal/mautrixsignal_serviceaccount.go +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_serviceaccount.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -36,7 +36,10 @@ import ( // FnWithRequest, to be called in the main reconciliation loop. // // It reconciles the ServiceAccount for mautrix-signal to its desired state. -func (r *MautrixSignalReconciler) reconcileMautrixSignalServiceAccount(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalServiceAccount( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -60,7 +63,9 @@ func (r *MautrixSignalReconciler) reconcileMautrixSignalServiceAccount(ctx conte } // serviceAccountForMautrixSignal returns a ServiceAccount object for running the mautrix-signal bridge -func (r *MautrixSignalReconciler) serviceAccountForMautrixSignal(ms *synapsev1alpha1.MautrixSignal) (client.Object, error) { +func (r *MautrixSignalReconciler) serviceAccountForMautrixSignal( + ms *synapsev1alpha1.MautrixSignal, +) (client.Object, error) { // TODO: https://github.com/opdev/synapse-operator/issues/19 sa, err := templates.ResourceFromTemplate[synapsev1alpha1.MautrixSignal, corev1.ServiceAccount](ms, "serviceaccount") if err != nil { @@ -78,7 +83,10 @@ func (r *MautrixSignalReconciler) serviceAccountForMautrixSignal(ms *synapsev1al // to be called in the main reconciliation loop. // // It reconciles the RoleBinding for mautrix-signal to its desired state. -func (r *MautrixSignalReconciler) reconcileMautrixSignalRoleBinding(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *MautrixSignalReconciler) reconcileMautrixSignalRoleBinding( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { ms := &synapsev1alpha1.MautrixSignal{} if r, err := utils.GetResource(ctx, r.Client, req, ms); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -102,7 +110,9 @@ func (r *MautrixSignalReconciler) reconcileMautrixSignalRoleBinding(ctx context. } // roleBindingForMautrixSignal returns a RoleBinding object for the mautrix-signal bridge -func (r *MautrixSignalReconciler) roleBindingForMautrixSignal(ms *synapsev1alpha1.MautrixSignal) (*rbacv1.RoleBinding, error) { +func (r *MautrixSignalReconciler) roleBindingForMautrixSignal( + ms *synapsev1alpha1.MautrixSignal, +) (*rbacv1.RoleBinding, error) { // TODO: https://github.com/opdev/synapse-operator/issues/19 rb, err := templates.ResourceFromTemplate[synapsev1alpha1.MautrixSignal, rbacv1.RoleBinding](ms, "rolebinding") if err != nil { diff --git a/internal/controller/synapse/mautrixsignal/mautrixsignal_test.go b/internal/controller/synapse/mautrixsignal/mautrixsignal_test.go new file mode 100644 index 0000000..183a3c0 --- /dev/null +++ b/internal/controller/synapse/mautrixsignal/mautrixsignal_test.go @@ -0,0 +1,5 @@ +// +// This file contains unit tests for the mautrixsignal package +// + +package mautrixsignal diff --git a/controllers/synapse/mautrixsignal/suite_test.go b/internal/controller/synapse/mautrixsignal/suite_test.go similarity index 94% rename from controllers/synapse/mautrixsignal/suite_test.go rename to internal/controller/synapse/mautrixsignal/suite_test.go index 6006435..e289c73 100644 --- a/controllers/synapse/mautrixsignal/suite_test.go +++ b/internal/controller/synapse/mautrixsignal/suite_test.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - //+kubebuilder:scaffold:imports + // +kubebuilder:scaffold:imports ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to diff --git a/controllers/synapse/synapse/suite_test.go b/internal/controller/synapse/synapse/suite_test.go similarity index 94% rename from controllers/synapse/synapse/suite_test.go rename to internal/controller/synapse/synapse/suite_test.go index 0669eaf..8a4b820 100644 --- a/controllers/synapse/synapse/suite_test.go +++ b/internal/controller/synapse/synapse/suite_test.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - //+kubebuilder:scaffold:imports + // +kubebuilder:scaffold:imports ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to diff --git a/controllers/synapse/synapse/synapse_configmap.go b/internal/controller/synapse/synapse/synapse_configmap.go similarity index 95% rename from controllers/synapse/synapse/synapse_configmap.go rename to internal/controller/synapse/synapse/synapse_configmap.go index c7caca1..98f201c 100644 --- a/controllers/synapse/synapse/synapse_configmap.go +++ b/internal/controller/synapse/synapse/synapse_configmap.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,10 +31,10 @@ import ( "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -117,7 +117,7 @@ func (r *SynapseReconciler) configMapForSynapse(s *synapsev1alpha1.Synapse) (*co // synapse.Spec.Homeserver.ConfigMap.Name exists and extrats the server_name // and report_stats values. func (r *SynapseReconciler) parseInputSynapseConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -164,8 +164,12 @@ func (r *SynapseReconciler) parseInputSynapseConfigMap(ctx context.Context, req // ParseHomeserverConfigMap loads the ConfigMap, which name is determined by // Spec.Homeserver.ConfigMap.Name, run validation checks and fetch necesarry // value needed to configure the Synapse Deployment. -func (r *SynapseReconciler) ParseHomeserverConfigMap(ctx context.Context, synapse *synapsev1alpha1.Synapse, cm corev1.ConfigMap) error { - log := ctrllog.FromContext(ctx) +func (r *SynapseReconciler) ParseHomeserverConfigMap( + ctx context.Context, + synapse *synapsev1alpha1.Synapse, + cm corev1.ConfigMap, +) error { + log := logf.FromContext(ctx) // TODO: // - Ensure that key path is and log config file path are in /data @@ -220,7 +224,10 @@ func (r *SynapseReconciler) ParseHomeserverConfigMap(ctx context.Context, synaps // // It configures the 'database' section of homeserver.yaml to allow Synapse to // connect to the newly created PostgresCluster instance. -func (r *SynapseReconciler) updateSynapseConfigMapForPostgresCluster(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) updateSynapseConfigMapForPostgresCluster( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -319,7 +326,10 @@ func (r *SynapseReconciler) fetchDatabaseDataFromSynapseStatus(s synapsev1alpha1 return databaseDataMap, nil } -func (r *SynapseReconciler) updateSynapseConfigMapForBridges(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) updateSynapseConfigMapForBridges( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -345,7 +355,10 @@ func (r *SynapseReconciler) updateSynapseConfigMapForBridges(ctx context.Context // // It registers the heisenbridge as an application service in the // homeserver.yaml config file. -func (r *SynapseReconciler) updateSynapseConfigMapForHeisenbridge(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) updateSynapseConfigMapForHeisenbridge( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -389,7 +402,10 @@ func (r *SynapseReconciler) updateHomeserverWithHeisenbridgeInfos( // // It registers the mautrix-signal bridge as an application service in the // homeserver.yaml config file. -func (r *SynapseReconciler) updateSynapseConfigMapForMautrixSignal(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) updateSynapseConfigMapForMautrixSignal( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/controllers/synapse/synapse/synapse_controller.go b/internal/controller/synapse/synapse/synapse_controller.go similarity index 86% rename from controllers/synapse/synapse/synapse_controller.go rename to internal/controller/synapse/synapse/synapse_controller.go index 80fe4f1..0c89649 100644 --- a/controllers/synapse/synapse/synapse_controller.go +++ b/internal/controller/synapse/synapse/synapse_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,16 +23,16 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" pgov1beta1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -56,14 +56,14 @@ type HomeserverPgsqlDatabase struct { } } -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses/finalizers,verbs=update -//+kubebuilder:rbac:groups=core,resources=services;persistentvolumeclaims;configmaps;serviceaccounts,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=postgres-operator.crunchydata.com,resources=postgresclusters,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=security.openshift.io,resourceNames=anyuid,resources=securitycontextconstraints,verbs=use +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=synapse.opdev.io,resources=synapses/finalizers,verbs=update +// +kubebuilder:rbac:groups=core,resources=services;persistentvolumeclaims;configmaps;serviceaccounts,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=postgres-operator.crunchydata.com,resources=postgresclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=security.openshift.io,resourceNames=anyuid,resources=securitycontextconstraints,verbs=use func GetPostgresClusterResourceName(synapse synapsev1alpha1.Synapse) string { return strings.Join([]string{synapse.Name, "pgsql"}, "-") @@ -73,9 +73,9 @@ func GetPostgresClusterResourceName(synapse synapsev1alpha1.Synapse) string { // move the current state of the cluster closer to the desired state. // // For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.9.2/pkg/reconcile +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/reconcile func (r *SynapseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) var synapse synapsev1alpha1.Synapse // The Synapse object being reconciled if r, err := utils.GetResource(ctx, r.Client, req, &synapse); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -169,8 +169,11 @@ func labelsForSynapse(name string) map[string]string { return map[string]string{"app": "synapse", "synapse_cr": name} } -func (r *SynapseReconciler) setStatusHomeserverConfiguration(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) +func (r *SynapseReconciler) setStatusHomeserverConfiguration( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -199,8 +202,11 @@ func (r *SynapseReconciler) isPostgresOperatorInstalled(ctx context.Context) boo // // It parses the PostgresCluster Secret and updates the Synapse status with the // database connection information. -func (r *SynapseReconciler) updateSynapseStatusWithPostgreSQLInfos(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) +func (r *SynapseReconciler) updateSynapseStatusWithPostgreSQLInfos( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -278,7 +284,8 @@ func (r *SynapseReconciler) updateSynapseStatusDatabase( } s.Status.DatabaseConnectionInfo.ConnectionURL = string(host) + ":" + string(port) - // s.Status.DatabaseConnectionInfo.DatabaseName = string(databaseName) // See https://github.com/opdev/synapse-operator/issues/12 + // See https://github.com/opdev/synapse-operator/issues/12 + // s.Status.DatabaseConnectionInfo.DatabaseName = string(databaseName) s.Status.DatabaseConnectionInfo.DatabaseName = "synapse" s.Status.DatabaseConnectionInfo.User = string(user) s.Status.DatabaseConnectionInfo.Password = string(base64encode(string(password))) @@ -292,7 +299,7 @@ func (r *SynapseReconciler) updateSynapseStatusDatabase( // // It set the Synapse Status 'State' field to 'RUNNING'. func (r *SynapseReconciler) setSynapseStatusAsRunning(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -313,7 +320,7 @@ func (r *SynapseReconciler) setSynapseStatusAsRunning(ctx context.Context, req c } func (r *SynapseReconciler) updateSynapseStatusBridges(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -325,7 +332,9 @@ func (r *SynapseReconciler) updateSynapseStatusBridges(ctx context.Context, req s.Status.Bridges.MautrixSignal = synapsev1alpha1.SynapseStatusBridgesMautrixSignal{} hList := &synapsev1alpha1.HeisenbridgeList{} - r.Client.List(ctx, hList) + if err := r.Client.List(ctx, hList); err != nil { + return subreconciler.RequeueWithError(err) + } for _, h := range hList.Items { if h.Spec.Synapse.Name == s.Name && h.GetDeletionTimestamp() == nil { s.Status.Bridges.Heisenbridge.Enabled = true @@ -335,7 +344,9 @@ func (r *SynapseReconciler) updateSynapseStatusBridges(ctx context.Context, req } msList := &synapsev1alpha1.MautrixSignalList{} - r.Client.List(ctx, msList) + if err := r.Client.List(ctx, msList); err != nil { + return subreconciler.RequeueWithError(err) + } for _, ms := range msList.Items { if ms.Spec.Synapse.Name == s.Name && ms.GetDeletionTimestamp() == nil { s.Status.Bridges.MautrixSignal.Enabled = true @@ -360,5 +371,6 @@ func (r *SynapseReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&corev1.Service{}). Owns(&appsv1.Deployment{}). Owns(&corev1.PersistentVolumeClaim{}). + Named("synapse-synapse"). Complete(r) } diff --git a/controllers/synapse/synapse/synapse_controller_test.go b/internal/controller/synapse/synapse/synapse_controller_test.go similarity index 93% rename from controllers/synapse/synapse/synapse_controller_test.go rename to internal/controller/synapse/synapse/synapse_controller_test.go index 7d46e9a..f12b7f6 100644 --- a/controllers/synapse/synapse/synapse_controller_test.go +++ b/internal/controller/synapse/synapse/synapse_controller_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package synapse import ( @@ -6,6 +22,7 @@ import ( "fmt" "io" "net/http" + "os" "path/filepath" "runtime" "strconv" @@ -13,7 +30,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -32,7 +49,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/metrics/server" pgov1beta1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -63,6 +80,11 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( // Common function to start envTest var startenvTest = func() { + // Retrieve the first found binary directory to allow running tests from IDEs + if getFirstFoundEnvTestBinaryDir() != "" { + testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() + } + cfg, err := testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) @@ -70,7 +92,7 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( Expect(synapsev1alpha1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) Expect(pgov1beta1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) - //+kubebuilder:scaffold:scheme + // +kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) @@ -112,8 +134,8 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( By("Getting latest version of the PostgresCluster CRD") postgresOperatorVersion := "5.2.0" - postgresClusterURL := "https://raw.githubusercontent.com/redhat-openshift-ecosystem/community-operators-prod/main/operators/postgresql/" + - postgresOperatorVersion + + postgresClusterURL := "https://raw.githubusercontent.com/redhat-openshift-ecosystem/" + + "community-operators-prod/main/operators/postgresql/" + postgresOperatorVersion + "/manifests/postgresclusters.postgres-operator.crunchydata.com.crd.yaml" resp, err := http.Get(postgresClusterURL) @@ -124,7 +146,7 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( // successfully Unmarshal the CRD Document into a // CustomResourceDefinition object, it is necessary to first transform the // YAML document into a intermediate JSON document. - defer resp.Body.Close() + defer resp.Body.Close() //nolint:errcheck yamlBody, err := io.ReadAll(resp.Body) Expect(err).ShouldNot(HaveOccurred()) @@ -146,13 +168,13 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_heisenbridges.yaml"), - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_mautrixsignals.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_heisenbridges.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_mautrixsignals.yaml"), }, CRDs: []*v1.CustomResourceDefinition{&PostgresClusterCRD}, ErrorIfCRDPathMissing: true, - BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", + BinaryAssetsDirectory: filepath.Join("..", "..", "..", "bin", "k8s", fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), AttachControlPlaneOutput: true, } @@ -656,7 +678,8 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( g.Expect(synapse.Status.DatabaseConnectionInfo.ConnectionURL).Should(Equal("hostname.postgresql.url:5432")) g.Expect(synapse.Status.DatabaseConnectionInfo.DatabaseName).Should(Equal("synapse")) g.Expect(synapse.Status.DatabaseConnectionInfo.User).Should(Equal("synapse")) - g.Expect(synapse.Status.DatabaseConnectionInfo.Password).Should(Equal(string(base64encode("VerySecureSyn@psePassword!")))) + encodedPassword := string(base64encode("VerySecureSyn@psePassword!")) + g.Expect(synapse.Status.DatabaseConnectionInfo.Password).Should(Equal(encodedPassword)) g.Expect(synapse.Status.DatabaseConnectionInfo.State).Should(Equal("READY")) }, timeout, interval).Should(Succeed()) }) @@ -1064,10 +1087,10 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), + filepath.Join("..", "..", "..", "..", "bundle", "manifests", "synapse.opdev.io_synapses.yaml"), }, ErrorIfCRDPathMissing: true, - BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", + BinaryAssetsDirectory: filepath.Join("..", "..", "..", "bin", "k8s", fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), AttachControlPlaneOutput: true, } @@ -1173,3 +1196,26 @@ var _ = Describe("Integration tests for the Synapse controller", Ordered, Label( }) }) }) + +// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. +// ENVTEST-based tests depend on specific binaries, usually located in paths set by +// controller-runtime. When running tests directly (e.g., via an IDE) without using +// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. +// +// This function streamlines the process by finding the required binaries, similar to +// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are +// properly set up, run 'make setup-envtest' beforehand. +func getFirstFoundEnvTestBinaryDir() string { + basePath := filepath.Join("..", "..", "..", "..", "bin", "k8s") + entries, err := os.ReadDir(basePath) + if err != nil { + logf.Log.Error(err, "Failed to read directory", "path", basePath) + return "" + } + for _, entry := range entries { + if entry.IsDir() { + return filepath.Join(basePath, entry.Name()) + } + } + return "" +} diff --git a/controllers/synapse/synapse/synapse_deployment.go b/internal/controller/synapse/synapse/synapse_deployment.go similarity index 93% rename from controllers/synapse/synapse/synapse_deployment.go rename to internal/controller/synapse/synapse/synapse_deployment.go index 6828430..406f86b 100644 --- a/controllers/synapse/synapse/synapse_deployment.go +++ b/internal/controller/synapse/synapse/synapse_deployment.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -69,7 +69,10 @@ func (r *SynapseReconciler) deploymentForSynapse(s *synapsev1alpha1.Synapse) (*a Labels: labelsForSynapse(s.Name), } - dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment](&extraValues, "synapse_deployment") + dep, err := templates.ResourceFromTemplate[deploymentExtraValues, appsv1.Deployment]( + &extraValues, + "synapse_deployment", + ) if err != nil { return nil, fmt.Errorf("could not get template: %v", err) } diff --git a/controllers/synapse/synapse/synapse_postgrescluster.go b/internal/controller/synapse/synapse/synapse_postgrescluster.go similarity index 90% rename from controllers/synapse/synapse/synapse_postgrescluster.go rename to internal/controller/synapse/synapse/synapse_postgrescluster.go index 71910dd..eb3b843 100644 --- a/controllers/synapse/synapse/synapse_postgrescluster.go +++ b/internal/controller/synapse/synapse/synapse_postgrescluster.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,11 +27,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" + logf "sigs.k8s.io/controller-runtime/pkg/log" pgov1beta1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" ) @@ -42,7 +42,7 @@ import ( // It reconciles the PostgresCluster CR to its desired state, and requeues // until the PostgreSQL cluster is up. func (r *SynapseReconciler) reconcilePostgresClusterCR(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { - log := ctrllog.FromContext(ctx) + log := logf.FromContext(ctx) s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { @@ -95,7 +95,10 @@ func (r *SynapseReconciler) reconcilePostgresClusterCR(ctx context.Context, req } // postgresClusterForSynapse returns a PostgresCluster object -func (r *SynapseReconciler) postgresClusterForSynapse(s *synapsev1alpha1.Synapse, objectMeta metav1.ObjectMeta) (*pgov1beta1.PostgresCluster, error) { +func (r *SynapseReconciler) postgresClusterForSynapse( + s *synapsev1alpha1.Synapse, + objectMeta metav1.ObjectMeta, +) (*pgov1beta1.PostgresCluster, error) { postgresCluster := &pgov1beta1.PostgresCluster{ ObjectMeta: objectMeta, Spec: pgov1beta1.PostgresClusterSpec{ @@ -183,7 +186,10 @@ func (r *SynapseReconciler) isPostgresClusterReady(p pgov1beta1.PostgresCluster) // to be called in the main reconciliation loop. // // It reconciles the PostgresCluster ConfigMap to its desired state. -func (r *SynapseReconciler) reconcilePostgresClusterConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) reconcilePostgresClusterConfigMap( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err @@ -214,10 +220,14 @@ func (r *SynapseReconciler) reconcilePostgresClusterConfigMap(ctx context.Contex } // configMapForPostgresCluster returns a ConfigMap object -func (r *SynapseReconciler) configMapForPostgresCluster(s *synapsev1alpha1.Synapse, objectMeta metav1.ObjectMeta) (*corev1.ConfigMap, error) { +func (r *SynapseReconciler) configMapForPostgresCluster( + s *synapsev1alpha1.Synapse, + objectMeta metav1.ObjectMeta, +) (*corev1.ConfigMap, error) { + createQuery := "CREATE DATABASE synapse LOCALE 'C' ENCODING 'UTF-8' TEMPLATE template0;" configMap := &corev1.ConfigMap{ ObjectMeta: objectMeta, - Data: map[string]string{"createdb.sql": "CREATE DATABASE synapse LOCALE 'C' ENCODING 'UTF-8' TEMPLATE template0;"}, + Data: map[string]string{"createdb.sql": createQuery}, } if err := ctrl.SetControllerReference(s, configMap, r.Scheme); err != nil { diff --git a/controllers/synapse/synapse/synapse_pvc.go b/internal/controller/synapse/synapse/synapse_pvc.go similarity index 90% rename from controllers/synapse/synapse/synapse_pvc.go rename to internal/controller/synapse/synapse/synapse_pvc.go index 27ca360..aef4def 100644 --- a/controllers/synapse/synapse/synapse_pvc.go +++ b/internal/controller/synapse/synapse/synapse_pvc.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -58,7 +58,9 @@ func (r *SynapseReconciler) reconcileSynapsePVC(ctx context.Context, req ctrl.Re } // persistentVolumeClaimForSynapse returns a synapse PVC object -func (r *SynapseReconciler) persistentVolumeClaimForSynapse(s *synapsev1alpha1.Synapse) (*corev1.PersistentVolumeClaim, error) { +func (r *SynapseReconciler) persistentVolumeClaimForSynapse( + s *synapsev1alpha1.Synapse, +) (*corev1.PersistentVolumeClaim, error) { pvc, err := templates.ResourceFromTemplate[synapsev1alpha1.Synapse, corev1.PersistentVolumeClaim](s, "pvc") if err != nil { return nil, fmt.Errorf("could not get template: %v", err) diff --git a/controllers/synapse/synapse/synapse_service.go b/internal/controller/synapse/synapse/synapse_service.go similarity index 96% rename from controllers/synapse/synapse/synapse_service.go rename to internal/controller/synapse/synapse/synapse_service.go index 082c2af..edfbfa5 100644 --- a/controllers/synapse/synapse/synapse_service.go +++ b/internal/controller/synapse/synapse/synapse_service.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" diff --git a/controllers/synapse/synapse/synapse_serviceaccount.go b/internal/controller/synapse/synapse/synapse_serviceaccount.go similarity index 94% rename from controllers/synapse/synapse/synapse_serviceaccount.go rename to internal/controller/synapse/synapse/synapse_serviceaccount.go index 7eba991..6d1252f 100644 --- a/controllers/synapse/synapse/synapse_serviceaccount.go +++ b/internal/controller/synapse/synapse/synapse_serviceaccount.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2025. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" subreconciler "github.com/opdev/subreconciler" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/reconcile" "github.com/opdev/synapse-operator/helpers/utils" "github.com/opdev/synapse-operator/internal/templates" @@ -35,7 +35,10 @@ import ( // be called in the main reconciliation loop. // // It reconciles the ServiceAccount for synapse to its desired state. -func (r *SynapseReconciler) reconcileSynapseServiceAccount(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { +func (r *SynapseReconciler) reconcileSynapseServiceAccount( + ctx context.Context, + req ctrl.Request, +) (*ctrl.Result, error) { s := &synapsev1alpha1.Synapse{} if r, err := utils.GetResource(ctx, r.Client, req, s); subreconciler.ShouldHaltOrRequeue(r, err) { return r, err diff --git a/controllers/synapse/synapse/synapse_test.go b/internal/controller/synapse/synapse/synapse_test.go similarity index 92% rename from controllers/synapse/synapse/synapse_test.go rename to internal/controller/synapse/synapse/synapse_test.go index f5472ea..49549ff 100644 --- a/controllers/synapse/synapse/synapse_test.go +++ b/internal/controller/synapse/synapse/synapse_test.go @@ -1,5 +1,5 @@ // -//This file contains unit tests for the Synapse package +// This file contains unit tests for the Synapse package // package synapse @@ -9,10 +9,10 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" pgov1beta1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" - synapsev1alpha1 "github.com/opdev/synapse-operator/apis/synapse/v1alpha1" + synapsev1alpha1 "github.com/opdev/synapse-operator/api/synapse/v1alpha1" "github.com/opdev/synapse-operator/helpers/utils" corev1 "k8s.io/api/core/v1" ) @@ -273,7 +273,7 @@ var _ = Describe("Unit tests for Synapse package", Label("unit"), func() { Expect(s.Status.DatabaseConnectionInfo.DatabaseName).Should(Equal("synapse")) Expect(s.Status.DatabaseConnectionInfo.User).Should(Equal("synapse")) Expect(s.Status.DatabaseConnectionInfo.Password).Should(Equal(string(base64encode("iOycqrF;EbyqUo7Z2oma}.), + // )) + }) +}) + +// serviceAccountToken returns a token for the specified service account in the given namespace. +// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request +// and parsing the resulting token from the API response. +func serviceAccountToken() (string, error) { + const tokenRequestRawString = `{ + "apiVersion": "authentication.k8s.io/v1", + "kind": "TokenRequest" + }` + + // Temporary file to store the token request + secretName := fmt.Sprintf("%s-token-request", serviceAccountName) + tokenRequestFile := filepath.Join("/tmp", secretName) + err := os.WriteFile(tokenRequestFile, []byte(tokenRequestRawString), os.FileMode(0o644)) + if err != nil { + return "", err + } + + var out string + verifyTokenCreation := func(g Gomega) { + // Execute kubectl command to create the token + cmd := exec.Command("kubectl", "create", "--raw", fmt.Sprintf( + "/api/v1/namespaces/%s/serviceaccounts/%s/token", + namespace, + serviceAccountName, + ), "-f", tokenRequestFile) + + output, err := cmd.CombinedOutput() + g.Expect(err).NotTo(HaveOccurred()) + + // Parse the JSON output to extract the token + var token tokenRequest + err = json.Unmarshal(output, &token) + g.Expect(err).NotTo(HaveOccurred()) + + out = token.Status.Token + } + Eventually(verifyTokenCreation).Should(Succeed()) + + return out, err +} + +// getMetricsOutput retrieves and returns the logs from the curl pod used to access the metrics endpoint. +func getMetricsOutput() string { + By("getting the curl-metrics logs") + cmd := exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + metricsOutput, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + Expect(metricsOutput).To(ContainSubstring("< HTTP/1.1 200 OK")) + return metricsOutput +} + +// tokenRequest is a simplified representation of the Kubernetes TokenRequest API response, +// containing only the token field that we need to extract. +type tokenRequest struct { + Status struct { + Token string `json:"token"` + } `json:"status"` +} diff --git a/test/utils/utils.go b/test/utils/utils.go new file mode 100644 index 0000000..04a5141 --- /dev/null +++ b/test/utils/utils.go @@ -0,0 +1,251 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "strings" + + . "github.com/onsi/ginkgo/v2" //nolint:golint,revive +) + +const ( + prometheusOperatorVersion = "v0.77.1" + prometheusOperatorURL = "https://github.com/prometheus-operator/prometheus-operator/" + + "releases/download/%s/bundle.yaml" + + certmanagerVersion = "v1.16.3" + certmanagerURLTmpl = "https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml" +) + +func warnError(err error) { + _, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) +} + +// Run executes the provided command within this context +func Run(cmd *exec.Cmd) (string, error) { + dir, _ := GetProjectDir() + cmd.Dir = dir + + if err := os.Chdir(cmd.Dir); err != nil { + _, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %s\n", err) + } + + cmd.Env = append(os.Environ(), "GO111MODULE=on") + command := strings.Join(cmd.Args, " ") + _, _ = fmt.Fprintf(GinkgoWriter, "running: %s\n", command) + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), fmt.Errorf("%s failed with error: (%v) %s", command, err, string(output)) + } + + return string(output), nil +} + +// InstallPrometheusOperator installs the prometheus Operator to be used to export the enabled metrics. +func InstallPrometheusOperator() error { + url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) + cmd := exec.Command("kubectl", "create", "-f", url) + _, err := Run(cmd) + return err +} + +// UninstallPrometheusOperator uninstalls the prometheus +func UninstallPrometheusOperator() { + url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } +} + +// IsPrometheusCRDsInstalled checks if any Prometheus CRDs are installed +// by verifying the existence of key CRDs related to Prometheus. +func IsPrometheusCRDsInstalled() bool { + // List of common Prometheus CRDs + prometheusCRDs := []string{ + "prometheuses.monitoring.coreos.com", + "prometheusrules.monitoring.coreos.com", + "prometheusagents.monitoring.coreos.com", + } + + cmd := exec.Command("kubectl", "get", "crds", "-o", "custom-columns=NAME:.metadata.name") + output, err := Run(cmd) + if err != nil { + return false + } + crdList := GetNonEmptyLines(output) + for _, crd := range prometheusCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// UninstallCertManager uninstalls the cert manager +func UninstallCertManager() { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } +} + +// InstallCertManager installs the cert manager bundle. +func InstallCertManager() error { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "apply", "-f", url) + if _, err := Run(cmd); err != nil { + return err + } + // Wait for cert-manager-webhook to be ready, which can take time if cert-manager + // was re-installed after uninstalling on a cluster. + cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook", + "--for", "condition=Available", + "--namespace", "cert-manager", + "--timeout", "5m", + ) + + _, err := Run(cmd) + return err +} + +// IsCertManagerCRDsInstalled checks if any Cert Manager CRDs are installed +// by verifying the existence of key CRDs related to Cert Manager. +func IsCertManagerCRDsInstalled() bool { + // List of common Cert Manager CRDs + certManagerCRDs := []string{ + "certificates.cert-manager.io", + "issuers.cert-manager.io", + "clusterissuers.cert-manager.io", + "certificaterequests.cert-manager.io", + "orders.acme.cert-manager.io", + "challenges.acme.cert-manager.io", + } + + // Execute the kubectl command to get all CRDs + cmd := exec.Command("kubectl", "get", "crds") + output, err := Run(cmd) + if err != nil { + return false + } + + // Check if any of the Cert Manager CRDs are present + crdList := GetNonEmptyLines(output) + for _, crd := range certManagerCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// LoadImageToKindClusterWithName loads a local docker image to the kind cluster +func LoadImageToKindClusterWithName(name string) error { + cluster := "kind" + if v, ok := os.LookupEnv("KIND_CLUSTER"); ok { + cluster = v + } + kindOptions := []string{"load", "docker-image", name, "--name", cluster} + cmd := exec.Command("kind", kindOptions...) + _, err := Run(cmd) + return err +} + +// GetNonEmptyLines converts given command output string into individual objects +// according to line breakers, and ignores the empty elements in it. +func GetNonEmptyLines(output string) []string { + var res []string + elements := strings.Split(output, "\n") + for _, element := range elements { + if element != "" { + res = append(res, element) + } + } + + return res +} + +// GetProjectDir will return the directory where the project is +func GetProjectDir() (string, error) { + wd, err := os.Getwd() + if err != nil { + return wd, err + } + wd = strings.Replace(wd, "/test/e2e", "", -1) + return wd, nil +} + +// UncommentCode searches for target in the file and remove the comment prefix +// of the target content. The target content may span multiple lines. +func UncommentCode(filename, target, prefix string) error { + // false positive + // nolint:gosec + content, err := os.ReadFile(filename) + if err != nil { + return err + } + strContent := string(content) + + idx := strings.Index(strContent, target) + if idx < 0 { + return fmt.Errorf("unable to find the code %s to be uncomment", target) + } + + out := new(bytes.Buffer) + _, err = out.Write(content[:idx]) + if err != nil { + return err + } + + scanner := bufio.NewScanner(bytes.NewBufferString(target)) + if !scanner.Scan() { + return nil + } + for { + _, err := out.WriteString(strings.TrimPrefix(scanner.Text(), prefix)) + if err != nil { + return err + } + // Avoid writing a newline in case the previous line was the last in target. + if !scanner.Scan() { + break + } + if _, err := out.WriteString("\n"); err != nil { + return err + } + } + + _, err = out.Write(content[idx+len(target):]) + if err != nil { + return err + } + // false positive + // nolint:gosec + return os.WriteFile(filename, out.Bytes(), 0644) +}