From 1510f54d2d1b545263bb0756aad87de5aff4467b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiz=20Poli=C4=87?= <32913827+ramizpolic@users.noreply.github.com> Date: Tue, 11 Jul 2023 16:10:52 +0200 Subject: [PATCH] feat: repository standardisation and overhaul (#101) --- .github/workflows/ci.yaml | 4 +- Dockerfile | 2 +- Makefile | 358 +++++++++++------- PROJECT | 21 + cmd/{manager => }/main.go | 90 +++-- deploy/charts/vault-operator/crds/crd.yaml | 6 +- .../bases/vault.banzaicloud.com_vaults.yaml} | 6 +- deploy/crd/kustomization.yaml | 21 + deploy/crd/kustomizeconfig.yaml | 19 + deploy/crd/patches/cainjection_in_vaults.yaml | 7 + deploy/crd/patches/webhook_in_vaults.yaml | 16 + deploy/default/kustomization.yaml | 143 +++++++ deploy/default/manager_auth_proxy_patch.yaml | 39 ++ deploy/default/manager_config_patch.yaml | 10 + deploy/default/rbac.yaml | 49 --- deploy/dev/multi-dc/aws/multi-dc-raft.sh | 3 +- deploy/dev/multi-dc/test/multi-dc-raft.sh | 3 +- deploy/manager/kustomization.yaml | 8 + deploy/manager/manager.yaml | 102 +++++ deploy/prometheus/kustomization.yaml | 2 + deploy/prometheus/monitor.yaml | 26 ++ .../rbac/auth_proxy_client_clusterrole.yaml | 16 + deploy/rbac/auth_proxy_role.yaml | 24 ++ deploy/rbac/auth_proxy_role_binding.yaml | 19 + deploy/rbac/auth_proxy_service.yaml | 21 + deploy/rbac/cluster_role_binding.yaml | 22 ++ deploy/rbac/kustomization.yaml | 19 + deploy/rbac/leader_election_role.yaml | 44 +++ deploy/rbac/leader_election_role_binding.yaml | 19 + deploy/rbac/role.yaml | 21 + deploy/rbac/role_binding.yaml | 19 + deploy/rbac/service_account.yaml | 12 + deploy/rbac/vault_editor_role.yaml | 31 ++ deploy/rbac/vault_viewer_role.yaml | 27 ++ go.mod | 9 +- go.sum | 33 +- hack/{scripts => }/custom-boilerplate.go.txt | 0 hack/{scripts => }/update-codegen.sh | 30 +- pkg/apis/addtoscheme_monitor_v1.go | 5 +- pkg/apis/addtoscheme_vault_v1alpha1.go | 1 - pkg/apis/vault/v1alpha1/doc.go | 18 - pkg/apis/vault/v1alpha1/embedded_v1.go | 36 +- .../{register.go => groupversion_info.go} | 32 +- pkg/apis/vault/v1alpha1/vault_types.go | 319 ++++++++-------- .../vault/v1alpha1/zz_generated.deepcopy.go | 56 ++- pkg/client/clientset/versioned/clientset.go | 41 +- pkg/client/clientset/versioned/doc.go | 18 - .../versioned/fake/clientset_generated.go | 5 +- .../clientset/versioned/fake/register.go | 14 +- .../clientset/versioned/scheme/register.go | 14 +- .../typed/vault/v1alpha1/fake/fake_vault.go | 7 +- .../typed/vault/v1alpha1/vault_client.go | 22 +- .../informers/externalversions/factory.go | 79 +++- .../informers/externalversions/generic.go | 2 +- .../{add_vault.go => addtomanager_vault.go} | 0 pkg/controller/vault/suite_test.go | 77 ++++ pkg/controller/vault/vault_controller.go | 24 +- test/acceptance_test.go | 280 ++++++-------- 58 files changed, 1644 insertions(+), 707 deletions(-) create mode 100644 PROJECT rename cmd/{manager => }/main.go (57%) rename deploy/{default/crd.yaml => crd/bases/vault.banzaicloud.com_vaults.yaml} (99%) create mode 100644 deploy/crd/kustomization.yaml create mode 100644 deploy/crd/kustomizeconfig.yaml create mode 100644 deploy/crd/patches/cainjection_in_vaults.yaml create mode 100644 deploy/crd/patches/webhook_in_vaults.yaml create mode 100644 deploy/default/kustomization.yaml create mode 100644 deploy/default/manager_auth_proxy_patch.yaml create mode 100644 deploy/default/manager_config_patch.yaml delete mode 100644 deploy/default/rbac.yaml create mode 100644 deploy/manager/kustomization.yaml create mode 100644 deploy/manager/manager.yaml create mode 100644 deploy/prometheus/kustomization.yaml create mode 100644 deploy/prometheus/monitor.yaml create mode 100644 deploy/rbac/auth_proxy_client_clusterrole.yaml create mode 100644 deploy/rbac/auth_proxy_role.yaml create mode 100644 deploy/rbac/auth_proxy_role_binding.yaml create mode 100644 deploy/rbac/auth_proxy_service.yaml create mode 100644 deploy/rbac/cluster_role_binding.yaml create mode 100644 deploy/rbac/kustomization.yaml create mode 100644 deploy/rbac/leader_election_role.yaml create mode 100644 deploy/rbac/leader_election_role_binding.yaml create mode 100644 deploy/rbac/role.yaml create mode 100644 deploy/rbac/role_binding.yaml create mode 100644 deploy/rbac/service_account.yaml create mode 100644 deploy/rbac/vault_editor_role.yaml create mode 100644 deploy/rbac/vault_viewer_role.yaml rename hack/{scripts => }/custom-boilerplate.go.txt (100%) rename hack/{scripts => }/update-codegen.sh (61%) delete mode 100644 pkg/apis/vault/v1alpha1/doc.go rename pkg/apis/vault/v1alpha1/{register.go => groupversion_info.go} (64%) delete mode 100644 pkg/client/clientset/versioned/doc.go rename pkg/controller/{add_vault.go => addtomanager_vault.go} (100%) create mode 100644 pkg/controller/vault/suite_test.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c46c303..bbd0f1c8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -190,8 +190,8 @@ jobs: - name: Acceptance test run: nix develop --impure .#ci -c make test-acceptance env: - VAULT_VERSION: ${{ matrix.vault_version }} - OPERATOR_VERSION: ${{ needs.artifacts.outputs.container-image-tag }} + TEST_VAULT_VERSION: ${{ matrix.vault_version }} + TEST_OPERATOR_VERSION: ${{ needs.artifacts.outputs.container-image-tag }} HELM_CHART: "${{ github.workspace }}/${{ needs.artifacts.outputs.helm-chart-package }}" multi-cluster-acceptance-test: diff --git a/Dockerfile b/Dockerfile index f6df2763..dc600724 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ RUN go mod download COPY . . -RUN go build -o /usr/local/bin/vault-operator ./cmd/manager/ +RUN go build -o /usr/local/bin/vault-operator ./cmd/ RUN xx-verify /usr/local/bin/vault-operator diff --git a/Makefile b/Makefile index 5e341257..49f75a57 100644 --- a/Makefile +++ b/Makefile @@ -1,157 +1,259 @@ # A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html -export PATH := $(abspath bin/):${PATH} +# Target image name +IMG ?= ghcr.io/bank-vaults/vault-operator:dev -CONTAINER_IMAGE_REF = ghcr.io/bank-vaults/vault-operator:dev +# Default test data +TEST_K8S_VERSION ?= 1.27.1 +TEST_VAULT_VERSION ?= 1.13.3 +TEST_BANK_VAULTS_VERSION ?= 1.19.0 +TEST_OPERATOR_VERSION ?= $(lastword $(subst :, ,$(IMG))) +TEST_KIND_CLUSTER ?= vault-operator -# Dependency versions -GOLANGCI_VERSION = 1.53.3 -LICENSEI_VERSION = 0.8.0 -KIND_VERSION = 0.20.0 -KURUN_VERSION = 0.7.0 -CODE_GENERATOR_VERSION = 0.27.1 -CONTROLLER_GEN_VERSION = 0.12.0 -HELM_DOCS_VERSION = 1.11.0 +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec -.PHONY: up -up: ## Start development environment - kind create cluster +##@ General -.PHONY: stop -stop: ## Stop development environment - # TODO: consider using k3d instead - kind delete cluster +# Targets commented with ## will be visible in "make help" info. +# Comments marked with ##@ will be used as categories for a group of targets. -.PHONY: down -down: ## Destroy development environment - kind delete cluster +.PHONY: help +default: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) -.PHONY: build -build: ## Build binary - @mkdir -p build - go build -race -o build/manager ./cmd/manager +##@ Checks -.PHONY: run -run: ## Run the operator locally talking to a Kubernetes cluster - kubectl replace -f deploy/default/crd.yaml || kubectl create -f deploy/default/crd.yaml - kubectl apply -f deploy/default/rbac.yaml - OPERATOR_NAME=vault-dev go run cmd/manager/main.go -verbose +.PHONY: fmt +fmt: ## Run go fmt against code + $(GOLANGCI_LINT) run --fix -.PHONY: clean -clean: ## Clean operator resources from a Kubernetes cluster - kubectl delete -f deploy/default/crd.yaml - kubectl delete -f deploy/default/rbac.yaml +.PHONY: lint-go +lint-go: # Run golang lint check + $(GOLANGCI_LINT) run $(if ${CI},--out-format github-actions,) -.PHONY: artifacts -artifacts: container-image helm-chart -artifacts: ## Build artifacts +.PHONY: lint-helm +lint-helm: # Run helm lint check + $(HELM) lint deploy/charts/vault-operator -.PHONY: container-image -container-image: ## Build container image - docker build -t ${CONTAINER_IMAGE_REF} . +.PHONY: lint-docker +lint-docker: # Run Dockerfile lint check + $(HADOLINT) Dockerfile -.PHONY: helm-chart -helm-chart: ## Build Helm chart - @mkdir -p build - helm package -d build/ deploy/charts/vault-operator +.PHONY: lint-yaml +lint-yaml: # Run yaml lint check + $(YAMLLINT) $(if ${CI},-f github,) --no-warnings . -.PHONY: check -check: test lint ## Run checks (tests and linters) +.PHONY: lint +lint: lint-go lint-helm lint-docker lint-yaml +lint: ## Run lint checks .PHONY: test test: ## Run tests - go test -race -v ./... + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(TEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \ + go test -race -v ./... -coverprofile cover.out .PHONY: test-acceptance -test-acceptance: ## Run acceptance tests - go test -race -v -timeout 900s -tags kubeall ./test +test-acceptance: ## Run acceptance tests. If running on a local kind cluster, run "make import-test" before this + VAULT_VERSION=$(TEST_VAULT_VERSION) BANK_VAULTS_VERSION=$(TEST_BANK_VAULTS_VERSION) OPERATOR_VERSION=$(TEST_OPERATOR_VERSION) \ + go test -race -v -timeout 900s -tags kubeall ./test -.PHONY: lint -lint: lint-go lint-helm lint-docker lint-yaml -lint: ## Run linters +.PHONY: license-check +license-check: ## Run license check + $(LICENSEI) check + $(LICENSEI) header -.PHONY: lint-go -lint-go: - golangci-lint run $(if ${CI},--out-format github-actions,) +.PHONY: check +check: lint test ## Run lint checks and tests -.PHONY: lint-helm -lint-helm: - helm lint deploy/charts/vault-operator +##@ Development -.PHONY: lint-docker -lint-docker: - hadolint Dockerfile +.PHONY: run +run: generate deploy ## Run manager from your host + OPERATOR_NAME=vault-dev go run cmd/main.go -verbose -.PHONY: lint-yaml -lint-yaml: - yamllint $(if ${CI},-f github,) --no-warnings . +.PHONY: up +up: ## Start kind development environment + $(KIND) create cluster --name $(TEST_KIND_CLUSTER) -.PHONY: fmt -fmt: ## Format code - golangci-lint run --fix +.PHONY: down +down: ## Destroy kind development environment + $(KIND) delete cluster --name $(TEST_KIND_CLUSTER) -.PHONY: license-check -license-check: ## Run license check - licensei check - licensei header +.PHONY: import-image +import-image: docker-build ## Import manager image to kind image repository + $(KIND) load docker-image ${IMG} --name $(TEST_KIND_CLUSTER) + +.PHONY: import-test +import-test: import-image ## Import images required for tests to kind image repository + docker pull ghcr.io/banzaicloud/bank-vaults:$(TEST_BANK_VAULTS_VERSION) + docker pull vault:$(TEST_VAULT_VERSION) + + $(KIND) load docker-image ghcr.io/banzaicloud/bank-vaults:$(TEST_BANK_VAULTS_VERSION) --name $(TEST_KIND_CLUSTER) + $(KIND) load docker-image vault:$(TEST_VAULT_VERSION) --name $(TEST_KIND_CLUSTER) + +##@ Build + +.PHONY: build +build: ## Build manager binary + @mkdir -p build + go build -race -o build/manager ./cmd + +# 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. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: ## Build docker image + docker build -t ${IMG} . + +# PLATFORMS defines the target platforms for the manager image be build 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=> then the export will fail) +# To properly provided solutions that supports more than one platform you should use this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build docker image 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 + rm Dockerfile.cross + +.PHONY: helm-chart +helm-chart: ## Build helm chart + @mkdir -p build + $(HELM) package -d build/ deploy/charts/vault-operator + +.PHONY: artifacts +artifacts: docker-build helm-chart +artifacts: ## Build docker image and helm chart + + +##@ Autogeneration + +.PHONY: gen-manifests +gen-manifests: ## Generate webhook, RBAC, and CRD resources + $(CONTROLLER_GEN) rbac:roleName=vault crd:maxDescLen=0 webhook paths="./..." \ + output:rbac:dir=deploy/rbac \ + output:crd:dir=deploy/crd/bases \ + output:webhook:dir=deploy/webhook + cp deploy/crd/bases/vault.banzaicloud.com_vaults.yaml deploy/charts/vault-operator/crds/crd.yaml + +.PHONY: gen-code +gen-code: ## Generate deepcopy, client, lister, and informer objects + $(CONTROLLER_GEN) object:headerFile="hack/custom-boilerplate.go.txt" paths="./..." + ./hack/update-codegen.sh v${CODE_GENERATOR_VERSION} + +.PHONY: gen-helm-docs +gen-helm-docs: ## Generate Helm chart documentation + $(HELM_DOCS) -s file -c deploy/charts/ -t README.md.gotmpl .PHONY: generate -generate: generate-code generate-crds generate-helm-docs -generate: ## Run generation jobs - -.PHONY: generate-code -generate-code: ## Regenerate clientset, deepcopy funcs, listers and informers - ./hack/scripts/update-codegen.sh v${CODE_GENERATOR_VERSION} - -.PHONY: generate-crds -generate-crds: ## Regenerate CRDs in the Helm chart and examples - controller-gen crd:maxDescLen=0 paths=./pkg/... output:crd:artifacts:config=./deploy/default - cp deploy/default/vault.banzaicloud.com_vaults.yaml deploy/charts/vault-operator/crds/crd.yaml - cp deploy/default/vault.banzaicloud.com_vaults.yaml deploy/default/crd.yaml - rm deploy/default/vault.banzaicloud.com_vaults.yaml - -.PHONY: generate-helm-docs -generate-helm-docs: - helm-docs -s file -c deploy/charts/ -t README.md.gotmpl - -deps: bin/golangci-lint bin/licensei bin/kind bin/kurun bin/controller-gen bin/helm-docs -deps: ## Install dependencies - -bin/golangci-lint: - @mkdir -p bin - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- v${GOLANGCI_VERSION} - -bin/licensei: - @mkdir -p bin - curl -sfL https://raw.githubusercontent.com/goph/licensei/master/install.sh | bash -s -- v${LICENSEI_VERSION} - -bin/kind: - @mkdir -p bin - curl -Lo bin/kind https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | sed -e "s/aarch64/arm64/; s/x86_64/amd64/") - @chmod +x bin/kind - -bin/kurun: - @mkdir -p bin - curl -Lo bin/kurun https://github.com/banzaicloud/kurun/releases/download/${KURUN_VERSION}/kurun-$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | sed -e "s/aarch64/arm64/; s/x86_64/amd64/") - @chmod +x bin/kurun - -bin/controller-gen: - @mkdir -p bin - set -ex ;\ - CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ - cd $$CONTROLLER_GEN_TMP_DIR ;\ - go mod init tmp ;\ - GOBIN=$(PWD)/bin/controller-gen-${CONTROLLER_GEN_VERSION}-bin/ go install sigs.k8s.io/controller-tools/cmd/controller-gen@v${CONTROLLER_GEN_VERSION} ;\ - mv $(PWD)/bin/controller-gen-${CONTROLLER_GEN_VERSION}-bin/controller-gen $(PWD)/bin/controller-gen ;\ - rm -rf $(PWD)/bin/controller-gen-${CONTROLLER_GEN_VERSION}-bin ;\ - rm -rf $$CONTROLLER_GEN_TMP_DIR - -bin/helm-docs: - @mkdir -p bin - curl -L https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS_VERSION}/helm-docs_${HELM_DOCS_VERSION}_$(shell uname)_x86_64.tar.gz | tar -zOxf - helm-docs > ./bin/helm-docs - @chmod +x bin/helm-docs +generate: gen-manifests gen-code gen-helm-docs +generate: ## Generate manifests, code, and docs resources -.PHONY: help -.DEFAULT_GOAL := help -help: - @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}' +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: gen-manifests ## Install CRDs into the K8s cluster + $(KUSTOMIZE) build deploy/crd | kubectl apply -f - + +.PHONY: uninstall +uninstall: gen-manifests ## Uninstall CRDs from the K8s cluster. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build deploy/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + +.PHONY: deploy +deploy: gen-manifests ## Deploy manager resources to the K8s cluster + cd deploy/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build deploy/default | kubectl apply -f - + +.PHONY: undeploy +clean: ## Clean manager resources from the K8s cluster. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build deploy/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + +##@ Dependencies + +# Dependency tool chain +GOLANGCI_VERSION = 1.53.3 +LICENSEI_VERSION = 0.8.0 +KIND_VERSION = 0.20.0 +KURUN_VERSION = 0.7.0 +CODE_GENERATOR_VERSION = 0.27.1 +HELM_DOCS_VERSION = 1.11.0 +KUSTOMIZE_VERSION = 5.0.1 +CONTROLLER_TOOLS_VERSION = 0.12.0 + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +KUSTOMIZE ?= $(or $(shell which kustomize),$(LOCALBIN)/kustomize) +$(KUSTOMIZE): $(LOCALBIN) + @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q v$(KUSTOMIZE_VERSION); then \ + echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ + rm -rf $(LOCALBIN)/kustomize; \ + fi + test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v5@v$(KUSTOMIZE_VERSION) + +CONTROLLER_GEN ?= $(or $(shell which controller-gen),$(LOCALBIN)/controller-gen) +$(CONTROLLER_GEN): $(LOCALBIN) + test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q v$(CONTROLLER_TOOLS_VERSION) || \ + GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@v$(CONTROLLER_TOOLS_VERSION) + +ENVTEST ?= $(or $(shell which setup-envtest),$(LOCALBIN)/setup-envtest) +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +GOLANGCI_LINT ?= $(or $(shell which golangci-lint),$(LOCALBIN)/golangci-lint) +$(GOLANGCI_LINT): $(LOCALBIN) + test -s $(LOCALBIN)/golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- v${GOLANGCI_VERSION} + +LICENSEI ?= $(or $(shell which licensei),$(LOCALBIN)/licensei) +$(LICENSEI): $(LOCALBIN) + test -s $(LOCALBIN)/licensei || curl -sfL https://raw.githubusercontent.com/goph/licensei/master/install.sh | bash -s -- v${LICENSEI_VERSION} + +HELM ?= $(or $(shell which helm),$(LOCALBIN)/helm) +$(HELM): $(LOCALBIN) + test -s $(LOCALBIN)/helm || curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | USE_SUDO=false HELM_INSTALL_DIR=$(LOCALBIN) bash + +KIND ?= $(or $(shell which kind),$(LOCALBIN)/kind) +$(KIND): $(LOCALBIN) + @if [ ! -s "$(LOCALBIN)/kind" ]; then \ + curl -Lo $(LOCALBIN)/kind https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | sed -e "s/aarch64/arm64/; s/x86_64/amd64/"); \ + chmod +x $(LOCALBIN)/kind; \ + fi + +HELM_DOCS ?= $(or $(shell which helm-docs),$(LOCALBIN)/helm-docs) +$(HELM_DOCS): $(LOCALBIN) + @if [ ! -s "$(LOCALBIN)/helm-docs" ]; then \ + curl -L https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS_VERSION}/helm-docs_${HELM_DOCS_VERSION}_$(shell uname)_x86_64.tar.gz | tar -zOxf - helm-docs > ./bin/helm-docs; \ + chmod +x $(LOCALBIN)/helm-docs; \ + fi + +KURUN ?= $(or $(shell which kurun),$(LOCALBIN)/kurun) +$(KURUN): $(LOCALBIN) + @if [ ! -s "$(LOCALBIN)/kurun" ]; then \ + curl -Lo $(LOCALBIN)/kurun https://github.com/banzaicloud/kurun/releases/download/${KURUN_VERSION}/kurun-$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | sed -e "s/aarch64/arm64/; s/x86_64/amd64/"); \ + chmod +x $(LOCALBIN)/kurun; \ + fi + +# TODO: add support for hadolint and yamllint dependencies +HADOLINT ?= hadolint +YAMLLINT ?= yamllint + +.PHONY: deps +deps: $(HELM) $(CONTROLLER_GEN) $(KUSTOMIZE) $(KIND) +deps: $(HELM_DOCS) $(ENVTEST) $(GOLANGCI_LINT) $(LICENSEI) $(KURUN) +deps: ## Download and install dependencies diff --git a/PROJECT b/PROJECT new file mode 100644 index 00000000..66c75a6f --- /dev/null +++ b/PROJECT @@ -0,0 +1,21 @@ +# 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 +componentConfig: true +domain: bank-vaults.dev +layout: +- go.kubebuilder.io/v4 +multigroup: true +projectName: vault-operator +repo: github.com/bank-vaults/vault-operator +resources: +- api: + crdVersion: v1alpha1 + namespaced: true + controller: true + group: vault.banzaicloud.com + kind: Vault + path: github.com/bank-vaults/vault-operator/pkg/apis/vault/v1alpha1 + version: v1alpha1 +version: "3" diff --git a/cmd/manager/main.go b/cmd/main.go similarity index 57% rename from cmd/manager/main.go rename to cmd/main.go index 8d00aa77..b6dbdc2f 100644 --- a/cmd/manager/main.go +++ b/cmd/main.go @@ -20,8 +20,9 @@ import ( "os" "time" - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - "k8s.io/client-go/rest" + // 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" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client/config" @@ -30,22 +31,28 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" "github.com/bank-vaults/vault-operator/pkg/apis" + vaultv1alpha1 "github.com/bank-vaults/vault-operator/pkg/apis/vault/v1alpha1" "github.com/bank-vaults/vault-operator/pkg/controller" ) -var log = ctrl.Log.WithName("cmd") - const ( - operatorNamespace = "OPERATOR_NAMESPACE" - watchNamespaceEnvVar = "WATCH_NAMESPACE" + envOperatorNamespace = "OPERATOR_NAMESPACE" + envWatchNamespace = "WATCH_NAMESPACE" + envKubeServiceHost = "KUBERNETES_SERVICE_HOST" + envKubeServicePort = "KUBERNETES_SERVICE_PORT" + envBankVaultsImage = "BANK_VAULTS_IMAGE" healthProbeBindAddress = ":8080" metricsBindAddress = ":8383" + defaultSyncPeriod = 30 * time.Second ) -func main() { - syncPeriod := flag.Duration("sync_period", 30*time.Second, "SyncPeriod determines the minimum frequency at which watched resources are reconciled") - verbose := flag.Bool("verbose", false, "enable verbose logging") +var log = ctrl.Log.WithName("cmd") +func main() { + // Register CLI flags + syncPeriod := flag.Duration("sync_period", defaultSyncPeriod, + "Determines the minimum frequency at which watched resources are reconciled") + verbose := flag.Bool("verbose", false, "Enables verbose logging") flag.Parse() // The logger instantiated here can be changed to any logger @@ -54,29 +61,38 @@ func main() { // uniform and structured logs. ctrl.SetLogger(zap.New(zap.UseDevMode(*verbose))) - // Fetch namespace data - namespace, isSet := os.LookupEnv(operatorNamespace) - if !isSet { - namespace, isSet = os.LookupEnv(watchNamespaceEnvVar) + // Update default bank vaults image if needed + defaultImage := os.Getenv(envBankVaultsImage) + if defaultImage != "" { + vaultv1alpha1.DefaultBankVaultsImage = defaultImage + } + + // Get namespace config + namespace := os.Getenv(envOperatorNamespace) + if namespace == "" { + namespace = os.Getenv(envWatchNamespace) } - var namespaces []string - if !isSet { - log.Info("No watched namespace found, watching the entire cluster") + namespaces := []string{} + if namespace == "" { + log.Info("no watched namespace found, watching the entire cluster") } else { - log.Info("Watched namespace: " + namespace) namespaces = []string{namespace} + log.Info("watched namespace: " + namespace) } - // Get a config to talk to the apiserver + // Load kube client config k8sConfig, err := config.GetConfig() if err != nil { - log.Error(err, "Unable to get k8s config") + log.Error(err, "unable to get k8s config") os.Exit(1) } + // Configure leader election + host := os.Getenv(envKubeServiceHost) + port := os.Getenv(envKubeServicePort) leaderElectionNamespace := "" - if !isInClusterConfig(k8sConfig) { + if k8sConfig.Host != "https://"+net.JoinHostPort(host, port) { leaderElectionNamespace = "default" } @@ -90,50 +106,48 @@ func main() { LeaderElectionNamespace: leaderElectionNamespace, LeaderElectionID: "vault-operator-lock", HealthProbeBindAddress: healthProbeBindAddress, + MetricsBindAddress: metricsBindAddress, LivenessEndpointName: "/", // For Chart backwards compatibility ReadinessEndpointName: "/ready", // For Chart backwards compatibility - MetricsBindAddress: metricsBindAddress, }) if err != nil { - log.Error(err, "Unable to create manager as defined") + log.Error(err, "unable to create manager as defined") os.Exit(1) } + // +kubebuilder:scaffold:builder + + // Register checks + log.Info("registering manager checks") err = mgr.AddReadyzCheck("ping", healthz.Ping) if err != nil { - log.Error(err, "Add Readyz Check failed") + log.Error(err, "unable to add readyz check") os.Exit(1) } + err = mgr.AddHealthzCheck("ping", healthz.Ping) if err != nil { - log.Error(err, "Unable to add heatlh check") + log.Error(err, "unable to add heatlhz check") os.Exit(1) } - log.Info("Registering Components.") + // Setup scheme and controller + log.Info("bootstrapping manager") - // Setup Scheme for all resources if err := apis.AddToScheme(mgr.GetScheme()); err != nil { - log.Error(err, "Failed to use api to add scheme") + log.Error(err, "unable to add scheme to manager") os.Exit(1) } - // Setup all Controllers if err := controller.AddToManager(mgr); err != nil { - log.Error(err, "Unable to add manager to controller") + log.Error(err, "unable to add manager to controller") os.Exit(1) } - log.Info("Starting the Cmd.") - - // Start the Cmd + // Start manager + log.Info("starting manager") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - log.Error(err, "manager exited non-zero") + log.Error(err, "problem running manager") os.Exit(1) } } - -func isInClusterConfig(k8sConfig *rest.Config) bool { - host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT") - return k8sConfig.Host == "https://"+net.JoinHostPort(host, port) -} diff --git a/deploy/charts/vault-operator/crds/crd.yaml b/deploy/charts/vault-operator/crds/crd.yaml index 2373e1cd..057a3c6c 100644 --- a/deploy/charts/vault-operator/crds/crd.yaml +++ b/deploy/charts/vault-operator/crds/crd.yaml @@ -1161,12 +1161,12 @@ spec: properties: preFlightChecks: type: boolean - storeRootToken: - type: boolean secretShares: type: integer secretThreshold: type: integer + storeRootToken: + type: boolean type: object vault: properties: @@ -10451,3 +10451,5 @@ spec: type: object served: true storage: true + subresources: + status: {} diff --git a/deploy/default/crd.yaml b/deploy/crd/bases/vault.banzaicloud.com_vaults.yaml similarity index 99% rename from deploy/default/crd.yaml rename to deploy/crd/bases/vault.banzaicloud.com_vaults.yaml index 2373e1cd..057a3c6c 100644 --- a/deploy/default/crd.yaml +++ b/deploy/crd/bases/vault.banzaicloud.com_vaults.yaml @@ -1161,12 +1161,12 @@ spec: properties: preFlightChecks: type: boolean - storeRootToken: - type: boolean secretShares: type: integer secretThreshold: type: integer + storeRootToken: + type: boolean type: object vault: properties: @@ -10451,3 +10451,5 @@ spec: type: object served: true storage: true + subresources: + status: {} diff --git a/deploy/crd/kustomization.yaml b/deploy/crd/kustomization.yaml new file mode 100644 index 00000000..a5bad48a --- /dev/null +++ b/deploy/crd/kustomization.yaml @@ -0,0 +1,21 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/vault.banzaicloud.com_vaults.yaml +#+kubebuilder:scaffold:crdkustomizeresource + +patches: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +#- path: patches/webhook_in_vaults.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 +#- path: patches/cainjection_in_vaults.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/deploy/crd/kustomizeconfig.yaml b/deploy/crd/kustomizeconfig.yaml new file mode 100644 index 00000000..ec5c150a --- /dev/null +++ b/deploy/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/deploy/crd/patches/cainjection_in_vaults.yaml b/deploy/crd/patches/cainjection_in_vaults.yaml new file mode 100644 index 00000000..d17d2299 --- /dev/null +++ b/deploy/crd/patches/cainjection_in_vaults.yaml @@ -0,0 +1,7 @@ +# 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: vault.banzaicloud.com diff --git a/deploy/crd/patches/webhook_in_vaults.yaml b/deploy/crd/patches/webhook_in_vaults.yaml new file mode 100644 index 00000000..4e27f02b --- /dev/null +++ b/deploy/crd/patches/webhook_in_vaults.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vault.banzaicloud.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: default + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/deploy/default/kustomization.yaml b/deploy/default/kustomization.yaml new file mode 100644 index 00000000..5494a51e --- /dev/null +++ b/deploy/default/kustomization.yaml @@ -0,0 +1,143 @@ +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: vault-operator- + +# Labels to add to all resources and selectors. +#labels: +#- includeSelectors: true +# pairs: +# someName: someValue + +resources: +- ../crd +- ../rbac +# [MANAGER] +# - ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus + +patches: [] +# [MANAGER] +# 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 + + + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- manager_webhook_patch.yaml + +# [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 + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +# Uncomment the following replacements to add the cert-manager CA injection annotations +#replacements: +# - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs +# 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 +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - select: +# kind: CustomResourceDefinition +# 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 # this name should match the one in certificate.yaml +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - select: +# kind: CustomResourceDefinition +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - source: # Add cert-manager annotation to the webhook Service +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# 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 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true diff --git a/deploy/default/manager_auth_proxy_patch.yaml b/deploy/default/manager_auth_proxy_patch.yaml new file mode 100644 index 00000000..6af23b07 --- /dev/null +++ b/deploy/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,39 @@ +# 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: default +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=0" + ports: + - containerPort: 8443 + protocol: TCP + name: https + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" diff --git a/deploy/default/manager_config_patch.yaml b/deploy/default/manager_config_patch.yaml new file mode 100644 index 00000000..f40fbd79 --- /dev/null +++ b/deploy/default/manager_config_patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: default +spec: + template: + spec: + containers: + - name: manager diff --git a/deploy/default/rbac.yaml b/deploy/default/rbac.yaml deleted file mode 100644 index 77ee9075..00000000 --- a/deploy/default/rbac.yaml +++ /dev/null @@ -1,49 +0,0 @@ -kind: ServiceAccount -apiVersion: v1 -metadata: - name: vault - ---- - -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: vault -rules: - - apiGroups: [""] - resources: ["secrets"] - verbs: ["*"] - - apiGroups: [""] - resources: ["pods"] - verbs: ["get", "update", "patch"] - ---- - -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: vault -roleRef: - kind: Role - name: vault - apiGroup: rbac.authorization.k8s.io -subjects: - - kind: ServiceAccount - name: vault - ---- - -# This binding allows the deployed Vault instance to authenticate clients -# through Kubernetes ServiceAccounts (if configured so). -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: vault-auth-delegator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: - - kind: ServiceAccount - name: vault - namespace: default diff --git a/deploy/dev/multi-dc/aws/multi-dc-raft.sh b/deploy/dev/multi-dc/aws/multi-dc-raft.sh index c5c04d98..6cbc3213 100755 --- a/deploy/dev/multi-dc/aws/multi-dc-raft.sh +++ b/deploy/dev/multi-dc/aws/multi-dc-raft.sh @@ -4,6 +4,7 @@ set -euo pipefail # REQUIREMENTS: # - kubectl +# - kustomize # - helm3 # - https://github.com/subfuzion/envtpl # - jq @@ -94,7 +95,7 @@ if [ $COMMAND = "install" ]; then create_aws_secret - kubectl apply -f operator/deploy/rbac.yaml + kubectl apply -k deploy/rbac/ cat operator/deploy/dev/multi-dc/aws/cr-${INSTANCE}.yaml | envtpl | kubectl apply -f - echo "Waiting for for ${INSTANCE} vault instance..." diff --git a/deploy/dev/multi-dc/test/multi-dc-raft.sh b/deploy/dev/multi-dc/test/multi-dc-raft.sh index 4396e974..3d2739ac 100755 --- a/deploy/dev/multi-dc/test/multi-dc-raft.sh +++ b/deploy/dev/multi-dc/test/multi-dc-raft.sh @@ -3,6 +3,7 @@ set -xeo pipefail # REQUIREMENTS: +# - kustomize # - kubectl # - helm3 # - https://github.com/subfuzion/envtpl @@ -83,7 +84,7 @@ function install_instance { helm upgrade --install vault-operator ./deploy/charts/vault-operator --wait --set image.tag=${OPERATOR_VERSION} --set image.pullPolicy=Never --set image.bankVaultsTag=${BANK_VAULTS_VERSION} - kubectl apply -f deploy/default/rbac.yaml + kubectl apply -k deploy/rbac/ envtpl deploy/dev/multi-dc/test/cr-"${INSTANCE}".yaml | kubectl apply -f - echo "Waiting for for ${INSTANCE} vault instance..." diff --git a/deploy/manager/kustomization.yaml b/deploy/manager/kustomization.yaml new file mode 100644 index 00000000..4ece6262 --- /dev/null +++ b/deploy/manager/kustomization.yaml @@ -0,0 +1,8 @@ +resources: +- manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: ghcr.io/bank-vaults/vault-operator + newTag: latest diff --git a/deploy/manager/manager.yaml b/deploy/manager/manager.yaml new file mode 100644 index 00000000..bcd7f129 --- /dev/null +++ b/deploy/manager/manager.yaml @@ -0,0 +1,102 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: namespace + app.kubernetes.io/instance: system + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: default + labels: + control-plane: controller-manager + app.kubernetes.io/name: deployment + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + 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: + runAsNonRoot: true + # TODO(user): For common cases that do not require escalating privileges + # it is recommended to ensure that all your Pods/Containers are restrictive. + # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + # Please uncomment the following code if your project does NOT have to work on old Kubernetes + # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). + # seccompProfile: + # type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + image: controller:latest + name: manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /ready + port: 8080 + 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: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/deploy/prometheus/kustomization.yaml b/deploy/prometheus/kustomization.yaml new file mode 100644 index 00000000..ed137168 --- /dev/null +++ b/deploy/prometheus/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- monitor.yaml diff --git a/deploy/prometheus/monitor.yaml b/deploy/prometheus/monitor.yaml new file mode 100644 index 00000000..bb34cdec --- /dev/null +++ b/deploy/prometheus/monitor.yaml @@ -0,0 +1,26 @@ + +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: servicemonitor + app.kubernetes.io/instance: controller-manager-metrics-monitor + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: default +spec: + endpoints: + - path: /metrics + port: https + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager diff --git a/deploy/rbac/auth_proxy_client_clusterrole.yaml b/deploy/rbac/auth_proxy_client_clusterrole.yaml new file mode 100644 index 00000000..91e3b85f --- /dev/null +++ b/deploy/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/deploy/rbac/auth_proxy_role.yaml b/deploy/rbac/auth_proxy_role.yaml new file mode 100644 index 00000000..5a6424a3 --- /dev/null +++ b/deploy/rbac/auth_proxy_role.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: proxy-role + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/deploy/rbac/auth_proxy_role_binding.yaml b/deploy/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 00000000..4ffff30d --- /dev/null +++ b/deploy/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: proxy-rolebinding + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: vault + namespace: default diff --git a/deploy/rbac/auth_proxy_service.yaml b/deploy/rbac/auth_proxy_service.yaml new file mode 100644 index 00000000..6cd9e5d1 --- /dev/null +++ b/deploy/rbac/auth_proxy_service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: service + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: default +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/deploy/rbac/cluster_role_binding.yaml b/deploy/rbac/cluster_role_binding.yaml new file mode 100644 index 00000000..486f3873 --- /dev/null +++ b/deploy/rbac/cluster_role_binding.yaml @@ -0,0 +1,22 @@ +# This binding allows the deployed Vault instance to authenticate clients +# through Kubernetes ServiceAccounts (if configured so). + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: vault-auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: vault + namespace: default diff --git a/deploy/rbac/kustomization.yaml b/deploy/rbac/kustomization.yaml new file mode 100644 index 00000000..ce15a98c --- /dev/null +++ b/deploy/rbac/kustomization.yaml @@ -0,0 +1,19 @@ +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- cluster_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 diff --git a/deploy/rbac/leader_election_role.yaml b/deploy/rbac/leader_election_role.yaml new file mode 100644 index 00000000..05922aa5 --- /dev/null +++ b/deploy/rbac/leader_election_role.yaml @@ -0,0 +1,44 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: role + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/deploy/rbac/leader_election_role_binding.yaml b/deploy/rbac/leader_election_role_binding.yaml new file mode 100644 index 00000000..d439a85d --- /dev/null +++ b/deploy/rbac/leader_election_role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: rolebinding + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: vault + namespace: default diff --git a/deploy/rbac/role.yaml b/deploy/rbac/role.yaml new file mode 100644 index 00000000..94d3ecd1 --- /dev/null +++ b/deploy/rbac/role.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: vault + namespace: default +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - patch + - update +- apiGroups: + - "" + resources: + - secrets + verbs: + - '*' diff --git a/deploy/rbac/role_binding.yaml b/deploy/rbac/role_binding.yaml new file mode 100644 index 00000000..08e04f2c --- /dev/null +++ b/deploy/rbac/role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: rolebinding + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: vault +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: vault +subjects: +- kind: ServiceAccount + name: vault + namespace: default diff --git a/deploy/rbac/service_account.yaml b/deploy/rbac/service_account.yaml new file mode 100644 index 00000000..0ef8a770 --- /dev/null +++ b/deploy/rbac/service_account.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/instance: vault-sa + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: vault + namespace: default diff --git a/deploy/rbac/vault_editor_role.yaml b/deploy/rbac/vault_editor_role.yaml new file mode 100644 index 00000000..caded76a --- /dev/null +++ b/deploy/rbac/vault_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit vaults. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: vault-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: vault-editor-role +rules: +- apiGroups: + - vault.banzaicloud.com + resources: + - vaults + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - vault.banzaicloud.com + resources: + - vaults/status + verbs: + - get diff --git a/deploy/rbac/vault_viewer_role.yaml b/deploy/rbac/vault_viewer_role.yaml new file mode 100644 index 00000000..93bac152 --- /dev/null +++ b/deploy/rbac/vault_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view vaults. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: vault-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: kustomize + name: vault-viewer-role +rules: +- apiGroups: + - vault.banzaicloud.com + resources: + - vaults + verbs: + - get + - list + - watch +- apiGroups: + - vault.banzaicloud.com + resources: + - vaults/status + verbs: + - get diff --git a/go.mod b/go.mod index 1a75946e..045bcf6b 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,8 @@ require ( github.com/gruntwork-io/terratest v0.43.8 github.com/hashicorp/vault/api v1.9.2 github.com/imdario/mergo v0.3.12 + github.com/onsi/ginkgo/v2 v2.9.5 + github.com/onsi/gomega v1.27.7 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.66.0 github.com/spf13/cast v1.5.1 github.com/stretchr/testify v1.8.4 @@ -36,7 +38,6 @@ require ( github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect @@ -47,12 +48,14 @@ require ( github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/s2a-go v0.1.3 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect @@ -60,7 +63,6 @@ require ( github.com/gruntwork-io/go-commons v0.8.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.6.6 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect @@ -73,8 +75,6 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/leosayous21/go-azure-msi v0.0.0-20210509193526-19353bedcfc8 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -106,6 +106,7 @@ require ( golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.9.1 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 0fa09bbd..630012f9 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,9 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cisco-open/k8s-objectmatcher v1.9.0 h1:/sfuO0BD09fpynZjXsqeZrh28Juc4VEwc2P6Ov/Q6fM= github.com/cisco-open/k8s-objectmatcher v1.9.0/go.mod h1:CH4E6qAK+q+JwKFJn0DaTNqxrbmWCaDQzGthKLK4nZ0= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -63,9 +66,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -90,6 +92,7 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -129,6 +132,7 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -151,8 +155,7 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -171,6 +174,7 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -199,16 +203,11 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 h1:ofNAzWCcyTALn2Zv40+8XitdzCgXY6e9qvXwN9W0YXg= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= @@ -231,7 +230,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -321,6 +322,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -352,17 +354,15 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -370,8 +370,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -406,6 +404,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= diff --git a/hack/scripts/custom-boilerplate.go.txt b/hack/custom-boilerplate.go.txt similarity index 100% rename from hack/scripts/custom-boilerplate.go.txt rename to hack/custom-boilerplate.go.txt diff --git a/hack/scripts/update-codegen.sh b/hack/update-codegen.sh similarity index 61% rename from hack/scripts/update-codegen.sh rename to hack/update-codegen.sh index dc1c5964..9c1d88f0 100755 --- a/hack/scripts/update-codegen.sh +++ b/hack/update-codegen.sh @@ -20,22 +20,36 @@ set -o pipefail function finish { rm -rf ${CODEGEN_DIR} + rm -rf github.com } trap finish EXIT -CODEGEN_DIR=$(mktemp -d) +## Package configs +MODULE=github.com/bank-vaults/vault-operator +APIS_PKG=pkg/apis +OUTPUT_PKG=pkg/client +GROUP_VERSION=vault:v1alpha1 -VERSION=$1 +## Prepare codegen +SOURCE_DIR=$(dirname "${BASH_SOURCE[0]}")/.. +CODEGEN_VERSION=$1 +CODEGEN_DIR=$(mktemp -d) -git clone git@github.com:kubernetes/code-generator.git ${CODEGEN_DIR} -cd ${CODEGEN_DIR} && git checkout $VERSION && cd - +git clone https://github.com/kubernetes/code-generator.git ${CODEGEN_DIR} +cd ${CODEGEN_DIR} && git checkout $CODEGEN_VERSION && cd - # generate the code with: # --output-base because this script should also be able to run inside the vendor dir of # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir # instead of the $GOPATH directly. For normal projects this can be dropped. -${CODEGEN_DIR}/generate-groups.sh all \ - github.com/banzaicloud/bank-vaults/vault-operator/pkg/client github.com/banzaicloud/bank-vaults/vault-operator/pkg/apis \ - vault:v1alpha1 \ - --go-header-file ./hack/scripts/custom-boilerplate.go.txt + +## Generate code +${CODEGEN_DIR}/generate-groups.sh "client,lister,informer" \ + ${MODULE}/${OUTPUT_PKG} ${MODULE}/${APIS_PKG} \ + ${GROUP_VERSION} \ + --go-header-file "${SOURCE_DIR}"/hack/custom-boilerplate.go.txt \ + --output-base "${SOURCE_DIR}" + +## Cleanup +cp -a ${MODULE}/. ${SOURCE_DIR} diff --git a/pkg/apis/addtoscheme_monitor_v1.go b/pkg/apis/addtoscheme_monitor_v1.go index db51f844..78e307c5 100644 --- a/pkg/apis/addtoscheme_monitor_v1.go +++ b/pkg/apis/addtoscheme_monitor_v1.go @@ -15,10 +15,9 @@ package apis import ( - v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + monitorv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" ) func init() { - // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back - AddToSchemes = append(AddToSchemes, v1.SchemeBuilder.AddToScheme) + AddToSchemes = append(AddToSchemes, monitorv1.SchemeBuilder.AddToScheme) } diff --git a/pkg/apis/addtoscheme_vault_v1alpha1.go b/pkg/apis/addtoscheme_vault_v1alpha1.go index 3fa409a9..29423d05 100644 --- a/pkg/apis/addtoscheme_vault_v1alpha1.go +++ b/pkg/apis/addtoscheme_vault_v1alpha1.go @@ -19,6 +19,5 @@ import ( ) func init() { - // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) } diff --git a/pkg/apis/vault/v1alpha1/doc.go b/pkg/apis/vault/v1alpha1/doc.go deleted file mode 100644 index 76794f58..00000000 --- a/pkg/apis/vault/v1alpha1/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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 v1alpha1 contains API Schema definitions for the vault v1alpha1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=vault.banzaicloud.com -package v1alpha1 diff --git a/pkg/apis/vault/v1alpha1/embedded_v1.go b/pkg/apis/vault/v1alpha1/embedded_v1.go index b574133e..0ac7be8a 100644 --- a/pkg/apis/vault/v1alpha1/embedded_v1.go +++ b/pkg/apis/vault/v1alpha1/embedded_v1.go @@ -27,6 +27,7 @@ type EmbeddedPodSpec struct { // +patchMergeKey=name // +patchStrategy=merge,retainKeys Volumes []v1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + // List of initialization containers belonging to the pod. // Init containers are executed in order prior to containers being started. If any // init container fails, the pod is considered to have failed and is handled according @@ -43,6 +44,7 @@ type EmbeddedPodSpec struct { // +patchMergeKey=name // +patchStrategy=merge InitContainers []v1.Container `json:"initContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,20,rep,name=initContainers"` + // List of containers belonging to the pod. // Containers cannot currently be added or removed. // There must be at least one container in a Pod. @@ -50,6 +52,7 @@ type EmbeddedPodSpec struct { // +patchMergeKey=name // +patchStrategy=merge Containers []v1.Container `json:"containers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"` + // List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing // pod to perform user-initiated actions such as debugging. This list cannot be specified when // creating a pod, and it cannot be modified by updating the pod spec. In order to add an @@ -58,12 +61,14 @@ type EmbeddedPodSpec struct { // +patchMergeKey=name // +patchStrategy=merge EphemeralContainers []v1.EphemeralContainer `json:"ephemeralContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,34,rep,name=ephemeralContainers"` + // Restart policy for all containers within the pod. // One of Always, OnFailure, Never. // Default to Always. // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy // +optional RestartPolicy v1.RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"` + // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. // Value must be non-negative integer. The value zero indicates stop immediately via // the kill signal (no opportunity to shut down). @@ -74,11 +79,13 @@ type EmbeddedPodSpec struct { // Defaults to 30 seconds. // +optional TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty" protobuf:"varint,4,opt,name=terminationGracePeriodSeconds"` + // Optional duration in seconds the pod may be active on the node relative to // StartTime before the system will actively try to mark it failed and kill associated containers. // Value must be a positive integer. // +optional ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"` + // Set DNS policy for the pod. // Defaults to "ClusterFirst". // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. @@ -87,6 +94,7 @@ type EmbeddedPodSpec struct { // explicitly to 'ClusterFirstWithHostNet'. // +optional DNSPolicy v1.DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"` + // NodeSelector is a selector which must be true for the pod to fit on a node. // Selector which must match a node's labels for the pod to be scheduled on that node. // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ @@ -98,11 +106,13 @@ type EmbeddedPodSpec struct { // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ // +optional ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"` + // DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. // Deprecated: Use serviceAccountName instead. // +k8s:conversion-gen=false // +optional DeprecatedServiceAccount string `json:"serviceAccount,omitempty" protobuf:"bytes,9,opt,name=serviceAccount"` + // AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. // +optional AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" protobuf:"varint,21,opt,name=automountServiceAccountToken"` @@ -112,22 +122,26 @@ type EmbeddedPodSpec struct { // requirements. // +optional NodeName string `json:"nodeName,omitempty" protobuf:"bytes,10,opt,name=nodeName"` + // Host networking requested for this pod. Use the host's network namespace. // If this option is set, the ports that will be used must be specified. // Default to false. // +k8s:conversion-gen=false // +optional HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,11,opt,name=hostNetwork"` + // Use the host's pid namespace. // Optional: Default to false. // +k8s:conversion-gen=false // +optional HostPID bool `json:"hostPID,omitempty" protobuf:"varint,12,opt,name=hostPID"` + // Use the host's ipc namespace. // Optional: Default to false. // +k8s:conversion-gen=false // +optional HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"` + // Share a single process namespace between all of the containers in a pod. // When this is set containers will be able to view and signal processes from other containers // in the same pod, and the first process in each container will not be assigned PID 1. @@ -136,10 +150,12 @@ type EmbeddedPodSpec struct { // +k8s:conversion-gen=false // +optional ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty" protobuf:"varint,27,opt,name=shareProcessNamespace"` + // SecurityContext holds pod-level security attributes and common container settings. // Optional: Defaults to empty. See type description for default values of each field. // +optional SecurityContext *v1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,14,opt,name=securityContext"` + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. // If specified, these secrets will be passed to individual puller implementations for them to use. // More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod @@ -147,30 +163,37 @@ type EmbeddedPodSpec struct { // +patchMergeKey=name // +patchStrategy=merge ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,15,rep,name=imagePullSecrets"` + // Specifies the hostname of the Pod // If not specified, the pod's hostname will be set to a system-defined value. // +optional Hostname string `json:"hostname,omitempty" protobuf:"bytes,16,opt,name=hostname"` + // If specified, the fully qualified Pod hostname will be "...svc.". // If not specified, the pod will not have a domainname at all. // +optional Subdomain string `json:"subdomain,omitempty" protobuf:"bytes,17,opt,name=subdomain"` + // If specified, the pod's scheduling constraints // +optional Affinity *v1.Affinity `json:"affinity,omitempty" protobuf:"bytes,18,opt,name=affinity"` + // If specified, the pod will be dispatched by specified scheduler. // If not specified, the pod will be dispatched by default scheduler. // +optional SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,19,opt,name=schedulerName"` + // If specified, the pod's tolerations. // +optional Tolerations []v1.Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"` + // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts // file if specified. This is only valid for non-hostNetwork pods. // +optional // +patchMergeKey=ip // +patchStrategy=merge HostAliases []v1.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,23,rep,name=hostAliases"` + // If specified, indicates the pod's priority. "system-node-critical" and // "system-cluster-critical" are two special keywords which indicate the // highest priorities with the former being the highest priority. Any other @@ -179,6 +202,7 @@ type EmbeddedPodSpec struct { // default. // +optional PriorityClassName string `json:"priorityClassName,omitempty" protobuf:"bytes,24,opt,name=priorityClassName"` + // The priority value. Various system components use this field to find the // priority of the pod. When Priority Admission Controller is enabled, it // prevents users from setting this field. The admission controller populates @@ -186,17 +210,20 @@ type EmbeddedPodSpec struct { // The higher the value, the higher the priority. // +optional Priority *int32 `json:"priority,omitempty" protobuf:"bytes,25,opt,name=priority"` + // Specifies the DNS parameters of a pod. // Parameters specified here will be merged to the generated DNS // configuration based on DNSPolicy. // +optional DNSConfig *v1.PodDNSConfig `json:"dnsConfig,omitempty" protobuf:"bytes,26,opt,name=dnsConfig"` + // If specified, all readiness gates will be evaluated for pod readiness. // A pod is ready when all its containers are ready AND // all conditions specified in the readiness gates have status equal to "True" // More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates // +optional ReadinessGates []v1.PodReadinessGate `json:"readinessGates,omitempty" protobuf:"bytes,28,opt,name=readinessGates"` + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used // to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. // If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an @@ -204,16 +231,19 @@ type EmbeddedPodSpec struct { // More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class // +optional RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,29,opt,name=runtimeClassName"` + // EnableServiceLinks indicates whether information about services should be injected into pod's // environment variables, matching the syntax of Docker links. // Optional: Defaults to true. // +optional EnableServiceLinks *bool `json:"enableServiceLinks,omitempty" protobuf:"varint,30,opt,name=enableServiceLinks"` + // PreemptionPolicy is the Policy for preempting pods with lower priority. // One of Never, PreemptLowerPriority. // Defaults to PreemptLowerPriority if unset. // +optional PreemptionPolicy *v1.PreemptionPolicy `json:"preemptionPolicy,omitempty" protobuf:"bytes,31,opt,name=preemptionPolicy"` + // Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. // This field will be autopopulated at admission time by the RuntimeClass admission controller. If // the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. @@ -223,6 +253,7 @@ type EmbeddedPodSpec struct { // More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md // +optional Overhead v1.ResourceList `json:"overhead,omitempty" protobuf:"bytes,32,opt,name=overhead"` + // TopologySpreadConstraints describes how a group of pods ought to spread across topology // domains. Scheduler will schedule pods in a way which abides by the constraints. // All topologySpreadConstraints are ANDed. @@ -233,6 +264,7 @@ type EmbeddedPodSpec struct { // +listMapKey=topologyKey // +listMapKey=whenUnsatisfiable TopologySpreadConstraints []v1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey" protobuf:"bytes,33,opt,name=topologySpreadConstraints"` + // If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). // In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). // In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. @@ -240,6 +272,7 @@ type EmbeddedPodSpec struct { // Default to false. // +optional SetHostnameAsFQDN *bool `json:"setHostnameAsFQDN,omitempty" protobuf:"varint,35,opt,name=setHostnameAsFQDN"` + // Specifies the OS of the containers in the pod. // Some pod and container fields are restricted if this is set. // @@ -294,6 +327,7 @@ type EmbeddedPodSpec struct { // +listType=map // +listMapKey=name SchedulingGates []v1.PodSchedulingGate `json:"schedulingGates,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,38,opt,name=schedulingGates"` + // ResourceClaims defines which ResourceClaims must be allocated // and reserved before the Pod is allowed to start. The resources // will be made available to those containers which consume them @@ -318,7 +352,7 @@ type EmbeddedPodSpec struct { type EmbeddedPersistentVolumeClaim struct { metav1.TypeMeta `json:",inline"` - // EmbeddedMetadata contains metadata relevant to an EmbeddedResource. + // EmbeddedObjectMetadata contains metadata relevant to an EmbeddedResource. EmbeddedObjectMetadata `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Spec defines the desired characteristics of a volume requested by a pod author. diff --git a/pkg/apis/vault/v1alpha1/register.go b/pkg/apis/vault/v1alpha1/groupversion_info.go similarity index 64% rename from pkg/apis/vault/v1alpha1/register.go rename to pkg/apis/vault/v1alpha1/groupversion_info.go index 41b111f8..47738ec5 100644 --- a/pkg/apis/vault/v1alpha1/register.go +++ b/pkg/apis/vault/v1alpha1/groupversion_info.go @@ -12,17 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// NOTE: Boilerplate only. Ignore this file. - -// Package v1alpha1 contains API Schema definitions for the vault v1alpha1 API group -// +k8s:deepcopy-gen=package,register +// +kubebuilder:object:generate=true // +groupName=vault.banzaicloud.com + +// Package v1alpha1 contains API Schema definitions for the vault.banzaicloud.com v1alpha1 API group package v1alpha1 import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" ) var ( @@ -30,8 +28,9 @@ var ( SchemeGroupVersion = schema.GroupVersion{Group: "vault.banzaicloud.com", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - // AddToScheme helper + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. AddToScheme = SchemeBuilder.AddToScheme ) @@ -44,20 +43,3 @@ func Kind(kind string) schema.GroupKind { func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - SchemeBuilder.Register(addKnownTypes) -} - -// Adds the list of known types to Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &Vault{}, - &VaultList{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/pkg/apis/vault/v1alpha1/vault_types.go b/pkg/apis/vault/v1alpha1/vault_types.go index 97b03091..13d23dc1 100644 --- a/pkg/apis/vault/v1alpha1/vault_types.go +++ b/pkg/apis/vault/v1alpha1/vault_types.go @@ -15,63 +15,47 @@ package v1alpha1 import ( - "encoding/json" - "errors" "fmt" - "os" - "reflect" - "sort" - "strings" - "time" - "github.com/Masterminds/semver/v3" "github.com/imdario/mergo" "github.com/spf13/cast" - v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" - extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" + "reflect" ctrl "sigs.k8s.io/controller-runtime" -) + "sort" + "strings" + "time" -var log = ctrl.Log.WithName("controller_vault") + v1 "k8s.io/api/core/v1" -var bankVaultsImage string + "encoding/json" + "errors" + extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" +) -func init() { - if bankVaultsImage = os.Getenv("BANK_VAULTS_IMAGE"); bankVaultsImage == "" { - bankVaultsImage = "ghcr.io/banzaicloud/bank-vaults:latest" +var ( + log = ctrl.Log.WithName("controller_vault") + + // DefaultBankVaultsImage defines the image used when VaultSpec.BankVaultsImage is empty. + DefaultBankVaultsImage = "ghcr.io/banzaicloud/bank-vaults:latest" + + // HAStorageTypes is the set of storage backends supporting High Availability + HAStorageTypes = map[string]bool{ + "consul": true, + "dynamodb": true, + "etcd": true, + "gcs": true, + "mysql": true, + "postgresql": true, + "raft": true, + "spanner": true, + "zookeeper": true, } -} - -// Vault is the Schema for the vaults API - -// +genclient -// +genclient:noStatus -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +k8s:openapi-gen=true -type Vault struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VaultSpec `json:"spec,omitempty"` - Status VaultStatus `json:"status,omitempty"` -} - -// VaultList contains a list of Vault - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type VaultList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Vault `json:"items"` -} - -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +) // VaultSpec defines the desired state of Vault -// Important: Run "make generate-code" to regenerate code after modifying this file type VaultSpec struct { // Size defines the number of Vault instances in the cluster (>= 1 means HA) @@ -327,19 +311,6 @@ type VaultSpec struct { VaultInitContainers []v1.Container `json:"vaultInitContainers,omitempty"` } -// HAStorageTypes is the set of storage backends supporting High Availability -var HAStorageTypes = map[string]bool{ - "consul": true, - "dynamodb": true, - "etcd": true, - "gcs": true, - "mysql": true, - "postgresql": true, - "raft": true, - "spanner": true, - "zookeeper": true, -} - // HasHAStorage detects if Vault is configured to use a storage backend which supports High Availability or if it has // ha_storage stanza, then doesn't check for ha_enabled flag func (spec *VaultSpec) HasHAStorage() bool { @@ -482,7 +453,7 @@ func (spec *VaultSpec) GetVaultImage() string { // GetBankVaultsImage returns the bank-vaults image to use func (spec *VaultSpec) GetBankVaultsImage() string { if spec.BankVaultsImage == "" { - return bankVaultsImage + return DefaultBankVaultsImage } return spec.BankVaultsImage } @@ -558,7 +529,7 @@ func (spec *VaultSpec) GetAPIPortName() string { return portName } -// GetVaultLAbels returns the Vault Pod , Secret and ConfigMap Labels +// GetVaultLabels returns the Vault Pod, Secret and ConfigMap Labels func (spec *VaultSpec) GetVaultLabels() map[string]string { if spec.VaultLabels == nil { spec.VaultLabels = map[string]string{} @@ -620,37 +591,6 @@ func (spec *VaultSpec) IsStatsDDisabled() bool { return spec.StatsDDisabled } -// ConfigJSON returns the Config field as a JSON string -func (v *Vault) ConfigJSON() ([]byte, error) { - config := map[string]interface{}{} - - err := json.Unmarshal(v.Spec.Config.Raw, &config) - if err != nil { - return nil, err - } - - if v.Spec.ServiceRegistrationEnabled && v.Spec.HasHAStorage() { - serviceRegistration := map[string]interface{}{ - "service_registration": map[string]interface{}{ - "kubernetes": map[string]string{ - "namespace": v.Namespace, - }, - }, - } - - if err := mergo.Merge(&config, serviceRegistration); err != nil { - return nil, err - } - } - - configJSON, err := json.Marshal(config) - if err != nil { - return nil, err - } - - return configJSON, nil -} - // ExternalConfigJSON returns the ExternalConfig field as a JSON string func (spec *VaultSpec) ExternalConfigJSON() []byte { return spec.ExternalConfig.Raw @@ -678,69 +618,6 @@ func (spec *VaultSpec) IsRaftBootstrapFollower() bool { return spec.RaftLeaderAddress != "" && spec.RaftLeaderAddress != "self" } -// GetIngress the Ingress configuration for Vault if any -func (vault *Vault) GetIngress() *Ingress { - if vault.Spec.Ingress != nil { - // Add the Vault Service as the backend if no rules are specified and there is no default backend - if len(vault.Spec.Ingress.Spec.Rules) == 0 && vault.Spec.Ingress.Spec.DefaultBackend == nil { - vault.Spec.Ingress.Spec.DefaultBackend = &netv1.IngressBackend{ - Service: &netv1.IngressServiceBackend{ - Name: vault.Name, - Port: netv1.ServiceBackendPort{ - Number: 8200, - }, - }, - } - } - - if vault.Spec.Ingress.Annotations == nil { - vault.Spec.Ingress.Annotations = map[string]string{} - } - - // If TLS is enabled add the Ingress TLS backend annotations - if !vault.Spec.IsTLSDisabled() { - // Supporting the NGINX ingress controller with TLS backends - // https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#backend-protocol - vault.Spec.Ingress.Annotations["nginx.ingress.kubernetes.io/backend-protocol"] = "HTTPS" - - // Supporting the Traefik ingress controller with TLS backends - // https://docs.traefik.io/configuration/backends/kubernetes/#tls-communication-between-traefik-and-backend-pods - vault.Spec.Ingress.Annotations["ingress.kubernetes.io/protocol"] = "https" - - // Supporting the HAProxy ingress controller with TLS backends - // https://github.com/jcmoraisjr/haproxy-ingress#secure-backend - vault.Spec.Ingress.Annotations["ingress.kubernetes.io/secure-backends"] = "true" - } - - return vault.Spec.Ingress - } - - return nil -} - -// LabelsForVault returns the labels for selecting the resources -// belonging to the given vault CR name. -func (vault *Vault) LabelsForVault() map[string]string { - return map[string]string{"app.kubernetes.io/name": "vault", "vault_cr": vault.Name} -} - -// LabelsForVaultConfigurer returns the labels for selecting the resources -// belonging to the given vault CR name. -func (vault *Vault) LabelsForVaultConfigurer() map[string]string { - return map[string]string{"app.kubernetes.io/name": "vault-configurator", "vault_cr": vault.Name} -} - -// AsOwnerReference returns this Vault instance as an OwnerReference -func (vault *Vault) AsOwnerReference() metav1.OwnerReference { - return metav1.OwnerReference{ - APIVersion: vault.APIVersion, - Kind: vault.Kind, - Name: vault.Name, - UID: vault.UID, - Controller: pointer.Bool(true), - } -} - // VaultStatus defines the observed state of Vault type VaultStatus struct { // Important: Run "make generate-code" to regenerate code after modifying this file @@ -749,6 +626,14 @@ type VaultStatus struct { Conditions []v1.ComponentCondition `json:"conditions,omitempty"` } +// UnsealOptions represents the common options to all unsealing backends +type UnsealOptions struct { + PreFlightChecks *bool `json:"preFlightChecks,omitempty"` + StoreRootToken *bool `json:"storeRootToken,omitempty"` + SecretThreshold *uint `json:"secretThreshold,omitempty"` + SecretShares *uint `json:"secretShares,omitempty"` +} + // UnsealConfig represents the UnsealConfig field of a VaultSpec Kubernetes object type UnsealConfig struct { Options UnsealOptions `json:"options,omitempty"` @@ -761,14 +646,6 @@ type UnsealConfig struct { HSM *HSMUnsealConfig `json:"hsm,omitempty"` } -// UnsealOptions represents the common options to all unsealing backends -type UnsealOptions struct { - PreFlightChecks *bool `json:"preFlightChecks,omitempty"` - StoreRootToken *bool `json:"storeRootToken,omitempty"` - SecretThreshold *uint `json:"secretThreshold,omitempty"` - SecretShares *uint `json:"secretShares,omitempty"` -} - // ToArgs returns the UnsealConfig as and argument array for bank-vaults func (usc *UnsealConfig) ToArgs(vault *Vault) []string { args := []string{} @@ -1051,3 +928,125 @@ type Ingress struct { Annotations map[string]string `json:"annotations,omitempty"` Spec netv1.IngressSpec `json:"spec,omitempty"` } + +// +genclient +// +genclient:noStatus +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// Vault is the Schema for the vaults API +type Vault struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VaultSpec `json:"spec,omitempty"` + Status VaultStatus `json:"status,omitempty"` +} + +// ConfigJSON returns the Config field as a JSON string +func (vault *Vault) ConfigJSON() ([]byte, error) { + config := map[string]interface{}{} + + err := json.Unmarshal(vault.Spec.Config.Raw, &config) + if err != nil { + return nil, err + } + + if vault.Spec.ServiceRegistrationEnabled && vault.Spec.HasHAStorage() { + serviceRegistration := map[string]interface{}{ + "service_registration": map[string]interface{}{ + "kubernetes": map[string]string{ + "namespace": vault.Namespace, + }, + }, + } + + if err := mergo.Merge(&config, serviceRegistration); err != nil { + return nil, err + } + } + + configJSON, err := json.Marshal(config) + if err != nil { + return nil, err + } + + return configJSON, nil +} + +// GetIngress the Ingress configuration for Vault if any +func (vault *Vault) GetIngress() *Ingress { + if vault.Spec.Ingress != nil { + // Add the Vault Service as the backend if no rules are specified and there is no default backend + if len(vault.Spec.Ingress.Spec.Rules) == 0 && vault.Spec.Ingress.Spec.DefaultBackend == nil { + vault.Spec.Ingress.Spec.DefaultBackend = &netv1.IngressBackend{ + Service: &netv1.IngressServiceBackend{ + Name: vault.Name, + Port: netv1.ServiceBackendPort{ + Number: 8200, + }, + }, + } + } + + if vault.Spec.Ingress.Annotations == nil { + vault.Spec.Ingress.Annotations = map[string]string{} + } + + // If TLS is enabled add the Ingress TLS backend annotations + if !vault.Spec.IsTLSDisabled() { + // Supporting the NGINX ingress controller with TLS backends + // https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#backend-protocol + vault.Spec.Ingress.Annotations["nginx.ingress.kubernetes.io/backend-protocol"] = "HTTPS" + + // Supporting the Traefik ingress controller with TLS backends + // https://docs.traefik.io/configuration/backends/kubernetes/#tls-communication-between-traefik-and-backend-pods + vault.Spec.Ingress.Annotations["ingress.kubernetes.io/protocol"] = "https" + + // Supporting the HAProxy ingress controller with TLS backends + // https://github.com/jcmoraisjr/haproxy-ingress#secure-backend + vault.Spec.Ingress.Annotations["ingress.kubernetes.io/secure-backends"] = "true" + } + + return vault.Spec.Ingress + } + + return nil +} + +// LabelsForVault returns the labels for selecting the resources +// belonging to the given vault CR name. +func (vault *Vault) LabelsForVault() map[string]string { + return map[string]string{"app.kubernetes.io/name": "vault", "vault_cr": vault.Name} +} + +// LabelsForVaultConfigurer returns the labels for selecting the resources +// belonging to the given vault CR name. +func (vault *Vault) LabelsForVaultConfigurer() map[string]string { + return map[string]string{"app.kubernetes.io/name": "vault-configurator", "vault_cr": vault.Name} +} + +// AsOwnerReference returns this Vault instance as an OwnerReference +func (vault *Vault) AsOwnerReference() metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: vault.APIVersion, + Kind: vault.Kind, + Name: vault.Name, + UID: vault.UID, + Controller: pointer.Bool(true), + } +} + +// +kubebuilder:object:root=true + +// VaultList contains a list of Vault +type VaultList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Vault `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Vault{}, &VaultList{}) +} diff --git a/pkg/apis/vault/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/vault/v1alpha1/zz_generated.deepcopy.go index 6e5a3b48..061aa185 100644 --- a/pkg/apis/vault/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/vault/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Copyright © 2019 Banzai Cloud @@ -14,19 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 import ( - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSUnsealConfig) DeepCopyInto(out *AWSUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSUnsealConfig. @@ -42,7 +42,6 @@ func (in *AWSUnsealConfig) DeepCopy() *AWSUnsealConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AlibabaUnsealConfig) DeepCopyInto(out *AlibabaUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlibabaUnsealConfig. @@ -58,7 +57,6 @@ func (in *AlibabaUnsealConfig) DeepCopy() *AlibabaUnsealConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureUnsealConfig) DeepCopyInto(out *AzureUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureUnsealConfig. @@ -74,7 +72,6 @@ func (in *AzureUnsealConfig) DeepCopy() *AzureUnsealConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialsConfig) DeepCopyInto(out *CredentialsConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsConfig. @@ -104,7 +101,6 @@ func (in *EmbeddedObjectMetadata) DeepCopyInto(out *EmbeddedObjectMetadata) { (*out)[key] = val } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedObjectMetadata. @@ -123,7 +119,6 @@ func (in *EmbeddedPersistentVolumeClaim) DeepCopyInto(out *EmbeddedPersistentVol out.TypeMeta = in.TypeMeta in.EmbeddedObjectMetadata.DeepCopyInto(&out.EmbeddedObjectMetadata) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedPersistentVolumeClaim. @@ -272,7 +267,28 @@ func (in *EmbeddedPodSpec) DeepCopyInto(out *EmbeddedPodSpec) { *out = new(bool) **out = **in } - return + if in.OS != nil { + in, out := &in.OS, &out.OS + *out = new(v1.PodOS) + **out = **in + } + if in.HostUsers != nil { + in, out := &in.HostUsers, &out.HostUsers + *out = new(bool) + **out = **in + } + if in.SchedulingGates != nil { + in, out := &in.SchedulingGates, &out.SchedulingGates + *out = make([]v1.PodSchedulingGate, len(*in)) + copy(*out, *in) + } + if in.ResourceClaims != nil { + in, out := &in.ResourceClaims, &out.ResourceClaims + *out = make([]v1.PodResourceClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedPodSpec. @@ -288,7 +304,6 @@ func (in *EmbeddedPodSpec) DeepCopy() *EmbeddedPodSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GoogleUnsealConfig) DeepCopyInto(out *GoogleUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GoogleUnsealConfig. @@ -304,7 +319,6 @@ func (in *GoogleUnsealConfig) DeepCopy() *GoogleUnsealConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HSMUnsealConfig) DeepCopyInto(out *HSMUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HSMUnsealConfig. @@ -328,7 +342,6 @@ func (in *Ingress) DeepCopyInto(out *Ingress) { } } in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ingress. @@ -344,7 +357,6 @@ func (in *Ingress) DeepCopy() *Ingress { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubernetesUnsealConfig) DeepCopyInto(out *KubernetesUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesUnsealConfig. @@ -385,7 +397,6 @@ func (in *Resources) DeepCopyInto(out *Resources) { *out = new(v1.ResourceRequirements) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. @@ -433,7 +444,6 @@ func (in *UnsealConfig) DeepCopyInto(out *UnsealConfig) { *out = new(HSMUnsealConfig) **out = **in } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnsealConfig. @@ -459,7 +469,16 @@ func (in *UnsealOptions) DeepCopyInto(out *UnsealOptions) { *out = new(bool) **out = **in } - return + if in.SecretThreshold != nil { + in, out := &in.SecretThreshold, &out.SecretThreshold + *out = new(uint) + **out = **in + } + if in.SecretShares != nil { + in, out := &in.SecretShares, &out.SecretShares + *out = new(uint) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnsealOptions. @@ -479,7 +498,6 @@ func (in *Vault) DeepCopyInto(out *Vault) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Vault. @@ -512,7 +530,6 @@ func (in *VaultList) DeepCopyInto(out *VaultList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultList. @@ -723,7 +740,6 @@ func (in *VaultSpec) DeepCopyInto(out *VaultSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultSpec. @@ -749,7 +765,6 @@ func (in *VaultStatus) DeepCopyInto(out *VaultStatus) { *out = make([]v1.ComponentCondition, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultStatus. @@ -765,7 +780,6 @@ func (in *VaultStatus) DeepCopy() *VaultStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VaultUnsealConfig) DeepCopyInto(out *VaultUnsealConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultUnsealConfig. diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 67c7a04c..44c28dff 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -18,6 +18,7 @@ package versioned import ( "fmt" + "net/http" vaultv1alpha1 "github.com/bank-vaults/vault-operator/pkg/client/clientset/versioned/typed/vault/v1alpha1" discovery "k8s.io/client-go/discovery" @@ -30,8 +31,7 @@ type Interface interface { VaultV1alpha1() vaultv1alpha1.VaultV1alpha1Interface } -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. +// Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient vaultV1alpha1 *vaultv1alpha1.VaultV1alpha1Client @@ -53,22 +53,45 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { // NewForConfig creates a new Clientset for the given config. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.Burst <= 0 { return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") } configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } + var cs Clientset var err error - cs.vaultV1alpha1, err = vaultv1alpha1.NewForConfig(&configShallowCopy) + cs.vaultV1alpha1, err = vaultv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -78,11 +101,11 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // NewForConfigOrDie creates a new Clientset for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.vaultV1alpha1 = vaultv1alpha1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs } // New creates a new Clientset for the given RESTClient. diff --git a/pkg/client/clientset/versioned/doc.go b/pkg/client/clientset/versioned/doc.go deleted file mode 100644 index bdfff159..00000000 --- a/pkg/client/clientset/versioned/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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. - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 5ed3ca18..563651c2 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -72,7 +72,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } -var _ clientset.Interface = &Clientset{} +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) // VaultV1alpha1 retrieves the VaultV1alpha1Client func (c *Clientset) VaultV1alpha1() vaultv1alpha1.VaultV1alpha1Interface { diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 46cf7b41..47e06b78 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -35,14 +35,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 36632ee9..2fa6b3ff 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -35,14 +35,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/pkg/client/clientset/versioned/typed/vault/v1alpha1/fake/fake_vault.go b/pkg/client/clientset/versioned/typed/vault/v1alpha1/fake/fake_vault.go index 759391c2..89b73d69 100644 --- a/pkg/client/clientset/versioned/typed/vault/v1alpha1/fake/fake_vault.go +++ b/pkg/client/clientset/versioned/typed/vault/v1alpha1/fake/fake_vault.go @@ -22,7 +22,6 @@ import ( v1alpha1 "github.com/bank-vaults/vault-operator/pkg/apis/vault/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" @@ -34,9 +33,9 @@ type FakeVaults struct { ns string } -var vaultsResource = schema.GroupVersionResource{Group: "vault.banzaicloud.com", Version: "v1alpha1", Resource: "vaults"} +var vaultsResource = v1alpha1.SchemeGroupVersion.WithResource("vaults") -var vaultsKind = schema.GroupVersionKind{Group: "vault.banzaicloud.com", Version: "v1alpha1", Kind: "Vault"} +var vaultsKind = v1alpha1.SchemeGroupVersion.WithKind("Vault") // Get takes name of the vault, and returns the corresponding vault object, and an error if there is any. func (c *FakeVaults) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Vault, err error) { @@ -103,7 +102,7 @@ func (c *FakeVaults) Update(ctx context.Context, vault *v1alpha1.Vault, opts v1. // Delete takes name of the vault and deletes it. Returns an error if one occurs. func (c *FakeVaults) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(vaultsResource, c.ns, name), &v1alpha1.Vault{}) + Invokes(testing.NewDeleteActionWithOptions(vaultsResource, c.ns, name, opts), &v1alpha1.Vault{}) return err } diff --git a/pkg/client/clientset/versioned/typed/vault/v1alpha1/vault_client.go b/pkg/client/clientset/versioned/typed/vault/v1alpha1/vault_client.go index 7c96b05e..3febc580 100644 --- a/pkg/client/clientset/versioned/typed/vault/v1alpha1/vault_client.go +++ b/pkg/client/clientset/versioned/typed/vault/v1alpha1/vault_client.go @@ -17,6 +17,8 @@ package v1alpha1 import ( + "net/http" + v1alpha1 "github.com/bank-vaults/vault-operator/pkg/apis/vault/v1alpha1" "github.com/bank-vaults/vault-operator/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -27,7 +29,7 @@ type VaultV1alpha1Interface interface { VaultsGetter } -// VaultV1alpha1Client is used to interact with features provided by the vault.banzaicloud.com group. +// VaultV1alpha1Client is used to interact with features provided by the vault group. type VaultV1alpha1Client struct { restClient rest.Interface } @@ -37,12 +39,28 @@ func (c *VaultV1alpha1Client) Vaults(namespace string) VaultInterface { } // NewForConfig creates a new VaultV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*VaultV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new VaultV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*VaultV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index bcfaaf69..5dcdaa71 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -45,6 +45,11 @@ type sharedInformerFactory struct { // startedInformers is used for tracking which informers have been started. // This allows Start() to be called multiple times safely. startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool } // WithCustomResyncConfig sets a custom resync period for the specified informer types. @@ -105,20 +110,39 @@ func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResy return factory } -// Start initializes all requested informers. func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { f.lock.Lock() defer f.lock.Unlock() + if f.shuttingDown { + return + } + for informerType, informer := range f.informers { if !f.startedInformers[informerType] { - go informer.Run(stopCh) + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() f.startedInformers[informerType] = true } } } -// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { informers := func() map[reflect.Type]cache.SharedIndexInformer { f.lock.Lock() @@ -165,11 +189,58 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal // SharedInformerFactory provides shared informers for resources in all known // API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) type SharedInformerFactory interface { internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InternalInformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + Vault() vault.Interface } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 14fad615..ba8cd787 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -50,7 +50,7 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=vault.banzaicloud.com, Version=v1alpha1 + // Group=vault, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("vaults"): return &genericInformer{resource: resource.GroupResource(), informer: f.Vault().V1alpha1().Vaults().Informer()}, nil diff --git a/pkg/controller/add_vault.go b/pkg/controller/addtomanager_vault.go similarity index 100% rename from pkg/controller/add_vault.go rename to pkg/controller/addtomanager_vault.go diff --git a/pkg/controller/vault/suite_test.go b/pkg/controller/vault/suite_test.go new file mode 100644 index 00000000..7850d352 --- /dev/null +++ b/pkg/controller/vault/suite_test.go @@ -0,0 +1,77 @@ +// Copyright © 2019 Banzai Cloud +// +// 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 vault + +import ( + bankvaultsdevv1alpha1 "github.com/bank-vaults/vault-operator/pkg/apis/vault/v1alpha1" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = bankvaultsdevv1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + // +kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/pkg/controller/vault/vault_controller.go b/pkg/controller/vault/vault_controller.go index e50d2810..bccbe35b 100644 --- a/pkg/controller/vault/vault_controller.go +++ b/pkg/controller/vault/vault_controller.go @@ -59,9 +59,13 @@ import ( "sigs.k8s.io/controller-runtime/pkg/source" ) -var log = logf.Log.WithName("controller_vault") +const defaultConfigFile = "vault-config.yml" + +var ( + log = logf.Log.WithName("controller_vault") -var configFileNames = []string{"vault-config.yml", "vault-config.yaml"} + configFileNames = []string{"vault-config.yml", "vault-config.yaml"} +) // Add creates a new Vault Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. @@ -106,16 +110,22 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { var _ reconcile.Reconciler = &ReconcileVault{} +// +kubebuilder:rbac:groups="",namespace=default,resources=secrets,verbs=* +// +kubebuilder:rbac:groups="",namespace=default,resources=pods,verbs=get;update;patch + // ReconcileVault reconciles a Vault object type ReconcileVault struct { - // This client, initialized using mgr.Client() above, is a split client + // client initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver client client.Client - // since the cache inside the client is namespaced we need to create another client which is not namespaced + + // nonNamespacedClient since the cache inside the client is namespaced, + // we need to create another client which is not namespaced // TODO the cache should be restricted to Secrets only right now in this one if possible nonNamespacedClient client.Client - scheme *runtime.Scheme - httpClient *http.Client + + scheme *runtime.Scheme + httpClient *http.Client } func (r *ReconcileVault) createOrUpdateObject(ctx context.Context, o client.Object) error { @@ -973,8 +983,6 @@ func deprecatedConfigMapForConfigurer(v *vaultv1alpha1.Vault) *corev1.ConfigMap } } -const defaultConfigFile = "vault-config.yml" - func secretForConfigurer(v *vaultv1alpha1.Vault) *corev1.Secret { ls := v.LabelsForVaultConfigurer() return &corev1.Secret{ diff --git a/test/acceptance_test.go b/test/acceptance_test.go index 68eb1b82..e2aa3ba5 100644 --- a/test/acceptance_test.go +++ b/test/acceptance_test.go @@ -33,43 +33,53 @@ import ( "testing" "time" + "github.com/gruntwork-io/terratest/modules/helm" + "github.com/gruntwork-io/terratest/modules/k8s" + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/retry" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" - corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - - "github.com/gruntwork-io/terratest/modules/helm" - "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/gruntwork-io/terratest/modules/logger" - "github.com/gruntwork-io/terratest/modules/retry" ) var ( vaultVersion = "latest" - bankVaultsVersion = "1.19.0" // TODO: Make it work locally with latest + bankVaultsVersion = "latest" + operatorVersion = "latest" ) // Installing the operator helm chart before testing func TestMain(m *testing.M) { t := &testing.T{} - // Setting Vault version - if os.Getenv("VAULT_VERSION") != "" { - vaultVersion = os.Getenv("VAULT_VERSION") - } - // Setup Vault operator as a dependency for each test releaseName := "vault-operator" defaultKubectlOptions := k8s.NewKubectlOptions("", "", "default") - operatorVersion := "latest" + // Set Vault version + if v := os.Getenv("VAULT_VERSION"); v != "" { + vaultVersion = v + } + + // Set Bank vaults version + if v := os.Getenv("BANK_VAULTS_VERSION"); v != "" { + bankVaultsVersion = v + } + + // Set Operator version if v := os.Getenv("OPERATOR_VERSION"); v != "" { operatorVersion = v } + // Set Helm chart + chart := "../deploy/charts/vault-operator" + if v := os.Getenv("HELM_CHART"); v != "" { + chart = v + } + // Setup args for helm. helmOptions := &helm.Options{ KubectlOptions: defaultKubectlOptions, @@ -80,36 +90,34 @@ func TestMain(m *testing.M) { }, } - chart := "../deploy/charts/vault-operator" - if v := os.Getenv("HELM_CHART"); v != "" { - chart = v - } - // Deploy the chart using `helm install` and wait until the pod comes up helm.Install(t, helmOptions, chart, releaseName) + defer helm.Delete(t, helmOptions, releaseName, true) + operatorPods := waitUntilPodsCreated(t, defaultKubectlOptions, releaseName, 10, 5*time.Second) k8s.WaitUntilPodAvailable(t, defaultKubectlOptions, operatorPods[0].GetName(), 5, 10*time.Second) clientset, err := k8s.GetKubernetesClientFromOptionsE(t, defaultKubectlOptions) - _, err = clientset.RbacV1().ClusterRoleBindings().Create(context.Background(), &v1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "vault-auth-delegator", - }, - Subjects: []v1.Subject{}, - RoleRef: v1.RoleRef{ - Kind: "ClusterRole", - Name: "system:auth-delegator", + _, err = clientset.RbacV1().ClusterRoleBindings().Create( + context.Background(), + &v1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vault-auth-delegator", + }, + Subjects: []v1.Subject{}, + RoleRef: v1.RoleRef{ + Kind: "ClusterRole", + Name: "system:auth-delegator", + }, }, - }, metav1.CreateOptions{}) + metav1.CreateOptions{}, + ) require.NoError(t, err) + defer clientset.RbacV1().ClusterRoleBindings().Delete(context.Background(), "vault-auth-delegator", metav1.DeleteOptions{}) // Run tests exitCode := m.Run() - // Tear down dependencies - helm.Delete(t, helmOptions, releaseName, true) - clientset.RbacV1().ClusterRoleBindings().Delete(context.Background(), "vault-auth-delegator", metav1.DeleteOptions{}) - // Exit based on the test results os.Exit(exitCode) } @@ -117,20 +125,14 @@ func TestMain(m *testing.M) { func TestKvv2(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "kvv2", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-kvv2.yaml", + kubectlOptions := prepareEnv(t, + "kvv2", + []string{ + "rbac.yaml", + "../deploy/examples/cr-kvv2.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -139,20 +141,14 @@ func TestKvv2(t *testing.T) { func TestStatsd(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "statsd", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-statsd.yaml", + kubectlOptions := prepareEnv(t, + "statsd", + []string{ + "rbac.yaml", + "../deploy/examples/cr-statsd.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -161,20 +157,14 @@ func TestStatsd(t *testing.T) { func TestExternalSecretsWatcherDeployment(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "external-secrets-watcher-deployment", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "deploy/test-external-secrets-watch-deployment.yaml", - "../deploy/default/rbac.yaml", + kubectlOptions := prepareEnv(t, + "external-secrets-watcher-deployment", + []string{ + "rbac.yaml", + "deploy/test-external-secrets-watch-deployment.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -186,23 +176,15 @@ func TestExternalSecretsWatcherDeployment(t *testing.T) { func TestExternalSecretsWatcherSecrets(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "external-secrets-watcher-secrets", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - - // Applying secrets to be watched - k8s.KubectlApply(t, kubectlOptions, "deploy/test-external-secrets-watch-secrets.yaml") - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "deploy/test-external-secrets-watch-deployment.yaml", - "../deploy/default/rbac.yaml", + kubectlOptions := prepareEnv(t, + "external-secrets-watcher-secrets", + []string{ + "rbac.yaml", + "deploy/test-external-secrets-watch-secrets.yaml", + "deploy/test-external-secrets-watch-deployment.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -218,20 +200,14 @@ func TestExternalSecretsWatcherSecrets(t *testing.T) { func TestRaft(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "raft", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-raft.yaml", + kubectlOptions := prepareEnv(t, + "raft", + []string{ + "rbac.yaml", + "../deploy/examples/cr-raft.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until all vault pods come up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -242,20 +218,14 @@ func TestRaft(t *testing.T) { func TestSoftHSM(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "softhsm", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-hsm-softhsm.yaml", + kubectlOptions := prepareEnv(t, + "softhsm", + []string{ + "rbac.yaml", + "../deploy/examples/cr-hsm-softhsm.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -264,26 +234,20 @@ func TestSoftHSM(t *testing.T) { func TestDisabledRootTokenStorage(t *testing.T) { // t.Parallel() - kubectlOptions := prepareNamespace(t, "disabled-root-token-storage", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-disabled-root-token-storage.yaml", + kubectlOptions := prepareEnv(t, + "disabled-root-token-storage", + []string{ + "rbac.yaml", + "../deploy/examples/cr-disabled-root-token-storage.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) // Check that the vault-root secret is not created - _, err = k8s.GetSecretE(t, kubectlOptions, "vault-root") + _, err := k8s.GetSecretE(t, kubectlOptions, "vault-root") require.Errorf(t, err, `secrets "vault-root" not found`) } @@ -293,8 +257,14 @@ func TestPriorityClass(t *testing.T) { // TODO: Disable test for now until examples are fixed return - kubectlOptions := prepareNamespace(t, "priority-class", vaultVersion) - defer k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) + // Prepare and apply resources + kubectlOptions := prepareEnv(t, + "priority-class", + []string{ + "rbac.yaml", + "../deploy/examples/cr-priority.yaml", + }, + ) // Add ServiceAccount to ClusterRoleBinding clientset, err := k8s.GetKubernetesClientFromOptionsE(t, kubectlOptions) @@ -307,18 +277,6 @@ func TestPriorityClass(t *testing.T) { _, err = clientset.RbacV1().ClusterRoleBindings().Update(context.Background(), crb, metav1.UpdateOptions{}) require.NoError(t, err) - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-priority.yaml", - ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } - // Wait until vault-0 pod comes up healthy and secrets are populated k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) time.Sleep(10 * time.Second) @@ -338,20 +296,14 @@ func TestOIDC(t *testing.T) { // TODO: Disable test for now until examples are fixed return - // Use the default namespace for this test - kubectlOptions := k8s.NewKubectlOptions("", "", "default") - // Prepare and apply resources - resources, err := prepareResources( - kubectlOptions.Namespace, - vaultVersion, - "../deploy/default/rbac.yaml", - "../deploy/examples/cr-oidc.yaml", + kubectlOptions := prepareEnv(t, + "default", + []string{ + "rbac.yaml", + "../deploy/examples/cr-oidc.yaml", + }, ) - require.NoError(t, err) - for _, resource := range resources { - k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) - } // Wait until vault-0 pod comes up healthy k8s.WaitUntilPodAvailable(t, kubectlOptions, "vault-0", 60, 10*time.Second) @@ -370,30 +322,23 @@ func TestOIDC(t *testing.T) { k8s.KubectlDelete(t, kubectlOptions, oidcPodFilePath) } -func prepareNamespace(t *testing.T, testName string, vaultVersion string) *k8s.KubectlOptions { - // Replace . with - in vaultVersion string - vaultVersion = strings.ReplaceAll(vaultVersion, ".", "-") - +// Installs k8s and kustomize components from configuration +func prepareEnv(t *testing.T, testName string, k8sRes []string) *k8s.KubectlOptions { // Setup a unique namespace for the resources for this test. - namespaceName := fmt.Sprintf("test-%s-vault-%s", testName, vaultVersion) + namespaceName := fmt.Sprintf("test-%s-vault-%s", testName, strings.ReplaceAll(vaultVersion, ".", "-")) // Setup the kubectl config (default HOME/.kube/config) and the default current context. kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName) - // Create namespace - k8s.CreateNamespace(t, kubectlOptions, namespaceName) - - return kubectlOptions -} + // Prepare namespace + prepareNamespace(t, namespaceName, kubectlOptions) -// Insert namespace name into resource definitions to be applied -func prepareResources(namespaceName string, vaultVersion string, crds ...string) ([][]byte, error) { // Reading files into byte slices var files [][]byte - for _, crd := range crds { + for _, crd := range k8sRes { data, err := os.ReadFile(crd) if err != nil { - return nil, err + t.Fatal(err) } files = append(files, data) } @@ -410,14 +355,13 @@ func prepareResources(namespaceName string, vaultVersion string, crds ...string) break } if err != nil { - return nil, err + t.Fatal(err) } documents = append(documents, v) } } // Iterate on yaml documents and change namespace name where necessary - var resources [][]byte for _, v := range documents { if v.(map[string]interface{})["kind"] == "Vault" { if i, ok := v.(map[string]interface{})["spec"].(map[string]interface{}); ok { @@ -455,12 +399,20 @@ func prepareResources(namespaceName string, vaultVersion string, crds ...string) resource, err := yaml.Marshal(v) if err != nil { - return nil, err + t.Fatal(err) } - resources = append(resources, resource) + k8s.KubectlApplyFromString(t, kubectlOptions, string(resource)) } - return resources, nil + + return kubectlOptions +} + +func prepareNamespace(t *testing.T, namespaceName string, kubectlOptions *k8s.KubectlOptions) { + k8s.CreateNamespace(t, kubectlOptions, namespaceName) + t.Cleanup(func() { + k8s.DeleteNamespace(t, kubectlOptions, kubectlOptions.Namespace) + }) } func executeShellCommand(command string) (string, string, error) {