diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index a310f3eeed..ae4d24d122 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -1,15 +1,20 @@ name: CodeQL on: + pull_request: push: branches: - - master + - main schedule: - cron: '10 18 * * 2' +env: + # Use the Go toolchain installed by setup-go + # https://github.com/actions/setup-go/issues/457 + GOTOOLCHAIN: local + jobs: analyze: - name: Analyze runs-on: ubuntu-latest permissions: actions: read diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index af302e7638..c715f2a1d7 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -2,8 +2,11 @@ name: Linters on: pull_request: - branches: - - master + +env: + # Use the Go toolchain installed by setup-go + # https://github.com/actions/setup-go/issues/457 + GOTOOLCHAIN: local jobs: golangci-lint: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index aef10d7694..e8174e4f95 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,11 +2,14 @@ name: Tests on: pull_request: - branches: - - master push: branches: - - master + - main + +env: + # Use the Go toolchain installed by setup-go + # https://github.com/actions/setup-go/issues/457 + GOTOOLCHAIN: local jobs: go-test: @@ -36,7 +39,6 @@ jobs: - run: ENVTEST_K8S_VERSION="${KUBERNETES#default}" make check-envtest env: KUBERNETES: "${{ matrix.kubernetes }}" - GOEXPERIMENT: nocoverageredesign # https://go.dev/issue/65653 GO_TEST: go test --coverprofile 'envtest.coverage' --coverpkg ./internal/... # Upload coverage to GitHub @@ -54,7 +56,7 @@ jobs: strategy: fail-fast: false matrix: - kubernetes: [v1.30, v1.25] + kubernetes: [v1.31, v1.28] steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 @@ -65,14 +67,13 @@ jobs: with: k3s-channel: "${{ matrix.kubernetes }}" prefetch-images: | - registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.51-1 - registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.22-1 - registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-15.7-1 + registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.53.1-0 + registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.23-0 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.4-2 - run: make createnamespaces check-envtest-existing env: PGO_TEST_TIMEOUT_SCALE: 1.2 - GOEXPERIMENT: nocoverageredesign # https://go.dev/issue/65653 GO_TEST: go test --coverprofile 'envtest-existing.coverage' --coverpkg ./internal/... # Upload coverage to GitHub @@ -89,7 +90,7 @@ jobs: strategy: fail-fast: false matrix: - kubernetes: [v1.29, v1.28, v1.27, v1.26, v1.25] + kubernetes: [v1.31, v1.30, v1.29, v1.28] steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 @@ -100,16 +101,16 @@ jobs: with: k3s-channel: "${{ matrix.kubernetes }}" prefetch-images: | - registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-26 - registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.51-1 - registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.22-1 + registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-31 + registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.53.1-0 + registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.23-0 registry.developers.crunchydata.com/crunchydata/crunchy-postgres-exporter:latest registry.developers.crunchydata.com/crunchydata/crunchy-upgrade:latest - registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-15.7-1 - registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-15.7-3.3-1 - registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1 - registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.3-1 - registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.4-1 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.4-2 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.3-2 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.4-2 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-17.0-0 + registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-17.0-3.4-0 - run: go mod download - name: Build executable run: PGO_VERSION='${{ github.sha }}' make build-postgres-operator @@ -118,7 +119,7 @@ jobs: run: make get-pgmonitor env: PGMONITOR_DIR: "${{ github.workspace }}/hack/tools/pgmonitor" - QUERIES_CONFIG_DIR: "${{ github.workspace }}/hack/tools/queries" + QUERIES_CONFIG_DIR: "${{ github.workspace }}/hack/tools/queries" # Start a Docker container with the working directory mounted. - name: Start PGO @@ -128,19 +129,20 @@ jobs: hack/create-kubeconfig.sh postgres-operator pgo docker run --detach --network host --read-only \ --volume "$(pwd):/mnt" --workdir '/mnt' --env 'PATH=/mnt/bin' \ + --env 'CHECK_FOR_UPGRADES=false' \ --env 'QUERIES_CONFIG_DIR=/mnt/hack/tools/queries' \ --env 'KUBECONFIG=hack/.kube/postgres-operator/pgo' \ - --env 'RELATED_IMAGE_PGADMIN=registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-26' \ - --env 'RELATED_IMAGE_PGBACKREST=registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.51-1' \ - --env 'RELATED_IMAGE_PGBOUNCER=registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.22-1' \ + --env 'RELATED_IMAGE_PGADMIN=registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-31' \ + --env 'RELATED_IMAGE_PGBACKREST=registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.53.1-0' \ + --env 'RELATED_IMAGE_PGBOUNCER=registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.23-0' \ --env 'RELATED_IMAGE_PGEXPORTER=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-exporter:latest' \ --env 'RELATED_IMAGE_PGUPGRADE=registry.developers.crunchydata.com/crunchydata/crunchy-upgrade:latest' \ - --env 'RELATED_IMAGE_POSTGRES_15=registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-15.7-1' \ - --env 'RELATED_IMAGE_POSTGRES_15_GIS_3.3=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-15.7-3.3-1' \ - --env 'RELATED_IMAGE_POSTGRES_16=registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1' \ - --env 'RELATED_IMAGE_POSTGRES_16_GIS_3.3=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.3-1' \ - --env 'RELATED_IMAGE_POSTGRES_16_GIS_3.4=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.4-1' \ - --env 'RELATED_IMAGE_STANDALONE_PGADMIN=registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-8.6-1' \ + --env 'RELATED_IMAGE_POSTGRES_16=registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.4-2' \ + --env 'RELATED_IMAGE_POSTGRES_16_GIS_3.3=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.3-2' \ + --env 'RELATED_IMAGE_POSTGRES_16_GIS_3.4=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.4-2' \ + --env 'RELATED_IMAGE_POSTGRES_17=registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-17.0-0' \ + --env 'RELATED_IMAGE_POSTGRES_17_GIS_3.4=registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-17.0-3.4-0' \ + --env 'RELATED_IMAGE_STANDALONE_PGADMIN=registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-8.12-0' \ --env 'PGO_FEATURE_GATES=TablespaceVolumes=true' \ --name 'postgres-operator' ubuntu \ postgres-operator @@ -151,11 +153,11 @@ jobs: - run: make generate-kuttl env: - KUTTL_PG_UPGRADE_FROM_VERSION: '15' - KUTTL_PG_UPGRADE_TO_VERSION: '16' - KUTTL_PG_VERSION: '15' + KUTTL_PG_UPGRADE_FROM_VERSION: '16' + KUTTL_PG_UPGRADE_TO_VERSION: '17' + KUTTL_PG_VERSION: '16' KUTTL_POSTGIS_VERSION: '3.4' - KUTTL_PSQL_IMAGE: 'registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1' + KUTTL_PSQL_IMAGE: 'registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.4-2' - run: | make check-kuttl && exit failed=$? diff --git a/.github/workflows/trivy-pr-scan.yaml b/.github/workflows/trivy.yaml similarity index 60% rename from .github/workflows/trivy-pr-scan.yaml rename to .github/workflows/trivy.yaml index 2d1ab30fd1..2a16e4929c 100644 --- a/.github/workflows/trivy-pr-scan.yaml +++ b/.github/workflows/trivy.yaml @@ -1,17 +1,38 @@ -# Uses Trivy to scan every pull request, rejecting those with severe, fixable vulnerabilities. -# Scans on PR to master and weekly with same behavior. name: Trivy on: pull_request: - branches: - - master push: branches: - - master + - main + +env: + # Use the Go toolchain installed by setup-go + # https://github.com/actions/setup-go/issues/457 + GOTOOLCHAIN: local jobs: - scan: + licenses: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Trivy needs a populated Go module cache to detect Go module licenses. + - uses: actions/setup-go@v5 + with: { go-version: stable } + - run: go mod download + + # Report success only when detected licenses are listed in [/trivy.yaml]. + - name: Scan licenses + uses: aquasecurity/trivy-action@0.28.0 + env: + TRIVY_DEBUG: true + with: + scan-type: filesystem + scanners: license + exit-code: 1 + + vulnerabilities: if: ${{ github.repository == 'CrunchyData/postgres-operator' }} permissions: @@ -28,23 +49,25 @@ jobs: # and is a convenience/redundant effort for those who prefer to # read logs and/or if anything goes wrong with the upload. - name: Log all detected vulnerabilities - uses: aquasecurity/trivy-action@master + uses: aquasecurity/trivy-action@0.28.0 with: - scan-type: fs + scan-type: filesystem hide-progress: true ignore-unfixed: true - + scanners: secret,vuln + # Upload actionable results to the GitHub Security tab. # Pull request checks fail according to repository settings. # - https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github # - https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning - name: Report actionable vulnerabilities - uses: aquasecurity/trivy-action@master + uses: aquasecurity/trivy-action@0.28.0 with: - scan-type: fs + scan-type: filesystem ignore-unfixed: true format: 'sarif' output: 'trivy-results.sarif' + scanners: secret,vuln - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 diff --git a/.golangci.yaml b/.golangci.yaml index 9d712da889..87a6ed0464 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -8,6 +8,7 @@ linters: - gofumpt enable: - depguard + - goheader - gomodguard - gosimple - importas @@ -43,6 +44,15 @@ linters-settings: exhaustive: default-signifies-exhaustive: true + goheader: + template: |- + Copyright {{ DATES }} Crunchy Data Solutions, Inc. + + SPDX-License-Identifier: Apache-2.0 + values: + regexp: + DATES: '((201[7-9]|202[0-3]) - 2024|2024)' + goimports: local-prefixes: github.com/crunchydata/postgres-operator diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 278beaffb1..e209f4e5a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,15 +13,11 @@ Thanks! We look forward to your contribution. # General Contributing Guidelines All ongoing development for an upcoming release gets committed to the -**`master`** branch. The `master` branch technically serves as the "development" -branch as well, but all code that is committed to the `master` branch should be +**`main`** branch. The `main` branch technically serves as the "development" +branch as well, but all code that is committed to the `main` branch should be considered _stable_, even if it is part of an ongoing release cycle. -All fixes for a supported release should be committed to the supported release -branch. For example, the 4.3 release is maintained on the `REL_4_3` branch. -Please see the section on _Supported Releases_ for more information. - -Ensure any changes are clear and well-documented. When we say "well-documented": +Ensure any changes are clear and well-documented: - If the changes include code, ensure all additional code has corresponding documentation in and around it. This includes documenting the definition of @@ -32,10 +28,7 @@ summarize how. Avoid simply repeating details from declarations,. When in doubt, favor overexplaining to underexplaining. - Code comments should be consistent with their language conventions. For -example, please use GoDoc conventions for Go source code. - -- Any new features must have corresponding user documentation. Any removed -features must have their user documentation removed from the documents. +example, please use `gofmt` [conventions](https://go.dev/doc/comment) for Go source code. - Do not submit commented-out code. If the code does not need to be used anymore, please remove it. @@ -62,12 +55,7 @@ All commits must either be rebased in atomic order or squashed (if the squashed commit is considered atomic). Merge commits are not accepted. All conflicts must be resolved prior to pushing changes. -**All pull requests should be made from the `master` branch** unless it is a fix -for a specific supported release. - -Once a major or minor release is made, no new features are added into the -release branch, only bug fixes. Any new features are added to the `master` -branch until the time that said new features are released. +**All pull requests should be made from the `main` branch.** # Commit Messages @@ -90,8 +78,7 @@ If you wish to tag a GitHub issue or another project management tracker, please do so at the bottom of the commit message, and make it clearly labeled like so: ``` -Issue: #123 -Issue: [sc-1234] +Issue: CrunchyData/postgres-operator#123 ``` # Submitting Pull Requests @@ -100,102 +87,23 @@ All work should be made in your own repository fork. When you believe your work is ready to be committed, please follow the guidance below for creating a pull request. -## Upcoming Releases / Features - -Ongoing work for new features should occur in branches off of the `master` -branch. It is suggested, but not required, that the branch name should reflect -that this is for an upcoming release, i.e. `upstream/branch-name` where the -`branch-name` is something descriptive for what you're working on. - -## Supported Releases / Fixes - -While not required, it is recommended to make your branch name along the lines -of: `REL_X_Y/branch-name` where the `branch-name` is something descriptive -for what you're working on. - -# Releases & Versioning - -Overall, release tags attempt to follow the -[semantic versioning](https://semver.org) scheme. - -"Supported releases" (described in the next section) occur on "minor" release -branches (e.g. the `x.y` portion of the `x.y.z`). - -One or more "patch" releases can occur after a minor release. A patch release is -used to fix bugs and other issues that may be found after a supported release. - -Fixes found on the `master` branch can be backported to a support release -branch. Any fixes for a supported release must have a pull request off of the -supported release branch, which is detailed below. - -## Supported Releases +## Upcoming Features -When a "minor" release is made, the release is stamped using the `vx.y.0` format -as denoted above, and a branch is created with the name `REL_X_Y`. Once a -minor release occurs, no new features are added to the `REL_X_Y` branch. -However, bug fixes can (and if found, should) be added to this branch. +Ongoing work for new features should occur in branches off of the `main` +branch. -To contribute a bug fix to a supported release, please make a pull request off -of the supported release branch. For instance, if you find a bug in the 4.3 -release, then you would make a pull request off of the `REL_4_3` branch. +## Unsupported Branches -## Unsupported Releases - -When a release is no longer supported, the branch will be renamed following the +When a release branch is no longer supported, it will be renamed following the pattern `REL_X_Y_FINAL` with the key suffix being _FINAL_. For example, `REL_3_2_FINAL` indicates that the 3.2 release is no longer supported. Nothing should ever be pushed to a `REL_X_Y_FINAL` branch once `FINAL` is on the branch name. -## Alpha, Beta, Release Candidate Releases - -At any point in the release cycle for a new release, there could exist one or -more alpha, beta, or release candidate (RC) release. Alpha, beta, and release -candidates **should not be used in production environments**. - -Alpha is the early stage of a release cycle and is typically made to test the -mechanics of an upcoming release. These should be considered relatively -unstable. The format for an alpha release tag is `v4.3.0-alpha.1`, which in this -case indicates it is the first alpha release for 4.3. - -Beta occurs during the later stage of a release cycle. At this point, the -release should be considered feature complete and the beta is used to -distribute, test, and collect feedback on the upcoming release. The betas should -be considered unstable, but as mentioned feature complete. The format for an -beta release tag is `v4.3.0-beta.1`, which in this case indicates it is the -first beta release for 4.3. - -Release candidates (RCs) occur just before a release. A release candidate should -be considered stable, and is typically used for a final round of bug checking -and testing. Multiple release candidates can occur in the event of serious bugs. -The format for a release candidate tag is `v4.3.0-rc.1`, which in this -case indicates it is the first release candidate for 4.3. - -**After a major or minor release, no alpha, beta, or release candidate releases -are supported**. In fact, any newer release of an alpha, beta, or RC immediately -deprecates any older alpha, beta or RC. (Naturally, a beta deprecates an alpha, -and a RC deprecates a beta). - -If you are testing on an older alpha, beta or RC, bug reports will not be -accepted. Please ensure you are testing on the latest version. - # Testing -We greatly appreciate any and all testing for the project. When testing, please -be sure you do the following: - -- If testing against a release, ensure your tests are performed against the -latest minor version (the last number in the release denotes the minor version, -e.g. the "3" in the 4.3.3) -- If testing against a pre-release (alpha, beta, RC), ensure your tests are -performed against latest version -- If testing against a development (`master`) or release (`REL_X_Y`) branch, -ensure your tests are performed against the latest commit - -Please do not test against unsupported versions (e.g. any release that is marked -final). - +We greatly appreciate any and all testing for the project. There are several ways to help with the testing effort: - Manual testing: testing particular features with a series of manual commands diff --git a/Makefile b/Makefile index b6e09d05d0..37aca1a37e 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ PGO_IMAGE_URL ?= https://www.crunchydata.com/products/crunchy-postgresql-for-kub PGO_IMAGE_PREFIX ?= localhost PGMONITOR_DIR ?= hack/tools/pgmonitor -PGMONITOR_VERSION ?= v4.11.0 +PGMONITOR_VERSION ?= v5.1.1 QUERIES_CONFIG_DIR ?= hack/tools/queries EXTERNAL_SNAPSHOTTER_DIR ?= hack/tools/external-snapshotter @@ -65,11 +65,9 @@ get-external-snapshotter: clean: ## Clean resources clean: clean-deprecated rm -f bin/postgres-operator - rm -f config/rbac/role.yaml rm -rf licenses/*/ [ ! -d testing/kuttl/e2e-generated ] || rm -r testing/kuttl/e2e-generated [ ! -d testing/kuttl/e2e-generated-other ] || rm -r testing/kuttl/e2e-generated-other - rm -rf build/crd/generated build/crd/*/generated [ ! -f hack/tools/setup-envtest ] || rm hack/tools/setup-envtest [ ! -d hack/tools/envtest ] || { chmod -R u+w hack/tools/envtest && rm -r hack/tools/envtest; } [ ! -d hack/tools/pgmonitor ] || rm -rf hack/tools/pgmonitor @@ -94,6 +92,8 @@ clean-deprecated: ## Clean deprecated resources @# crunchy-postgres-exporter used to live in this repo [ ! -d bin/crunchy-postgres-exporter ] || rm -r bin/crunchy-postgres-exporter [ ! -d build/crunchy-postgres-exporter ] || rm -r build/crunchy-postgres-exporter + @# CRDs used to require patching + [ ! -d build/crd ] || rm -r build/crd ##@ Deployment @@ -136,6 +136,9 @@ deploy-dev: createnamespaces CHECK_FOR_UPGRADES='$(if $(CHECK_FOR_UPGRADES),$(CHECK_FOR_UPGRADES),false)' \ KUBECONFIG=hack/.kube/postgres-operator/pgo \ PGO_NAMESPACE='postgres-operator' \ + PGO_INSTALLER='deploy-dev' \ + PGO_INSTALLER_ORIGIN='postgres-operator-repo' \ + BUILD_SOURCE='build-postgres-operator' \ $(shell kubectl kustomize ./config/dev | \ sed -ne '/^kind: Deployment/,/^---/ { \ /RELATED_IMAGE_/ { N; s,.*\(RELATED_[^[:space:]]*\).*value:[[:space:]]*\([^[:space:]]*\),\1="\2",; p; }; \ @@ -276,27 +279,7 @@ generate-crd: tools/controller-gen $(CONTROLLER) \ crd:crdVersions='v1' \ paths='./pkg/apis/...' \ - output:dir='build/crd/postgresclusters/generated' # build/crd/{plural}/generated/{group}_{plural}.yaml - @ - $(CONTROLLER) \ - crd:crdVersions='v1' \ - paths='./pkg/apis/...' \ - output:dir='build/crd/pgupgrades/generated' # build/crd/{plural}/generated/{group}_{plural}.yaml - @ - $(CONTROLLER) \ - crd:crdVersions='v1' \ - paths='./pkg/apis/...' \ - output:dir='build/crd/pgadmins/generated' # build/crd/{plural}/generated/{group}_{plural}.yaml - @ - $(CONTROLLER) \ - crd:crdVersions='v1' \ - paths='./pkg/apis/...' \ - output:dir='build/crd/crunchybridgeclusters/generated' # build/crd/{plural}/generated/{group}_{plural}.yaml - @ - kubectl kustomize ./build/crd/postgresclusters > ./config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml - kubectl kustomize ./build/crd/pgupgrades > ./config/crd/bases/postgres-operator.crunchydata.com_pgupgrades.yaml - kubectl kustomize ./build/crd/pgadmins > ./config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml - kubectl kustomize ./build/crd/crunchybridgeclusters > ./config/crd/bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml + output:dir='config/crd/bases' # {directory}/{group}_{plural}.yaml .PHONY: generate-deepcopy generate-deepcopy: ## Generate DeepCopy functions @@ -309,10 +292,9 @@ generate-deepcopy: tools/controller-gen generate-rbac: ## Generate RBAC generate-rbac: tools/controller-gen $(CONTROLLER) \ - rbac:roleName='generated' \ + rbac:roleName='postgres-operator' \ paths='./cmd/...' paths='./internal/...' \ - output:dir='config/rbac' # ${directory}/role.yaml - ./hack/generate-rbac.sh 'config/rbac' + output:dir='config/rbac' # {directory}/role.yaml ##@ Tools @@ -327,7 +309,7 @@ endef CONTROLLER ?= hack/tools/controller-gen tools: tools/controller-gen tools/controller-gen: - $(call go-get-tool,$(CONTROLLER),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.15.0) + $(call go-get-tool,$(CONTROLLER),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.4) ENVTEST ?= hack/tools/setup-envtest tools: tools/setup-envtest diff --git a/README.md b/README.md index 5a09aaad55..357734566e 100644 --- a/README.md +++ b/README.md @@ -185,22 +185,18 @@ In addition to the above, the geospatially enhanced PostgreSQL + PostGIS contain For more information about which versions of the PostgreSQL Operator include which components, please visit the [compatibility](https://access.crunchydata.com/documentation/postgres-operator/v5/references/components/) section of the documentation. -## Supported Platforms +## [Supported Platforms](https://access.crunchydata.com/documentation/postgres-operator/latest/overview/supported-platforms) PGO, the Postgres Operator from Crunchy Data, is tested on the following platforms: -- Kubernetes 1.25-1.30 -- OpenShift 4.12-4.16 +- Kubernetes +- OpenShift - Rancher - Google Kubernetes Engine (GKE), including Anthos - Amazon EKS - Microsoft AKS - VMware Tanzu -This list only includes the platforms that the Postgres Operator is specifically -tested on as part of the release process: PGO works on other Kubernetes -distributions as well. - # Contributing to the Project Want to contribute to the PostgreSQL Operator project? Great! We've put together @@ -214,7 +210,7 @@ Once you are ready to submit a Pull Request, please ensure you do the following: that you have followed the commit message format, added testing where appropriate, documented your changes, etc. 1. Open up a pull request based upon the guidelines. If you are adding a new - feature, please open up the pull request on the `master` branch. + feature, please open up the pull request on the `main` branch. 1. Please be as descriptive in your pull request as possible. If you are referencing an issue, please be sure to include the issue in your pull request diff --git a/build/crd/.gitignore b/build/crd/.gitignore deleted file mode 100644 index 83ad9d9191..0000000000 --- a/build/crd/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/crunchybridgeclusters/generated/ -/postgresclusters/generated/ -/pgupgrades/generated/ -/pgadmins/generated/ diff --git a/build/crd/crunchybridgeclusters/kustomization.yaml b/build/crd/crunchybridgeclusters/kustomization.yaml deleted file mode 100644 index 26454f3b07..0000000000 --- a/build/crd/crunchybridgeclusters/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- generated/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml - -patches: -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: crunchybridgeclusters.postgres-operator.crunchydata.com -# The version below should match the version on the PostgresCluster CRD - patch: |- - - op: add - path: "/metadata/labels" - value: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest diff --git a/build/crd/pgadmins/kustomization.yaml b/build/crd/pgadmins/kustomization.yaml deleted file mode 100644 index ca67fb89fa..0000000000 --- a/build/crd/pgadmins/kustomization.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- generated/postgres-operator.crunchydata.com_pgadmins.yaml - -patches: -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: pgadmins.postgres-operator.crunchydata.com - path: todos.yaml -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: pgadmins.postgres-operator.crunchydata.com -# The version below should match the version on the PostgresCluster CRD - patch: |- - - op: add - path: "/metadata/labels" - value: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest diff --git a/build/crd/pgadmins/todos.yaml b/build/crd/pgadmins/todos.yaml deleted file mode 100644 index 5412d0ad21..0000000000 --- a/build/crd/pgadmins/todos.yaml +++ /dev/null @@ -1,23 +0,0 @@ -- op: add - path: /work - value: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/imagePullSecrets/items/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/files/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/files/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/ldapBindPassword/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/users/items/properties/passwordRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/configDatabaseURI/properties/name/description -- op: remove - path: /work diff --git a/build/crd/pgupgrades/kustomization.yaml b/build/crd/pgupgrades/kustomization.yaml deleted file mode 100644 index 260b7e42cd..0000000000 --- a/build/crd/pgupgrades/kustomization.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- generated/postgres-operator.crunchydata.com_pgupgrades.yaml - -patches: -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: pgupgrades.postgres-operator.crunchydata.com - path: todos.yaml -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: pgupgrades.postgres-operator.crunchydata.com -# The version below should match the version on the PostgresCluster CRD - patch: |- - - op: add - path: "/metadata/labels" - value: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest diff --git a/build/crd/pgupgrades/todos.yaml b/build/crd/pgupgrades/todos.yaml deleted file mode 100644 index c0d2202859..0000000000 --- a/build/crd/pgupgrades/todos.yaml +++ /dev/null @@ -1,8 +0,0 @@ -- op: add - path: /work - value: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/imagePullSecrets/items/properties/name/description -- op: remove - path: /work diff --git a/build/crd/postgresclusters/condition.yaml b/build/crd/postgresclusters/condition.yaml deleted file mode 100644 index 577787b520..0000000000 --- a/build/crd/postgresclusters/condition.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# PostgresCluster "v1beta1" is in "/spec/versions/0" - -- op: add - path: /spec/versions/0/schema/openAPIV3Schema/properties/status/properties/conditions/items/description - value: Condition contains details for one aspect of the current state of this API Resource. -- op: add - path: /spec/versions/0/schema/openAPIV3Schema/properties/status/properties/conditions/items/properties/type/description - value: type of condition in CamelCase. -- op: add - path: "/spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/containers/items\ - /properties/securityContext/properties/seccompProfile/properties/type/description" - value: >- - type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. -- op: add - path: "/spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties\ - /containers/items/properties/securityContext/properties/seccompProfile/properties/type/description" - value: >- - type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. diff --git a/build/crd/postgresclusters/kustomization.yaml b/build/crd/postgresclusters/kustomization.yaml deleted file mode 100644 index eb8cb6540f..0000000000 --- a/build/crd/postgresclusters/kustomization.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- generated/postgres-operator.crunchydata.com_postgresclusters.yaml - -patchesJson6902: -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: postgresclusters.postgres-operator.crunchydata.com - path: condition.yaml -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: postgresclusters.postgres-operator.crunchydata.com - path: todos.yaml -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: postgresclusters.postgres-operator.crunchydata.com - path: validation.yaml -- target: - group: apiextensions.k8s.io - version: v1 - kind: CustomResourceDefinition - name: postgresclusters.postgres-operator.crunchydata.com - patch: |- - - op: add - path: "/metadata/labels" - value: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest diff --git a/build/crd/postgresclusters/todos.yaml b/build/crd/postgresclusters/todos.yaml deleted file mode 100644 index daa05249a0..0000000000 --- a/build/crd/postgresclusters/todos.yaml +++ /dev/null @@ -1,89 +0,0 @@ -- op: add - path: /work - value: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/configuration/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/configuration/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/repoHost/properties/sshConfigMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/repoHost/properties/sshSecret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/files/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/files/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/customReplicationTLSSecret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/customTLSSecret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/dataSource/properties/pgbackrest/properties/configuration/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/dataSource/properties/pgbackrest/properties/configuration/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/imagePullSecrets/items/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/containers/items/properties/env/items/properties/valueFrom/properties/configMapKeyRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/containers/items/properties/env/items/properties/valueFrom/properties/secretKeyRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/containers/items/properties/envFrom/items/properties/configMapRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/containers/items/properties/envFrom/items/properties/secretRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/monitoring/properties/pgmonitor/properties/exporter/properties/configuration/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/monitoring/properties/pgmonitor/properties/exporter/properties/configuration/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/monitoring/properties/pgmonitor/properties/exporter/properties/customTLSSecret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/config/properties/files/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/config/properties/files/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/containers/items/properties/env/items/properties/valueFrom/properties/configMapKeyRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/containers/items/properties/env/items/properties/valueFrom/properties/secretKeyRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/containers/items/properties/envFrom/items/properties/configMapRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/containers/items/properties/envFrom/items/properties/secretRef/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/proxy/properties/pgBouncer/properties/customTLSSecret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/userInterface/properties/pgAdmin/properties/config/properties/files/items/properties/configMap/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/userInterface/properties/pgAdmin/properties/config/properties/files/items/properties/secret/properties/name/description -- op: copy - from: /work - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/userInterface/properties/pgAdmin/properties/config/properties/ldapBindPassword/properties/name/description -- op: remove - path: /work diff --git a/build/crd/postgresclusters/validation.yaml b/build/crd/postgresclusters/validation.yaml deleted file mode 100644 index c619c4f11d..0000000000 --- a/build/crd/postgresclusters/validation.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# PostgresCluster "v1beta1" is in "/spec/versions/0" - -# Make a temporary workspace. -- { op: add, path: /work, value: {} } - -# Containers should not run with a root GID. -# - https://kubernetes.io/docs/concepts/security/pod-security-standards/ -- op: add - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/supplementalGroups/items/minimum - value: 1 - -# Supplementary GIDs must fit within int32. -# - https://releases.k8s.io/v1.18.0/pkg/apis/core/validation/validation.go#L3659-L3663 -# - https://releases.k8s.io/v1.22.0/pkg/apis/core/validation/validation.go#L3923-L3927 -- op: add - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/supplementalGroups/items/maximum - value: 2147483647 # math.MaxInt32 - -# Make a copy of a standard PVC properties. -- op: copy - from: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/dataVolumeClaimSpec/properties - path: /work/pvcSpecProperties - -# Start an empty list when a standard PVC has no required fields. -- op: test - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/dataVolumeClaimSpec/required - value: null -- op: add - path: /work/pvcSpecRequired - value: [] - -# PersistentVolumeClaims must have an access mode. -# - https://releases.k8s.io/v1.18.0/pkg/apis/core/validation/validation.go#L1893-L1895 -# - https://releases.k8s.io/v1.22.0/pkg/apis/core/validation/validation.go#L2073-L2075 -- op: add - path: /work/pvcSpecRequired/- - value: accessModes -- op: add - path: /work/pvcSpecProperties/accessModes/minItems - value: 1 - -# PersistentVolumeClaims must have a storage request. -# - https://releases.k8s.io/v1.18.0/pkg/apis/core/validation/validation.go#L1904-L1911 -# - https://releases.k8s.io/v1.22.0/pkg/apis/core/validation/validation.go#L2101-L2108 -- op: add - path: /work/pvcSpecRequired/- - value: resources -- op: add - path: /work/pvcSpecProperties/resources/required - value: [requests] -- op: add - path: /work/pvcSpecProperties/resources/properties/requests/required - value: [storage] - -# Replace PVCs throughout the CRD. -- op: copy - from: /work/pvcSpecProperties - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/dataVolumeClaimSpec/properties -- op: copy - from: /work/pvcSpecRequired - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/dataVolumeClaimSpec/required -- op: copy - from: /work/pvcSpecProperties - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/walVolumeClaimSpec/properties -- op: copy - from: /work/pvcSpecRequired - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/instances/items/properties/walVolumeClaimSpec/required -- op: copy - from: /work/pvcSpecProperties - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/repos/items/properties/volume/properties/volumeClaimSpec/properties -- op: copy - from: /work/pvcSpecRequired - path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/backups/properties/pgbackrest/properties/repos/items/properties/volume/properties/volumeClaimSpec/required - -# Remove the temporary workspace. -- { op: remove, path: /work } diff --git a/cmd/postgres-operator/main.go b/cmd/postgres-operator/main.go index 6522abed19..b2f8ae49b6 100644 --- a/cmd/postgres-operator/main.go +++ b/cmd/postgres-operator/main.go @@ -1,19 +1,8 @@ -package main - -/* -Copyright 2017 - 2024 Crunchy Data Solutions, Inc. -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 +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +package main import ( "context" @@ -67,7 +56,7 @@ func initLogging() { runtime.SetLogger(global) } -//+kubebuilder:rbac:groups="coordination.k8s.io",resources="leases",verbs={get,create,update} +//+kubebuilder:rbac:groups="coordination.k8s.io",resources="leases",verbs={get,create,update,watch} func initManager() (runtime.Options, error) { log := logging.FromContext(context.Background()) @@ -179,7 +168,7 @@ func main() { registrar, err := registration.NewRunner(os.Getenv("RSA_KEY"), os.Getenv("TOKEN_PATH"), shutdown) assertNoError(err) assertNoError(mgr.Add(registrar)) - _ = registrar.CheckToken() + token, _ := registrar.CheckToken() // add all PostgreSQL Operator controllers to the runtime manager addControllersToManager(mgr, openshift, log, registrar) @@ -199,8 +188,14 @@ func main() { if !upgradeCheckingDisabled { log.Info("upgrade checking enabled") // get the URL for the check for upgrades endpoint if set in the env - assertNoError(upgradecheck.ManagedScheduler(mgr, - openshift, os.Getenv("CHECK_FOR_UPGRADES_URL"), versionString)) + assertNoError( + upgradecheck.ManagedScheduler( + mgr, + openshift, + os.Getenv("CHECK_FOR_UPGRADES_URL"), + versionString, + token, + )) } else { log.Info("upgrade checking disabled") } diff --git a/cmd/postgres-operator/main_test.go b/cmd/postgres-operator/main_test.go index da23e1a3e6..f369ce6bd3 100644 --- a/cmd/postgres-operator/main_test.go +++ b/cmd/postgres-operator/main_test.go @@ -1,17 +1,6 @@ -/* -Copyright 2017 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package main diff --git a/cmd/postgres-operator/open_telemetry.go b/cmd/postgres-operator/open_telemetry.go index 94050b987e..2c9eedc135 100644 --- a/cmd/postgres-operator/open_telemetry.go +++ b/cmd/postgres-operator/open_telemetry.go @@ -1,19 +1,8 @@ -package main - -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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 +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +package main import ( "context" diff --git a/config/README.md b/config/README.md index d1ecf9d1f8..73d2e59e6f 100644 --- a/config/README.md +++ b/config/README.md @@ -1,16 +1,7 @@ @@ -19,9 +10,6 @@ - The `default` target installs the operator in the `postgres-operator` namespace and configures it to manage resources in all namespaces. -- The `singlenamespace` target installs the operator in the `postgres-operator` - namespace and configures it to manage resources in that same namespace. - diff --git a/config/crd/bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml b/config/crd/bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml index 14b1fe1b2e..82db84b466 100644 --- a/config/crd/bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml +++ b/config/crd/bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml @@ -1,11 +1,9 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 - labels: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest + controller-gen.kubebuilder.io/version: v0.16.4 name: crunchybridgeclusters.postgres-operator.crunchydata.com spec: group: postgres-operator.crunchydata.com @@ -45,11 +43,7 @@ spec: to be managed by Crunchy Data Bridge properties: clusterName: - description: |- - The name of the cluster - --- - According to Bridge API/GUI errors, - "Field name should be between 5 and 50 characters in length, containing only unicode characters, unicode numbers, hyphens, spaces, or underscores, and starting with a character", and ending with a character or number. + description: The name of the cluster maxLength: 50 minLength: 5 pattern: ^[A-Za-z][A-Za-z0-9\-_ ]*[A-Za-z0-9]$ @@ -68,8 +62,8 @@ spec: majorVersion: description: |- The ID of the cluster's major Postgres version. - Currently Bridge offers 13-16 - maximum: 16 + Currently Bridge offers 13-17 + maximum: 17 minimum: 13 type: integer metadata: @@ -156,6 +150,7 @@ spec: - plan - provider - region + - secret - storage type: object status: @@ -166,16 +161,8 @@ spec: description: conditions represent the observations of postgres cluster's current state. items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -216,12 +203,7 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml b/config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml index 4bcdce7f00..da729cfaf2 100644 --- a/config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml +++ b/config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml @@ -1,11 +1,9 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 - labels: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest + controller-gen.kubebuilder.io/version: v0.16.4 name: pgadmins.postgres-operator.crunchydata.com spec: group: postgres-operator.crunchydata.com @@ -980,7 +978,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret or its key must be @@ -1003,14 +1006,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -1138,7 +1138,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -1265,7 +1270,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret @@ -1321,7 +1331,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret or its key must be @@ -1563,7 +1578,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic @@ -1594,11 +1614,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -1780,7 +1798,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret or its key must @@ -1822,16 +1845,8 @@ spec: conditions represent the observations of pgAdmin's current state. Known .status.conditions.type is: "PersistentVolumeResizing" items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -1872,12 +1887,7 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/crd/bases/postgres-operator.crunchydata.com_pgupgrades.yaml b/config/crd/bases/postgres-operator.crunchydata.com_pgupgrades.yaml index c45526d179..4ae831cfc7 100644 --- a/config/crd/bases/postgres-operator.crunchydata.com_pgupgrades.yaml +++ b/config/crd/bases/postgres-operator.crunchydata.com_pgupgrades.yaml @@ -1,11 +1,9 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 - labels: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest + controller-gen.kubebuilder.io/version: v0.16.4 name: pgupgrades.postgres-operator.crunchydata.com spec: group: postgres-operator.crunchydata.com @@ -965,8 +963,8 @@ spec: type: object fromPostgresVersion: description: The major version of PostgreSQL before the upgrade. - maximum: 16 - minimum: 10 + maximum: 17 + minimum: 11 type: integer image: description: The image name to use for major PostgreSQL upgrades. @@ -993,7 +991,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic @@ -1028,11 +1031,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -1082,8 +1083,8 @@ spec: type: string toPostgresVersion: description: The major version of PostgreSQL to be upgraded to. - maximum: 16 - minimum: 10 + maximum: 17 + minimum: 11 type: integer tolerations: description: |- @@ -1138,16 +1139,8 @@ spec: description: conditions represent the observations of PGUpgrade's current state. items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -1188,12 +1181,7 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml b/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml index 0550a17b94..6f9dd40f02 100644 --- a/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml +++ b/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml @@ -1,11 +1,9 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 - labels: - app.kubernetes.io/name: pgo - app.kubernetes.io/version: latest + controller-gen.kubebuilder.io/version: v0.16.4 name: postgresclusters.postgres-operator.crunchydata.com spec: group: postgres-operator.crunchydata.com @@ -62,14 +60,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -198,7 +193,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -329,7 +329,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the @@ -1340,11 +1345,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -2428,11 +2431,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -2522,7 +2523,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -2576,7 +2582,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret @@ -2695,7 +2706,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -2735,7 +2745,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -2753,7 +2762,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -2765,7 +2773,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -2904,7 +2911,6 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string - minItems: 1 type: array x-kubernetes-list-type: atomic dataSource: @@ -3018,11 +3024,7 @@ spec: If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - required: - - storage type: object - required: - - requests type: object selector: description: selector is a label query over @@ -3101,10 +3103,14 @@ spec: description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string - required: - - accessModes - - resources type: object + x-kubernetes-validations: + - message: missing accessModes + rule: has(self.accessModes) && size(self.accessModes) + > 0 + - message: missing storage request + rule: has(self.resources) && has(self.resources.requests) + && has(self.resources.requests.storage) required: - volumeClaimSpec type: object @@ -4102,11 +4108,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -4210,11 +4214,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -4271,11 +4273,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -4330,6 +4330,7 @@ spec: volumeSnapshotClassName: description: Name of the VolumeSnapshotClass that should be used by VolumeSnapshots + minLength: 1 type: string required: - volumeSnapshotClassName @@ -4347,14 +4348,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -4482,7 +4480,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -4609,7 +4612,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret @@ -4698,7 +4706,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret or its @@ -4758,7 +4771,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret or its @@ -5726,14 +5744,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -5862,7 +5877,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -5993,7 +6013,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the @@ -6337,6 +6362,13 @@ spec: to the PersistentVolume backing this claim. type: string type: object + x-kubernetes-validations: + - message: missing accessModes + rule: has(self.accessModes) && size(self.accessModes) + > 0 + - message: missing storage request + rule: has(self.resources) && has(self.resources.requests) + && has(self.resources.requests.storage) required: - volumeClaimSpec type: object @@ -6352,11 +6384,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -7430,11 +7460,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -7630,7 +7658,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic @@ -8644,8 +8677,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the ConfigMap @@ -8707,8 +8744,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret @@ -8743,8 +8784,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the ConfigMap must @@ -8761,8 +8806,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret must @@ -9051,11 +9100,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -9266,11 +9315,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -9419,11 +9468,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -9636,12 +9683,13 @@ spec: Must be set if type is "Localhost". Must NOT be set for any other type. type: string type: - description: 'type indicates which kind of seccomp - profile will be applied. Valid options are: - Localhost - a profile defined in a file on the - node should be used. RuntimeDefault - the container - runtime default profile should be used. Unconfined - - no profile should be applied.' + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. type: string required: - type @@ -9720,11 +9768,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -9939,10 +9987,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -9950,11 +9996,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -9999,7 +10043,6 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string - minItems: 1 type: array x-kubernetes-list-type: atomic dataSource: @@ -10109,11 +10152,7 @@ spec: If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - required: - - storage type: object - required: - - requests type: object selector: description: selector is a label query over volumes to consider @@ -10191,10 +10230,13 @@ spec: description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string - required: - - accessModes - - resources type: object + x-kubernetes-validations: + - message: missing accessModes + rule: has(self.accessModes) && size(self.accessModes) > 0 + - message: missing storage request + rule: has(self.resources) && has(self.resources.requests) + && has(self.resources.requests.storage) metadata: description: Metadata contains metadata for custom resources properties: @@ -10244,11 +10286,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -10306,11 +10346,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -10566,6 +10604,13 @@ spec: the PersistentVolume backing this claim. type: string type: object + x-kubernetes-validations: + - message: missing accessModes + rule: has(self.accessModes) && size(self.accessModes) + > 0 + - message: missing storage request + rule: has(self.resources) && has(self.resources.requests) + && has(self.resources.requests.storage) name: description: |- The name for the tablespace, used as the path name for the volume. @@ -10691,7 +10736,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -10731,7 +10775,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -10749,7 +10792,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -10761,7 +10803,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -10816,7 +10857,6 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string - minItems: 1 type: array x-kubernetes-list-type: atomic dataSource: @@ -10926,11 +10966,7 @@ spec: If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - required: - - storage type: object - required: - - requests type: object selector: description: selector is a label query over volumes to consider @@ -11008,10 +11044,13 @@ spec: description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string - required: - - accessModes - - resources type: object + x-kubernetes-validations: + - message: missing accessModes + rule: has(self.accessModes) && size(self.accessModes) > 0 + - message: missing storage request + rule: has(self.resources) && has(self.resources.requests) + && has(self.resources.requests.storage) required: - dataVolumeClaimSpec type: object @@ -11058,14 +11097,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -11194,8 +11230,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -11328,8 +11368,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether @@ -11414,7 +11458,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret @@ -11437,11 +11486,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -11579,8 +11626,8 @@ spec: postgresVersion: description: The major version of PostgreSQL installed in the PostgreSQL image - maximum: 16 - minimum: 10 + maximum: 17 + minimum: 11 type: integer proxy: description: The specification of a proxy that connects to PostgreSQL. @@ -12558,14 +12605,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -12694,8 +12738,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -12828,8 +12876,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether @@ -12955,8 +13007,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the ConfigMap @@ -13020,8 +13076,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret @@ -13056,8 +13116,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the ConfigMap @@ -13074,8 +13138,12 @@ spec: properties: name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret must @@ -13366,11 +13434,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -13581,11 +13649,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -13734,11 +13802,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -13951,13 +14017,13 @@ spec: Must be set if type is "Localhost". Must NOT be set for any other type. type: string type: - description: 'type indicates which kind of seccomp - profile will be applied. Valid options are: - Localhost - a profile defined in a file on - the node should be used. RuntimeDefault - - the container runtime default profile should - be used. Unconfined - no profile should be - applied.' + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. type: string required: - type @@ -14036,11 +14102,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14256,10 +14322,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -14267,11 +14331,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -14353,7 +14415,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether the Secret @@ -14419,11 +14486,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -14525,11 +14590,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -14686,7 +14749,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -14726,7 +14788,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -14744,7 +14805,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -14756,7 +14816,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -15900,14 +15959,11 @@ spec: ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -16036,8 +16092,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional specify whether the ConfigMap @@ -16170,8 +16230,12 @@ spec: x-kubernetes-list-type: atomic name: default: "" - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: optional field specify whether @@ -16221,7 +16285,12 @@ spec: type: string name: default: "" - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the Secret or its key @@ -16481,11 +16550,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -16682,7 +16749,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -16722,7 +16788,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -16740,7 +16805,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -16752,7 +16816,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -16925,7 +16988,7 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase. + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index e2625322ae..85b7cbdf29 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -1,4 +1,3 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: @@ -6,3 +5,13 @@ resources: - bases/postgres-operator.crunchydata.com_postgresclusters.yaml - bases/postgres-operator.crunchydata.com_pgupgrades.yaml - bases/postgres-operator.crunchydata.com_pgadmins.yaml + +patches: +- target: + kind: CustomResourceDefinition + patch: |- + - op: add + path: /metadata/labels + value: + app.kubernetes.io/name: pgo + app.kubernetes.io/version: latest diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 82b2310ca0..7001380693 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -11,7 +11,7 @@ labels: resources: - ../crd -- ../rbac/cluster +- ../rbac - ../manager images: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 24e770a958..2eb849e138 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -12,34 +12,38 @@ spec: - name: operator image: postgres-operator env: + - name: PGO_INSTALLER + value: kustomize + - name: PGO_INSTALLER_ORIGIN + value: postgres-operator-repo - name: PGO_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: CRUNCHY_DEBUG value: "true" - - name: RELATED_IMAGE_POSTGRES_15 - value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-15.7-1" - - name: RELATED_IMAGE_POSTGRES_15_GIS_3.3 - value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-15.7-3.3-1" - name: RELATED_IMAGE_POSTGRES_16 - value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.4-2" - name: RELATED_IMAGE_POSTGRES_16_GIS_3.3 - value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.3-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.3-2" - name: RELATED_IMAGE_POSTGRES_16_GIS_3.4 - value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.3-3.4-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-16.4-3.4-2" + - name: RELATED_IMAGE_POSTGRES_17 + value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-17.0-0" + - name: RELATED_IMAGE_POSTGRES_17_GIS_3.4 + value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-gis:ubi8-17.0-3.4-0" - name: RELATED_IMAGE_PGADMIN - value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-26" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-4.30-31" - name: RELATED_IMAGE_PGBACKREST - value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.51-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.53.1-0" - name: RELATED_IMAGE_PGBOUNCER - value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.22-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.23-0" - name: RELATED_IMAGE_PGEXPORTER value: "registry.developers.crunchydata.com/crunchydata/crunchy-postgres-exporter:latest" - name: RELATED_IMAGE_PGUPGRADE value: "registry.developers.crunchydata.com/crunchydata/crunchy-upgrade:latest" - name: RELATED_IMAGE_STANDALONE_PGADMIN - value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-8.6-1" + value: "registry.developers.crunchydata.com/crunchydata/crunchy-pgadmin4:ubi8-8.12-0" securityContext: allowPrivilegeEscalation: false capabilities: { drop: [ALL] } diff --git a/config/rbac/.gitignore b/config/rbac/.gitignore deleted file mode 100644 index 2ad5901955..0000000000 --- a/config/rbac/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/role.yaml diff --git a/config/rbac/cluster/kustomization.yaml b/config/rbac/kustomization.yaml similarity index 100% rename from config/rbac/cluster/kustomization.yaml rename to config/rbac/kustomization.yaml diff --git a/config/rbac/namespace/kustomization.yaml b/config/rbac/namespace/kustomization.yaml deleted file mode 100644 index 82cfb0841b..0000000000 --- a/config/rbac/namespace/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- service_account.yaml -- role.yaml -- role_binding.yaml diff --git a/config/rbac/namespace/role.yaml b/config/rbac/namespace/role.yaml deleted file mode 100644 index d4ede32c6c..0000000000 --- a/config/rbac/namespace/role.yaml +++ /dev/null @@ -1,176 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: postgres-operator -rules: -- apiGroups: - - '' - resources: - - configmaps - - persistentvolumeclaims - - secrets - - serviceaccounts - - services - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - '' - resources: - - endpoints - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - watch -- apiGroups: - - '' - resources: - - endpoints/restricted - - pods/exec - verbs: - - create -- apiGroups: - - '' - resources: - - events - verbs: - - create - - patch -- apiGroups: - - '' - resources: - - pods - verbs: - - delete - - get - - list - - patch - - watch -- apiGroups: - - apps - resources: - - deployments - - statefulsets - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - batch - resources: - - cronjobs - - jobs - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - get - - update - - watch -- apiGroups: - - policy - resources: - - poddisruptionbudgets - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - crunchybridgeclusters - verbs: - - get - - list - - patch - - update - - watch -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - crunchybridgeclusters/finalizers - - crunchybridgeclusters/status - verbs: - - patch - - update -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - pgadmins - - pgupgrades - verbs: - - get - - list - - watch -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - pgadmins/finalizers - - pgupgrades/finalizers - - postgresclusters/finalizers - verbs: - - update -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - pgadmins/status - - pgupgrades/status - - postgresclusters/status - verbs: - - patch -- apiGroups: - - postgres-operator.crunchydata.com - resources: - - postgresclusters - verbs: - - get - - list - - patch - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - - roles - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots - verbs: - - create - - delete - - get - - list - - patch - - watch diff --git a/config/rbac/namespace/role_binding.yaml b/config/rbac/namespace/role_binding.yaml deleted file mode 100644 index d7c16c8a5b..0000000000 --- a/config/rbac/namespace/role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: postgres-operator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: postgres-operator -subjects: -- kind: ServiceAccount - name: pgo diff --git a/config/rbac/namespace/service_account.yaml b/config/rbac/namespace/service_account.yaml deleted file mode 100644 index 364f797171..0000000000 --- a/config/rbac/namespace/service_account.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pgo diff --git a/config/rbac/cluster/role.yaml b/config/rbac/role.yaml similarity index 98% rename from config/rbac/cluster/role.yaml rename to config/rbac/role.yaml index 1119eb0d5a..d5783d00b1 100644 --- a/config/rbac/cluster/role.yaml +++ b/config/rbac/role.yaml @@ -5,7 +5,7 @@ metadata: name: postgres-operator rules: - apiGroups: - - '' + - "" resources: - configmaps - persistentvolumeclaims @@ -20,7 +20,7 @@ rules: - patch - watch - apiGroups: - - '' + - "" resources: - endpoints verbs: @@ -32,21 +32,21 @@ rules: - patch - watch - apiGroups: - - '' + - "" resources: - endpoints/restricted - pods/exec verbs: - create - apiGroups: - - '' + - "" resources: - events verbs: - create - patch - apiGroups: - - '' + - "" resources: - pods verbs: diff --git a/config/rbac/cluster/role_binding.yaml b/config/rbac/role_binding.yaml similarity index 100% rename from config/rbac/cluster/role_binding.yaml rename to config/rbac/role_binding.yaml diff --git a/config/rbac/cluster/service_account.yaml b/config/rbac/service_account.yaml similarity index 100% rename from config/rbac/cluster/service_account.yaml rename to config/rbac/service_account.yaml diff --git a/config/singlenamespace/kustomization.yaml b/config/singlenamespace/kustomization.yaml deleted file mode 100644 index a6dc8de538..0000000000 --- a/config/singlenamespace/kustomization.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -namespace: postgres-operator - -labels: -- includeSelectors: true - pairs: - postgres-operator.crunchydata.com/control-plane: postgres-operator - -resources: -- ../crd -- ../rbac/namespace -- ../manager - -images: -- name: postgres-operator - newName: registry.developers.crunchydata.com/crunchydata/postgres-operator - newTag: latest - -patches: -- path: manager-target.yaml diff --git a/config/singlenamespace/manager-target.yaml b/config/singlenamespace/manager-target.yaml deleted file mode 100644 index 949250e264..0000000000 --- a/config/singlenamespace/manager-target.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pgo -spec: - template: - spec: - containers: - - name: operator - env: - - name: PGO_TARGET_NAMESPACE - valueFrom: { fieldRef: { apiVersion: v1, fieldPath: metadata.namespace } } diff --git a/examples/postgrescluster/postgrescluster.yaml b/examples/postgrescluster/postgrescluster.yaml index 7ad4524571..75756af94e 100644 --- a/examples/postgrescluster/postgrescluster.yaml +++ b/examples/postgrescluster/postgrescluster.yaml @@ -3,7 +3,6 @@ kind: PostgresCluster metadata: name: hippo spec: - image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-16.3-1 postgresVersion: 16 instances: - name: instance1 @@ -15,7 +14,6 @@ spec: storage: 1Gi backups: pgbackrest: - image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.51-1 repos: - name: repo1 volume: @@ -34,5 +32,4 @@ spec: requests: storage: 1Gi proxy: - pgBouncer: - image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbouncer:ubi8-1.22-1 + pgBouncer: {} diff --git a/go.mod b/go.mod index 4d1b01cdd5..d268d66018 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,7 @@ module github.com/crunchydata/postgres-operator go 1.22.0 -toolchain go1.22.4 - require ( - github.com/evanphx/json-patch/v5 v5.9.0 github.com/go-logr/logr v1.4.2 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-cmp v0.6.0 @@ -24,7 +21,7 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 go.opentelemetry.io/otel/sdk v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 - golang.org/x/crypto v0.24.0 + golang.org/x/crypto v0.27.0 gotest.tools/v3 v3.1.0 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 @@ -42,6 +39,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -74,17 +72,17 @@ require ( go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect - google.golang.org/grpc v1.64.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index ba3e7da896..aed2056f6f 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -165,8 +165,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -178,15 +178,15 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -204,10 +204,10 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 h1:QW9+G6Fir4VcRXVH8x3LilNAb6cxBGLa6+GM4hRwexE= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3/go.mod h1:kdrSS/OiLkPrNUpzD4aHgCq2rVuC/YRxok32HXZ4vRE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 2c973beb91..7fc3d63c10 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,15 +1,3 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ - +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 diff --git a/hack/create-todo-patch.sh b/hack/create-todo-patch.sh deleted file mode 100755 index 7aab184a3a..0000000000 --- a/hack/create-todo-patch.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -# 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. - -directory=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -clusters_dir="${directory}/../build/crd/postgresclusters" -upgrades_dir="${directory}/../build/crd/pgupgrades" - -# Generate a Kustomize patch file for removing any TODOs we inherit from the Kubernetes API. -# Right now there is one TODO in our CRD. This script focuses on removing the specific TODO -# anywhere they are found in the CRD. - -# The TODO comes from the following: -# https://github.com/kubernetes/api/blob/25b7aa9e86de7bba38c35cbe56701d2c1ff207e9/core/v1/types.go#L5609 -# Additionally, the hope is that this step can be removed once the following issue is addressed -# in the kubebuilder controller-tools project: -# https://github.com/kubernetes-sigs/controller-tools/issues/649 - -echo "Generating Kustomize patch file for removing Kube API TODOs" - -# Get the description of the "name" field with the TODO from any place it is used in the CRD and -# store it in a variable. Then, create another variable with the TODO stripped out. -name_desc_with_todo=$( - python3 -m yq -r \ - .spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.customTLSSecret.properties.name.description \ - "${clusters_dir}/generated/postgres-operator.crunchydata.com_postgresclusters.yaml" -) -name_desc_without_todo=$(sed 's/ TODO.*//g' <<< "${name_desc_with_todo}") - -# Generate a JSON patch file to update the "name" description for all applicable paths in the CRD. -python3 -m yq -y --arg old "${name_desc_with_todo}" --arg new "${name_desc_without_todo}" ' - [{ op: "add", path: "/work", value: $new }] + - [paths(select(. == $old)) | { op: "copy", from: "/work", path: "/\(map(tostring) | join("/"))" }] + - [{ op: "remove", path: "/work" }] -' \ - "${clusters_dir}/generated/postgres-operator.crunchydata.com_postgresclusters.yaml" > "${clusters_dir}/todos.yaml" - -python3 -m yq -y --arg old "${name_desc_with_todo}" --arg new "${name_desc_without_todo}" ' - [{ op: "add", path: "/work", value: $new }] + - [paths(select(. == $old)) | { op: "copy", from: "/work", path: "/\(map(tostring) | join("/"))" }] + - [{ op: "remove", path: "/work" }] -' \ - "${upgrades_dir}/generated/postgres-operator.crunchydata.com_pgupgrades.yaml" > "${upgrades_dir}/todos.yaml" diff --git a/hack/generate-rbac.sh b/hack/generate-rbac.sh deleted file mode 100755 index 4ad430a5e9..0000000000 --- a/hack/generate-rbac.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -# 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. - -set -eu - -declare -r directory="$1" - -# NOTE(cbandy): `kustomize` v4.1 and `kubectl` v1.22 will be able to change the -# kind of a resource: https://pr.k8s.io/101120 -ruby -r 'set' -r 'yaml' -e ' -directory = ARGV[0] -roles = YAML.load_stream(IO.read(File.join(directory, "role.yaml"))) -operator = roles.shift - -abort "Expected the operator ClusterRole first!" unless operator and operator["kind"] == "ClusterRole" - -# The client used by the controller sets up a cache and an informer for any GVK -# that it GETs. That informer needs the "watch" permission. -# - https://github.com/kubernetes-sigs/controller-runtime/issues/1249 -# - https://github.com/kubernetes-sigs/controller-runtime/issues/1454 -# TODO(cbandy): Move this into an RBAC marker when it can be configured on the Manager. -operator["rules"].each do |rule| - verbs = rule["verbs"].to_set - rule["verbs"] = verbs.add("watch").sort if verbs.intersect? Set["get", "list"] -end - -# Combine the other parsed Roles into the ClusterRole. -rules = operator["rules"] + roles.flat_map { |role| role["rules"] } -rules = rules. - group_by { |rule| rule.slice("apiGroups", "resources") }. - map do |(group_resource, rules)| - verbs = rules.flat_map { |rule| rule["verbs"] }.to_set.sort - group_resource.merge("verbs" => verbs) - end -operator["rules"] = rules.sort_by { |rule| rule.to_a } - -# Combine resources that have the same verbs. -rules = operator["rules"]. - group_by { |rule| rule.slice("apiGroups", "verbs") }. - map do |(group_verb, rules)| - resources = rules.flat_map { |rule| rule["resources"] }.to_set.sort - rule = group_verb.merge("resources" => resources) - rule.slice("apiGroups", "resources", "verbs") # keep the keys in order - end -operator["rules"] = rules.sort_by { |rule| rule.to_a } - -operator["metadata"] = { "name" => "postgres-operator" } -IO.write(File.join(directory, "cluster", "role.yaml"), YAML.dump(operator)) - -operator["kind"] = "Role" -IO.write(File.join(directory, "namespace", "role.yaml"), YAML.dump(operator)) -' -- "${directory}" diff --git a/installers/olm/.gitignore b/installers/olm/.gitignore deleted file mode 100644 index a2d12b4ff2..0000000000 --- a/installers/olm/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/bundles/ -/projects/ -/tools/ -/config/marketplace diff --git a/installers/olm/Makefile b/installers/olm/Makefile deleted file mode 100644 index 9784d352cf..0000000000 --- a/installers/olm/Makefile +++ /dev/null @@ -1,112 +0,0 @@ -.DEFAULT_GOAL := help -.SUFFIXES: - -CONTAINER ?= docker -PGO_VERSION ?= latest -REPLACES_VERSION ?= 5.x.y - -OS_KERNEL ?= $(shell bash -c 'echo $${1,,}' - `uname -s`) -OS_MACHINE ?= $(shell bash -c 'echo $${1/x86_/amd}' - `uname -m`) -SYSTEM = $(OS_KERNEL)-$(OS_MACHINE) - -export PATH := $(CURDIR)/tools/$(SYSTEM):$(PATH) - -export PGO_VERSION - -export REPLACES_VERSION - -distros = community redhat marketplace - -.PHONY: bundles -bundles: ## Build OLM bundles -bundles: $(distros:%=bundles/%) - -# https://olm.operatorframework.io/docs/tasks/creating-operator-bundle/#validating-your-bundle -# https://github.com/operator-framework/community-operators/blob/8a36a33/docs/packaging-required-criteria-ocp.md -.PHONY: bundles/community -bundles/community: - ./generate.sh community - env operator-sdk bundle validate $@ --select-optional='suite=operatorframework' - env operator-sdk bundle validate $@ --select-optional='name=community' --optional-values='index-path=$@/Dockerfile' - -# https://redhat-connect.gitbook.io/certified-operator-guide/ocp-deployment/operator-metadata/reviewing-your-metadata-bundle -.PHONY: bundles/redhat -bundles/redhat: - ./generate.sh redhat - env operator-sdk bundle validate $@ --select-optional='suite=operatorframework' - -# The 'marketplace' configuration is currently identical to the 'redhat', so we just copy it here. -.PHONY: bundles/marketplace -bundles/marketplace: - cp -r ./config/redhat/ ./config/marketplace - ./generate.sh marketplace - env operator-sdk bundle validate $@ --select-optional='suite=operatorframework' - -.PHONY: clean -clean: clean-deprecated -clean: ## Remove generated files and downloaded tools - rm -rf ./bundles ./projects ./tools ./config/marketplace - -.PHONY: clean-deprecated -clean-deprecated: - rm -rf ./package - -.PHONY: help -help: ALIGN=18 -help: ## Print this message - @awk -F ': ## ' -- "/^[^':]+: ## /"' { printf "'$$(tput bold)'%-$(ALIGN)s'$$(tput sgr0)' %s\n", $$1, $$2 }' $(MAKEFILE_LIST) - -.PHONY: install-olm -install-olm: ## Install OLM in Kubernetes - env operator-sdk olm install - -.PHONY: tools -tools: ## Download tools needed to build bundles - -tools: tools/$(SYSTEM)/jq -tools/$(SYSTEM)/jq: - install -d '$(dir $@)' - curl -fSL -o '$@' "https://github.com/jqlang/jq/releases/download/jq-1.6/jq-$$(SYSTEM='$(SYSTEM)'; \ - case "$$SYSTEM" in \ - (linux-*) echo "$${SYSTEM/-amd/}";; (darwin-*) echo "$${SYSTEM/darwin/osx}";; (*) echo '$(SYSTEM)';; \ - esac)" - chmod u+x '$@' - -tools: tools/$(SYSTEM)/kubectl -tools/$(SYSTEM)/kubectl: - install -d '$(dir $@)' - curl -fSL -o '$@' 'https://dl.k8s.io/release/$(shell curl -Ls https://dl.k8s.io/release/stable-1.21.txt)/bin/$(OS_KERNEL)/$(OS_MACHINE)/kubectl' - chmod u+x '$@' - -# quay.io/operator-framework/operator-sdk -tools: tools/$(SYSTEM)/operator-sdk -tools/$(SYSTEM)/operator-sdk: - install -d '$(dir $@)' - curl -fSL -o '$@' 'https://github.com/operator-framework/operator-sdk/releases/download/v1.18.0/operator-sdk_$(OS_KERNEL)_$(OS_MACHINE)' - chmod u+x '$@' - -tools: tools/$(SYSTEM)/opm -tools/$(SYSTEM)/opm: - install -d '$(dir $@)' - curl -fSL -o '$@' 'https://github.com/operator-framework/operator-registry/releases/download/v1.33.0/$(OS_KERNEL)-$(OS_MACHINE)-opm' - chmod u+x '$@' - -tools/$(SYSTEM)/venv: - install -d '$(dir $@)' - python3 -m venv '$@' - -tools: tools/$(SYSTEM)/yq -tools/$(SYSTEM)/yq: | tools/$(SYSTEM)/venv - 'tools/$(SYSTEM)/venv/bin/python' -m pip install yq - cd '$(dir $@)' && ln -s venv/bin/yq - -.PHONY: validate-bundles -validate-bundles: ## Build temporary bundle images and run scorecard tests in Kubernetes -validate-bundles: $(distros:%=validate-%-image) -validate-bundles: $(distros:%=validate-%-directory) - -validate-%-directory: - ./validate-directory.sh 'bundles/$*' - -validate-%-image: - ./validate-image.sh '$(CONTAINER)' 'bundles/$*' diff --git a/installers/olm/README.md b/installers/olm/README.md deleted file mode 100644 index e067c86b39..0000000000 --- a/installers/olm/README.md +++ /dev/null @@ -1,147 +0,0 @@ -This directory contains the files that are used to install [Crunchy PostgreSQL for Kubernetes][hub-listing], -which includes PGO, the Postgres Operator from [Crunchy Data][], using [Operator Lifecycle Manager][OLM]. - -The integration centers around a [ClusterServiceVersion][olm-csv] [manifest](./bundle.csv.yaml) -that gets packaged for OperatorHub. Changes there are accepted only if they pass all the [scorecard][] -tests. Consult the [technical requirements][hub-contrib] when making changes. - - - -[Crunchy Data]: https://www.crunchydata.com -[hub-contrib]: https://operator-framework.github.io/community-operators/packaging-operator/ -[hub-listing]: https://operatorhub.io/operator/postgresql -[OLM]: https://github.com/operator-framework/operator-lifecycle-manager -[olm-csv]: https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/building-your-csv.md -[scorecard]: https://sdk.operatorframework.io/docs/testing-operators/scorecard/ - -[Red Hat Container Certification]: https://redhat-connect.gitbook.io/partner-guide-for-red-hat-openshift-and-container/ -[Red Hat Operator Certification]: https://redhat-connect.gitbook.io/certified-operator-guide/ - - - -## Notes - -### v5 Versions per Repository - -Community: https://github.com/k8s-operatorhub/community-operators/tree/main/operators/postgresql - -5.0.2 -5.0.3 -5.0.4 -5.0.5 -5.1.0 - -Community Prod: https://github.com/redhat-openshift-ecosystem/community-operators-prod/tree/main/operators/postgresql - -5.0.2 -5.0.3 -5.0.4 -5.0.5 -5.1.0 - -Certified: https://github.com/redhat-openshift-ecosystem/certified-operators/tree/main/operators/crunchy-postgres-operator - -5.0.4 -5.0.5 -5.1.0 - -Marketplace: https://github.com/redhat-openshift-ecosystem/redhat-marketplace-operators/tree/main/operators/crunchy-postgres-operator-rhmp - -5.0.4 -5.0.5 -5.1.0 - -### Issues Encountered - -We hit various issues with 5.1.0 where the 'replaces' name, set in the clusterserviceversion.yaml, didn't match the -expected names found for all indexes. Previously, we set the 'com.redhat.openshift.versions' annotation to "v4.6-v4.9". -The goal for this setting was to limit the upper bound of supported versions for a particularly PGO release. -The problem with this was, at the time of the 5.1.0 release, OCP 4.10 had been just been released. This meant that the -5.0.5 bundle did not exist in the OCP 4.10 index. The solution presented by Red Hat was to use the 'skips' clause for -the 5.1.0 release to remedy the immediate problem, but then go back to using an unbounded setting for subsequent -releases. - -For the certified, marketplace and community repositories, this strategy of using 'skips' instead of replaces worked as -expected. However, for the production community operator bundle, we were seeing a failure that required adding an -additional 'replaces' value of 5.0.4 in addition to the 5.0.5 'skips' value. While this allowed the PR to merge, it -seems at odds with the behavior at the other repos. - -For more information on the use of 'skips' and 'replaces', please see: -https://olm.operatorframework.io/docs/concepts/olm-architecture/operator-catalog/creating-an-update-graph/ - - -Another version issue encountered was related to our attempt to both support OCP v4.6 (which is an Extended Update -Support (EUS) release) while also limiting Kubernetes to 1.20+. The issue with this is that OCP 4.6 utilizes k8s 1.19 -and the kube minversion validation was in fact limiting the OCP version as well. Our hope was that those setting would -be treated independently, but that was unfortunately not the case. The fix for this was to move this kube version to the -1.19, despite its being released 3rd quarter of 2020 with 1 year of patch support. - -Following the lessons learned above, when bumping the Openshift supported version from v4.6 to v4.8, we will similarly -keep the matching minimum Kubernetes version, i.e. 1.21. -https://access.redhat.com/solutions/4870701 - -## Testing - -### Setup - -```sh -make tools -``` - -### Testing - -```sh -make bundles validate-bundles -``` - -Previously, the 'validate_bundle_image' function in validate-bundles.sh ended -with the following command: - -```sh - # Create an index database from the bundle image. - "${opm[@]}" index add --bundles="${image}" --generate - - # drwxr-xr-x. 2 user user 22 database - # -rw-r--r--. 1 user user 286720 database/index.db - # -rw-r--r--. 1 user user 267 index.Dockerfile -``` - -this command was used to generate the updated registry database, but this step -is no longer required when validating the OLM bundles. -- https://github.com/operator-framework/operator-registry/blob/master/docs/design/opm-tooling.md#add-1 - -```sh -BUNDLE_DIRECTORY='bundles/community' -BUNDLE_IMAGE='gcr.io/.../postgres-operator-bundle:latest' -INDEX_IMAGE='gcr.io/.../postgres-operator-bundle-index:latest' -NAMESPACE='pgo' - -docker build --tag "$BUNDLE_IMAGE" "$BUNDLE_DIRECTORY" -docker push "$BUNDLE_IMAGE" - -opm index add --bundles "$BUNDLE_IMAGE" --tag "$INDEX_IMAGE" --container-tool=docker -docker push "$INDEX_IMAGE" - -./install.sh operator "$BUNDLE_DIRECTORY" "$INDEX_IMAGE" "$NAMESPACE" "$NAMESPACE" - -# Cleanup -operator-sdk cleanup postgresql --namespace="$NAMESPACE" -kubectl -n "$NAMESPACE" delete operatorgroup olm-operator-group -``` - -### Post Bundle Generation - -After generating and testing the OLM bundles, there are two manual steps. - -1. Update the image SHA values (denoted with '', required for both the Red Hat 'Certified' and -'Marketplace' bundles) -2. Update the 'description.md' file to indicate which OCP versions this release of PGO was tested against. - -### Troubleshooting - -If, when running `make validate-bundles` you encounter an error similar to - -`cannot find Containerfile or Dockerfile in context directory: stat /mnt/Dockerfile: permission denied` - -the target command is likely being blocked by SELinux and you will need to adjust -your settings accordingly. diff --git a/installers/olm/bundle.Dockerfile b/installers/olm/bundle.Dockerfile deleted file mode 100644 index a81d16f73e..0000000000 --- a/installers/olm/bundle.Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Used to build the bundle image. This file is ignored by the community operator -# registries which work with bundle directories instead. -# https://operator-framework.github.io/community-operators/packaging-operator/ - -FROM scratch AS builder - -COPY manifests/ /build/manifests/ -COPY metadata/ /build/metadata/ -COPY tests/ /build/tests - - -FROM scratch - -# ANNOTATIONS is replaced with bundle.annotations.yaml -LABEL \ - ${ANNOTATIONS} - -COPY --from=builder /build/ / diff --git a/installers/olm/bundle.annotations.yaml b/installers/olm/bundle.annotations.yaml deleted file mode 100644 index 27dce5aa07..0000000000 --- a/installers/olm/bundle.annotations.yaml +++ /dev/null @@ -1,38 +0,0 @@ ---- -annotations: - # https://olm.operatorframework.io/docs/tasks/creating-operator-bundle/ - # https://docs.openshift.com/container-platform/4.7/operators/understanding/olm-packaging-format.html - operators.operatorframework.io.bundle.mediatype.v1: registry+v1 - operators.operatorframework.io.bundle.manifests.v1: manifests/ - operators.operatorframework.io.bundle.metadata.v1: metadata/ - - operators.operatorframework.io.test.mediatype.v1: scorecard+v1 - operators.operatorframework.io.test.config.v1: tests/scorecard/ - - # "package.v1" is the name of the PackageManifest. It also determines the URL - # of the details page at OperatorHub.io; "postgresql" here becomes: - # https://operatorhub.io/operator/postgresql - # - # A package consists of multiple bundles (versions) arranged into channels. - # https://olm.operatorframework.io/docs/concepts/olm-architecture/operator-catalog/creating-an-update-graph/ - operators.operatorframework.io.bundle.package.v1: '' # generate.sh - - # "channels.v1" is the comma-separated list of channels from which this bundle - # can be installed. - # - # "channel.default.v1" is the default channel of the PackageManifest. It is - # the first channel presented, the first used to satisfy dependencies, and - # the one used by a Subscription that does not specify a channel. OLM uses - # the value from the bundle with the highest semantic version. - # - # https://olm.operatorframework.io/docs/best-practices/channel-naming/ - operators.operatorframework.io.bundle.channels.v1: v5 - operators.operatorframework.io.bundle.channel.default.v1: v5 - - # OpenShift v4.9 is the lowest version supported for v5.3.0+. - # https://github.com/operator-framework/community-operators/blob/8a36a33/docs/packaging-required-criteria-ocp.md - # https://redhat-connect.gitbook.io/certified-operator-guide/ocp-deployment/operator-metadata/bundle-directory - com.redhat.delivery.operator.bundle: true - com.redhat.openshift.versions: 'v4.10' - -... diff --git a/installers/olm/bundle.csv.yaml b/installers/olm/bundle.csv.yaml deleted file mode 100644 index 600f8b1bc0..0000000000 --- a/installers/olm/bundle.csv.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# https://olm.operatorframework.io/docs/concepts/crds/clusterserviceversion/ -# https://docs.openshift.com/container-platform/4.7/operators/operator_sdk/osdk-generating-csvs.html -# https://redhat-connect.gitbook.io/certified-operator-guide/ocp-deployment/operator-metadata/creating-the-csv -# https://pkg.go.dev/github.com/operator-framework/api@v0.10.1/pkg/operators/v1alpha1#ClusterServiceVersion - -apiVersion: operators.coreos.com/v1alpha1 -kind: ClusterServiceVersion -metadata: - name: '' # generate.sh - annotations: - support: crunchydata.com - olm.properties: '[]' - - # The following affect how the package is indexed at OperatorHub.io: - # https://operatorhub.io/?category=Database - # https://sdk.operatorframework.io/docs/advanced-topics/operator-capabilities/operator-capabilities/ - categories: Database - capabilities: Auto Pilot - description: Production Postgres Made Easy - - # The following appear on the details page at OperatorHub.io: - # https://operatorhub.io/operator/postgresql - createdAt: 2019-12-31 19:40Z - repository: https://github.com/CrunchyData/postgres-operator - containerImage: # kustomize config/operator - alm-examples: |- # kustomize config/examples - -spec: - # The following affect how the package is indexed at OperatorHub.io: - # https://operatorhub.io/ - displayName: Crunchy Postgres for Kubernetes - provider: - # These values become labels on the PackageManifest. - name: Crunchy Data - url: https://www.crunchydata.com/ - keywords: - - postgres - - postgresql - - database - - sql - - operator - - crunchy data - - # The following appear on the details page at OperatorHub.io: - # https://operatorhub.io/operator/postgresql - description: |- # description.md - version: '' # generate.sh - links: - - name: Crunchy Data - url: https://www.crunchydata.com/ - - name: Documentation - url: https://access.crunchydata.com/documentation/postgres-operator/v5/ - maintainers: - - name: Crunchy Data - email: info@crunchydata.com - - # https://olm.operatorframework.io/docs/best-practices/common/ - # Note: The minKubeVersion must correspond to the lowest supported OCP version - minKubeVersion: 1.23.0 - maturity: stable - # https://github.com/operator-framework/operator-lifecycle-manager/blob/v0.18.2/doc/design/how-to-update-operators.md#replaces--channels - replaces: '' # generate.sh - - # https://github.com/operator-framework/operator-lifecycle-manager/blob/v0.18.2/doc/design/building-your-csv.md#your-custom-resource-definitions - customresourcedefinitions: - # The "displayName" and "description" fields appear in the "Custom Resource Definitions" section - # on the details page at OperatorHub.io: https://operatorhub.io/operator/postgresql - # - # The "specDescriptors" and "statusDescriptors" fields appear in the OpenShift Console: - # https://github.com/openshift/console/tree/a8b35e4/frontend/packages/operator-lifecycle-manager/src/components/descriptors - owned: # operator-sdk generate kustomize manifests - - # https://olm.operatorframework.io/docs/advanced-tasks/operator-scoping-with-operatorgroups/ - installModes: - - { type: OwnNamespace, supported: true } - - { type: SingleNamespace, supported: true } - - { type: MultiNamespace, supported: false } - - { type: AllNamespaces, supported: true } - - install: - strategy: deployment - spec: - permissions: # kustomize config/operator - deployments: # kustomize config/operator diff --git a/installers/olm/bundle.relatedImages.yaml b/installers/olm/bundle.relatedImages.yaml deleted file mode 100644 index 3824b27b2e..0000000000 --- a/installers/olm/bundle.relatedImages.yaml +++ /dev/null @@ -1,25 +0,0 @@ - relatedImages: - - name: PGADMIN - image: registry.connect.redhat.com/crunchydata/crunchy-pgadmin4@sha256: - - name: PGBACKREST - image: registry.connect.redhat.com/crunchydata/crunchy-pgbackrest@sha256: - - name: PGBOUNCER - image: registry.connect.redhat.com/crunchydata/crunchy-pgbouncer@sha256: - - name: PGEXPORTER - image: registry.connect.redhat.com/crunchydata/crunchy-postgres-exporter@sha256: - - name: PGUPGRADE - image: registry.connect.redhat.com/crunchydata/crunchy-upgrade@sha256: - - name: POSTGRES_14 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres@sha256: - - name: POSTGRES_15 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres@sha256: - - name: POSTGRES_14_GIS_3.1 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256: - - name: POSTGRES_14_GIS_3.2 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256: - - name: POSTGRES_14_GIS_3.3 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256: - - name: POSTGRES_15_GIS_3.3 - image: registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256: - - name: postgres-operator - image: registry.connect.redhat.com/crunchydata/postgres-operator@sha256: diff --git a/installers/olm/config/community/kustomization.yaml b/installers/olm/config/community/kustomization.yaml deleted file mode 100644 index a34c7b4844..0000000000 --- a/installers/olm/config/community/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- ../operator -- ../examples diff --git a/installers/olm/config/examples/kustomization.yaml b/installers/olm/config/examples/kustomization.yaml deleted file mode 100644 index 420c2644f7..0000000000 --- a/installers/olm/config/examples/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Custom resources that are imported into the ClusterServiceVersion. -# -# The first for each GVK appears in the "Custom Resource Definitions" section on -# the details page at OperatorHub.io: https://operatorhub.io/operator/postgresql -# -# The "metadata.name" fields should be unique so they can be given a description -# that is presented by compatible UIs. -# https://github.com/operator-framework/operator-lifecycle-manager/blob/v0.18.2/doc/design/building-your-csv.md#crd-templates -# -# The "image" fields should be omitted so the defaults are used. -# https://redhat-connect.gitbook.io/certified-operator-guide/troubleshooting-and-resources/offline-enabled-operators - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- postgrescluster.example.yaml -- pgadmin.example.yaml -- pgupgrade.example.yaml diff --git a/installers/olm/config/examples/pgadmin.example.yaml b/installers/olm/config/examples/pgadmin.example.yaml deleted file mode 100644 index 7ed1d3c03f..0000000000 --- a/installers/olm/config/examples/pgadmin.example.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGAdmin -metadata: - name: example-pgadmin - namespace: openshift-operators -spec: - dataVolumeClaimSpec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - serverGroups: - - name: "Crunchy Postgres for Kubernetes" - postgresClusterSelector: {} diff --git a/installers/olm/config/examples/pgupgrade.example.yaml b/installers/olm/config/examples/pgupgrade.example.yaml deleted file mode 100644 index ad4f45310a..0000000000 --- a/installers/olm/config/examples/pgupgrade.example.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: example-upgrade -spec: - postgresClusterName: example - fromPostgresVersion: 14 - toPostgresVersion: 15 diff --git a/installers/olm/config/examples/postgrescluster.example.yaml b/installers/olm/config/examples/postgrescluster.example.yaml deleted file mode 100644 index 502eaff437..0000000000 --- a/installers/olm/config/examples/postgrescluster.example.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: example -spec: - postgresVersion: 15 - instances: - - replicas: 1 - dataVolumeClaimSpec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 1Gi - backups: - pgbackrest: - repos: - - name: repo1 - volume: - volumeClaimSpec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 1Gi diff --git a/installers/olm/config/operator/kustomization.yaml b/installers/olm/config/operator/kustomization.yaml deleted file mode 100644 index dfdce41618..0000000000 --- a/installers/olm/config/operator/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- ../../../../config/default - -patches: -- path: target-namespace.yaml diff --git a/installers/olm/config/operator/target-namespace.yaml b/installers/olm/config/operator/target-namespace.yaml deleted file mode 100644 index d7dbaadeef..0000000000 --- a/installers/olm/config/operator/target-namespace.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pgo -spec: - template: - spec: - containers: - - name: operator - env: - # https://docs.openshift.com/container-platform/4.7/operators/understanding/olm/olm-understanding-operatorgroups.html - - name: PGO_TARGET_NAMESPACE - valueFrom: { fieldRef: { fieldPath: "metadata.annotations['olm.targetNamespaces']" } } diff --git a/installers/olm/config/redhat/kustomization.yaml b/installers/olm/config/redhat/kustomization.yaml deleted file mode 100644 index 4d28b460a2..0000000000 --- a/installers/olm/config/redhat/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: - - ../operator - - ../examples - -patches: - - path: related-images.yaml - - path: registration.yaml diff --git a/installers/olm/config/redhat/registration.yaml b/installers/olm/config/redhat/registration.yaml deleted file mode 100644 index 8aa8a70ceb..0000000000 --- a/installers/olm/config/redhat/registration.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# Red Hat Marketplace requires that bundles work offline. OSBS will fill out -# the "spec.relatedImages" field of the ClusterServiceVersion if it is blank. -# -# https://redhat-connect.gitbook.io/certified-operator-guide/troubleshooting-and-resources/offline-enabled-operators -# https://osbs.readthedocs.io/en/latest/users.html#pinning-pullspecs-for-related-images -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pgo -spec: - template: - spec: - containers: - - name: operator - env: - - { name: REGISTRATION_REQUIRED, value: "true" } - - { name: TOKEN_PATH, value: "/etc/cpk/cpk_token" } - - name: REGISTRATION_URL - value: "https://access.crunchydata.com/register-cpk" - - name: RSA_KEY - value: |- - -----BEGIN PUBLIC KEY----- - MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0JWaCc/F+/uV5zJQ7ryN - uzvO+oGgT7z9uXm11qtKae86H3Z3W4qX+gGPs5LrFg444yDRMLqKzPLwuS2yc4mz - QxtVbJyBZijbEDVd/knycj6MxFdBkbjxeGeWYT8nuZf4jBnWB48/O+uUnCbIYt8Q - hUtyJ+KMIXkxrOd4mOgL6dQSCEAIcxBh10ZAucDQIgCn2BrD595uPrvlrrioV/Nq - P0w0qIaKS785YU75qM4rT8tGeWVMEGst4AaRwfV7ZdVe065TP0hjd9sv8iJkr7En - /Zym1NXcKbpwoeT3X9E7cVSARPFhZU1mmtL56wq3QLeFxef9TmVva1/Io0mKn4ah - Uly5jgOpazrXliKJUoOurfMOakkHWfqSd5EfmRTh5nBcNqxtytLdiH0WlCkPSm+Z - Ue3aY91YwcRnFhImLpbQYD5aVLAryzu+IdfRJa+zcZYSK0N8n9irg6jSrQZBct7z - OagHUc0n/ZDP/BO8m0jlpJ7jH+N31Z5qFoNSaxf5H1Y/CwByXtzHJ1k2LleYsr9k - k40nMY4l+SXCe4PmW4zW9uP3ItBWKEI2jFrRJgowQvL0MwtzDhbX9qg4+L9eBFpK - jpHXr2kgLu4srIyXH6JO5UmE/62mHZh0SuqtOT1GQqWde5RjZyidYkwkAHup/AqA - P0TPL/poQ6yvI9a0i22TCpcCAwEAAQ== - -----END PUBLIC KEY----- - volumeMounts: - - mountPath: /etc/cpk - name: cpk-registration-volume - volumes: - - name: cpk-registration-volume - secret: - optional: true - secretName: cpk-registration diff --git a/installers/olm/config/redhat/related-images.yaml b/installers/olm/config/redhat/related-images.yaml deleted file mode 100644 index 7feea0c3f2..0000000000 --- a/installers/olm/config/redhat/related-images.yaml +++ /dev/null @@ -1,78 +0,0 @@ -# Red Hat Marketplace requires that bundles work offline. OSBS will fill out -# the "spec.relatedImages" field of the ClusterServiceVersion if it is blank. -# -# https://redhat-connect.gitbook.io/certified-operator-guide/troubleshooting-and-resources/offline-enabled-operators -# https://osbs.readthedocs.io/en/latest/users.html#pinning-pullspecs-for-related-images -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pgo -spec: - template: - spec: - containers: - - name: operator - image: registry.connect.redhat.com/crunchydata/postgres-operator@sha256: - env: - - { - name: RELATED_IMAGE_PGADMIN, - value: "registry.connect.redhat.com/crunchydata/crunchy-pgadmin4@sha256:", - } - - { - name: RELATED_IMAGE_STANDALONE_PGADMIN, - value: "registry.connect.redhat.com/crunchydata/crunchy-pgadmin4@sha256:", - } - - { - name: RELATED_IMAGE_PGBACKREST, - value: "registry.connect.redhat.com/crunchydata/crunchy-pgbackrest@sha256:", - } - - { - name: RELATED_IMAGE_PGBOUNCER, - value: "registry.connect.redhat.com/crunchydata/crunchy-pgbouncer@sha256:", - } - - { - name: RELATED_IMAGE_PGEXPORTER, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-exporter@sha256:", - } - - { - name: RELATED_IMAGE_PGUPGRADE, - value: "registry.connect.redhat.com/crunchydata/crunchy-upgrade@sha256:", - } - - - { - name: RELATED_IMAGE_POSTGRES_14, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_15, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_16, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres@sha256:", - } - - - { - name: RELATED_IMAGE_POSTGRES_14_GIS_3.1, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_14_GIS_3.2, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_14_GIS_3.3, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_15_GIS_3.3, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_16_GIS_3.3, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } - - { - name: RELATED_IMAGE_POSTGRES_16_GIS_3.4, - value: "registry.connect.redhat.com/crunchydata/crunchy-postgres-gis@sha256:", - } diff --git a/installers/olm/description.md b/installers/olm/description.md deleted file mode 100644 index 4528ba5aad..0000000000 --- a/installers/olm/description.md +++ /dev/null @@ -1,75 +0,0 @@ -[Crunchy Postgres for Kubernetes](https://www.crunchydata.com/products/crunchy-postgresql-for-kubernetes), is the leading Kubernetes native -Postgres solution. Built on PGO, the Postgres Operator from Crunchy Data, Crunchy Postgres for Kubernetes gives you a declarative Postgres -solution that automatically manages your PostgreSQL clusters. - -Designed for your GitOps workflows, it is [easy to get started](https://access.crunchydata.com/documentation/postgres-operator/latest/quickstart) -with Crunchy Postgres for Kubernetes. Within a few moments, you can have a production grade Postgres cluster complete with high availability, disaster -recovery, and monitoring, all over secure TLS communications. Even better, Crunchy Postgres for Kubernetes lets you easily customize your Postgres -cluster to tailor it to your workload! - -With conveniences like cloning Postgres clusters to using rolling updates to roll out disruptive changes with minimal downtime, Crunchy Postgres -for Kubernetes is ready to support your Postgres data at every stage of your release pipeline. Built for resiliency and uptime, Crunchy Postgres -for Kubernetes will keep your Postgres cluster in a desired state so you do not need to worry about it. - -Crunchy Postgres for Kubernetes is developed with many years of production experience in automating Postgres management on Kubernetes, providing -a seamless cloud native Postgres solution to keep your data always available. - -Crunchy Postgres for Kubernetes is made available to users without an active Crunchy Data subscription in connection with Crunchy Data's -[Developer Program](https://www.crunchydata.com/developers/terms-of-use). -For more information, please contact us at [info@crunchydata.com](mailto:info@crunchydata.com). - -- **PostgreSQL Cluster Provisioning**: [Create, Scale, & Delete PostgreSQL clusters with ease][provisioning], - while fully customizing your Pods and PostgreSQL configuration! -- **High-Availability**: Safe, automated failover backed by a [distributed consensus based high-availability solution][high-availability]. - Uses [Pod Anti-Affinity][k8s-anti-affinity] to help resiliency; you can configure how aggressive this can be! - Failed primaries automatically heal, allowing for faster recovery time. You can even create regularly scheduled - backups as well and set your backup retention policy -- **Disaster Recovery**: [Backups][backups] and [restores][disaster-recovery] leverage the open source [pgBackRest][] utility and - [includes support for full, incremental, and differential backups as well as efficient delta restores][backups]. - Set how long you want your backups retained for. Works great with very large databases! -- **Monitoring**: [Track the health of your PostgreSQL clusters][monitoring] using the open source [pgMonitor][] library. -- **Clone**: [Create new clusters from your existing clusters or backups][clone] with efficient data cloning. -- **TLS**: All connections are over [TLS][tls]. You can also [bring your own TLS infrastructure][tls] if you do not want to use the provided defaults. -- **Connection Pooling**: Advanced [connection pooling][pool] support using [pgBouncer][]. -- **Affinity and Tolerations**: Have your PostgreSQL clusters deployed to [Kubernetes Nodes][k8s-nodes] of your preference. - Set your [pod anti-affinity][k8s-anti-affinity], node affinity, Pod tolerations and more rules to customize your deployment topology! -- **PostgreSQL Major Version Upgrades**: Perform a [PostgreSQL major version upgrade][major-version-upgrade] declaratively. -- **Database Administration**: Easily deploy [pgAdmin4][pgadmin] to administer your PostgresClusters' databases. - The automatic discovery of PostgresClusters ensures that you are able to seamlessly access any databases within your environment from the pgAdmin4 GUI. -- **Full Customizability**: Crunchy PostgreSQL for Kubernetes makes it easy to get your own PostgreSQL-as-a-Service up and running - and fully customize your deployments, including: - - Choose the resources for your Postgres cluster: [container resources and storage size][resize-cluster]. [Resize at any time][resize-cluster] with minimal disruption. - - Use your own container image repository, including support `imagePullSecrets` and private repositories - - [Customize your PostgreSQL configuration][customize-cluster] - -and much more! - -[backups]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/backups-disaster-recovery -[clone]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/disaster-recovery -[customize-cluster]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/day-two/customize-cluster -[disaster-recovery]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/backups-disaster-recovery/disaster-recovery -[high-availability]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/day-two/high-availability -[major-version-upgrade]: https://access.crunchydata.com/documentation/postgres-operator/v5/guides/major-postgres-version-upgrade/ -[monitoring]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/day-two/monitoring -[pool]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/basic-setup/connection-pooling -[provisioning]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/basic-setup/create-cluster -[resize-cluster]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/cluster-management/resize-cluster -[tls]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/day-two/customize-cluster#customize-tls - -[k8s-anti-affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity -[k8s-nodes]: https://kubernetes.io/docs/concepts/architecture/nodes/ - -[pgAdmin]: https://www.pgadmin.org/ -[pgBackRest]: https://www.pgbackrest.org -[pgBouncer]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials/basic-setup/connection-pooling -[pgMonitor]: https://github.com/CrunchyData/pgmonitor - -## Post-Installation - -### Tutorial - -Want to [learn more about the PostgreSQL Operator][tutorial]? Browse through the [tutorial][] to learn more about what you can do, [join the Discord server][discord] for community support, or check out the [PGO GitHub repo][ghrepo] to learn more about the open source Postgres Operator project that powers Crunchy Postgres for Kubernetes. - -[tutorial]: https://access.crunchydata.com/documentation/postgres-operator/v5/tutorials -[discord]: https://discord.gg/a7vWKG8Ec9 -[ghrepo]: https://github.com/CrunchyData/postgres-operator diff --git a/installers/olm/generate.sh b/installers/olm/generate.sh deleted file mode 100755 index 8814bd4c75..0000000000 --- a/installers/olm/generate.sh +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env bash -# shellcheck disable=SC2016 -# vim: set noexpandtab : -set -eu - -DISTRIBUTION="$1" - -cd "${BASH_SOURCE[0]%/*}" - -bundle_directory="bundles/${DISTRIBUTION}" -project_directory="projects/${DISTRIBUTION}" -go_api_directory=$(cd ../../pkg/apis && pwd) - -# The 'operators.operatorframework.io.bundle.package.v1' package name for each -# bundle (updated for the 'certified' and 'marketplace' bundles). -package_name='postgresql' - -# The project name used by operator-sdk for initial bundle generation. -project_name='postgresoperator' - -# The prefix for the 'clusterserviceversion.yaml' file. -# Per OLM guidance, the filename for the clusterserviceversion.yaml must be prefixed -# with the Operator's package name for the 'redhat' and 'marketplace' bundles. -# https://github.com/redhat-openshift-ecosystem/certification-releases/blob/main/4.9/ga/troubleshooting.md#get-supported-versions -file_name='postgresoperator' -case "${DISTRIBUTION}" in - # https://redhat-connect.gitbook.io/certified-operator-guide/appendix/what-if-ive-already-published-a-community-operator - 'redhat') - file_name='crunchy-postgres-operator' - package_name='crunchy-postgres-operator' - ;; - # https://github.com/redhat-openshift-ecosystem/certification-releases/blob/main/4.9/ga/ci-pipeline.md#bundle-structure - 'marketplace') - file_name='crunchy-postgres-operator-rhmp' - package_name='crunchy-postgres-operator-rhmp' - ;; -esac - -operator_yamls=$(kubectl kustomize "config/${DISTRIBUTION}") -operator_crds=$(yq <<< "${operator_yamls}" --slurp --yaml-roundtrip 'map(select(.kind == "CustomResourceDefinition"))') -operator_deployments=$(yq <<< "${operator_yamls}" --slurp --yaml-roundtrip 'map(select(.kind == "Deployment"))') -operator_accounts=$(yq <<< "${operator_yamls}" --slurp --yaml-roundtrip 'map(select(.kind == "ServiceAccount"))') -operator_roles=$(yq <<< "${operator_yamls}" --slurp --yaml-roundtrip 'map(select(.kind == "ClusterRole"))') - -# Recreate the Operator SDK project. -[ ! -d "${project_directory}" ] || rm -r "${project_directory}" -install -d "${project_directory}" -( - cd "${project_directory}" - operator-sdk init --fetch-deps='false' --project-name=${project_name} - rm ./*.go go.* - - # Generate CRD descriptions from Go markers. - # https://sdk.operatorframework.io/docs/building-operators/golang/references/markers/ - crd_gvks=$(yq <<< "${operator_crds}" 'map({ - group: .spec.group, kind: .spec.names.kind, version: .spec.versions[].name - })') - yq --in-place --yaml-roundtrip --argjson resources "${crd_gvks}" \ - '.multigroup = true | .resources = $resources | .' ./PROJECT - - ln -s "${go_api_directory}" . - operator-sdk generate kustomize manifests --interactive='false' -) - -# Recreate the OLM bundle. -[ ! -d "${bundle_directory}" ] || rm -r "${bundle_directory}" -install -d \ - "${bundle_directory}/manifests" \ - "${bundle_directory}/metadata" \ - "${bundle_directory}/tests/scorecard" \ - -# `echo "${operator_yamls}" | operator-sdk generate bundle` includes the ServiceAccount which cannot -# be upgraded: https://github.com/operator-framework/operator-lifecycle-manager/issues/2193 - -# Include Operator SDK scorecard tests. -# https://sdk.operatorframework.io/docs/advanced-topics/scorecard/scorecard/ -kubectl kustomize "${project_directory}/config/scorecard" \ - > "${bundle_directory}/tests/scorecard/config.yaml" - -# Render bundle annotations and strip comments. -# Per Red Hat we should not include the org.opencontainers annotations in the -# 'redhat' & 'marketplace' annotations.yaml file, so only add them for 'community'. -# - https://coreos.slack.com/team/UP1LZCC1Y -if [ ${DISTRIBUTION} == 'community' ]; then -yq --yaml-roundtrip < bundle.annotations.yaml > "${bundle_directory}/metadata/annotations.yaml" \ - --arg package "${package_name}" \ -' - .annotations["operators.operatorframework.io.bundle.package.v1"] = $package | - .annotations["org.opencontainers.image.authors"] = "info@crunchydata.com" | - .annotations["org.opencontainers.image.url"] = "https://crunchydata.com" | - .annotations["org.opencontainers.image.vendor"] = "Crunchy Data" | -.' -else -yq --yaml-roundtrip < bundle.annotations.yaml > "${bundle_directory}/metadata/annotations.yaml" \ - --arg package "${package_name}" \ -' - .annotations["operators.operatorframework.io.bundle.package.v1"] = $package | -.' -fi - -# Copy annotations into Dockerfile LABELs. -labels=$(yq --raw-output < "${bundle_directory}/metadata/annotations.yaml" \ - '.annotations | to_entries | map(.key +"="+ (.value | tojson)) | join(" \\\n\t")') -ANNOTATIONS="${labels}" envsubst '$ANNOTATIONS' < bundle.Dockerfile > "${bundle_directory}/Dockerfile" - -# Include CRDs as manifests. -crd_names=$(yq --raw-output <<< "${operator_crds}" 'to_entries[] | [.key, .value.metadata.name] | @tsv') -while IFS=$'\t' read -r index name; do - yq --yaml-roundtrip <<< "${operator_crds}" ".[${index}]" > "${bundle_directory}/manifests/${name}.crd.yaml" -done <<< "${crd_names}" - - -abort() { echo >&2 "$@"; exit 1; } -dump() { yq --color-output; } - -yq > /dev/null <<< "${operator_deployments}" --exit-status 'length == 1' || - abort "too many deployments!" $'\n'"$(dump <<< "${operator_deployments}")" - -yq > /dev/null <<< "${operator_accounts}" --exit-status 'length == 1' || - abort "too many service accounts!" $'\n'"$(dump <<< "${operator_accounts}")" - -yq > /dev/null <<< "${operator_roles}" --exit-status 'length == 1' || - abort "too many roles!" $'\n'"$(dump <<< "${operator_roles}")" - -# Render bundle CSV and strip comments. - -csv_stem=$(yq --raw-output '.projectName' "${project_directory}/PROJECT") - -crd_descriptions=$(yq '.spec.customresourcedefinitions.owned' \ -"${project_directory}/config/manifests/bases/${csv_stem}.clusterserviceversion.yaml") - -crd_gvks=$(yq <<< "${operator_crds}" 'map({ - group: .spec.group, kind: .spec.names.kind, version: .spec.versions[].name -} | { - apiVersion: "\(.group)/\(.version)", kind -})') -crd_examples=$(yq <<< "${operator_yamls}" --slurp --argjson gvks "${crd_gvks}" 'map(select( - IN({ apiVersion, kind }; $gvks | .[]) -))') - -yq --yaml-roundtrip < bundle.csv.yaml > "${bundle_directory}/manifests/${file_name}.clusterserviceversion.yaml" \ - --argjson deployment "$(yq <<< "${operator_deployments}" 'first')" \ - --argjson account "$(yq <<< "${operator_accounts}" 'first | .metadata.name')" \ - --argjson rules "$(yq <<< "${operator_roles}" 'first | .rules')" \ - --argjson crds "${crd_descriptions}" \ - --arg examples "${crd_examples}" \ - --arg version "${PGO_VERSION}" \ - --arg replaces "${REPLACES_VERSION}" \ - --arg description "$(< description.md)" \ - --arg icon "$(base64 ../seal.svg | tr -d '\n')" \ - --arg stem "${csv_stem}" \ -' - .metadata.annotations["alm-examples"] = $examples | - .metadata.annotations["containerImage"] = ($deployment.spec.template.spec.containers[0].image) | - - .metadata.name = "\($stem).v\($version)" | - .spec.version = $version | - .spec.replaces = "\($stem).v\($replaces)" | - - .spec.customresourcedefinitions.owned = $crds | - .spec.description = $description | - .spec.icon = [{ mediatype: "image/svg+xml", base64data: $icon }] | - - .spec.install.spec.permissions = [{ serviceAccountName: $account, rules: $rules }] | - .spec.install.spec.deployments = [( $deployment | { name: .metadata.name, spec } )] | -.' - -case "${DISTRIBUTION}" in - 'redhat') - # https://redhat-connect.gitbook.io/certified-operator-guide/appendix/what-if-ive-already-published-a-community-operator - yq --in-place --yaml-roundtrip \ - ' - .metadata.annotations.certified = "true" | - .metadata.annotations["containerImage"] = "registry.connect.redhat.com/crunchydata/postgres-operator@sha256:" | - .metadata.annotations["containerImage"] = "registry.connect.redhat.com/crunchydata/postgres-operator@sha256:" | - .' \ - "${bundle_directory}/manifests/${file_name}.clusterserviceversion.yaml" - - # Finally, add related images. NOTE: SHA values will need to be updated - # -https://github.com/redhat-openshift-ecosystem/certification-releases/blob/main/4.9/ga/troubleshooting.md#digest-pinning - cat bundle.relatedImages.yaml >> "${bundle_directory}/manifests/${file_name}.clusterserviceversion.yaml" - ;; - 'marketplace') - # Annotations needed when targeting Red Hat Marketplace - # https://github.com/redhat-openshift-ecosystem/certification-releases/blob/main/4.9/ga/ci-pipeline.md#bundle-structure - yq --in-place --yaml-roundtrip \ - --arg package_url "https://marketplace.redhat.com/en-us/operators/${file_name}" \ - ' - .metadata.annotations["containerImage"] = "registry.connect.redhat.com/crunchydata/postgres-operator@sha256:" | - .metadata.annotations["marketplace.openshift.io/remote-workflow"] = - "\($package_url)/pricing?utm_source=openshift_console" | - .metadata.annotations["marketplace.openshift.io/support-workflow"] = - "\($package_url)/support?utm_source=openshift_console" | - .' \ - "${bundle_directory}/manifests/${file_name}.clusterserviceversion.yaml" - - # Finally, add related images. NOTE: SHA values will need to be updated - # -https://github.com/redhat-openshift-ecosystem/certification-releases/blob/main/4.9/ga/troubleshooting.md#digest-pinning - cat bundle.relatedImages.yaml >> "${bundle_directory}/manifests/${file_name}.clusterserviceversion.yaml" - ;; -esac - -if > /dev/null command -v tree; then tree -C "${bundle_directory}"; fi diff --git a/installers/olm/install.sh b/installers/olm/install.sh deleted file mode 100755 index 2c4f6ce190..0000000000 --- a/installers/olm/install.sh +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env bash -# vim: set noexpandtab : -set -eu - -if command -v oc >/dev/null; then - kubectl() { oc "$@"; } - kubectl version -else - kubectl version --short -fi - -catalog_source() ( - source_namespace="$1" - source_name="$2" - index_image="$3" - - kc() { kubectl --namespace="$source_namespace" "$@"; } - kc get namespace "$source_namespace" --output=jsonpath='{""}' 2>/dev/null || - kc create namespace "$source_namespace" - - # See https://godoc.org/github.com/operator-framework/api/pkg/operators/v1alpha1#CatalogSource - source_json=$(jq --null-input \ - --arg name "${source_name}" \ - --arg image "${index_image}" \ - '{ - apiVersion: "operators.coreos.com/v1alpha1", kind: "CatalogSource", - metadata: { name: $name }, - spec: { - displayName: "Test Registry", - sourceType: "grpc", image: $image - } - }') - kc create --filename=- <<< "$source_json" - - # Wait for Pod to exist and be healthy. - for _ in $(seq 10); do - [ '[]' != "$( kc get pod --selector="olm.catalogSource=${source_name}" --output=jsonpath='{.items}' )" ] && - break || sleep 1s - done - if ! kc wait --for='condition=ready' --timeout='30s' pod --selector="olm.catalogSource=${source_name}"; then - kc logs --previous --tail='-1' --selector="olm.catalogSource=${source_name}" - fi -) - -operator_group() ( - group_namespace="$1" - group_name="$2" - target_namespaces=("${@:3}") - - kc() { kubectl --namespace="$group_namespace" "$@"; } - kc get namespace "$group_namespace" --output=jsonpath='{""}' 2>/dev/null || - kc create namespace "$group_namespace" - - group_json="$( jq <<< '{}' --arg name "$group_name" '{ - apiVersion: "operators.coreos.com/v1", kind: "OperatorGroup", - metadata: { "name": $name }, - spec: { targetNamespaces: [] } - }' )" - - for ns in "${target_namespaces[@]}"; do - group_json="$( jq <<< "$group_json" --arg namespace "$ns" '.spec.targetNamespaces += [ $namespace ]' )" - done - - kc create --filename=- <<< "$group_json" -) - -operator() ( - bundle_directory="$1" index_image="$2" - operator_namespace="$3" - target_namespaces=("${@:4}") - - package_name=$(yq \ - --raw-output '.annotations["operators.operatorframework.io.bundle.package.v1"]' \ - "${bundle_directory}"/*/annotations.yaml) - channel_name=$(yq \ - --raw-output '.annotations["operators.operatorframework.io.bundle.channels.v1"]' \ - "${bundle_directory}"/*/annotations.yaml) - csv_name=$(yq --raw-output '.metadata.name' \ - "${bundle_directory}"/*/*.clusterserviceversion.yaml) - - kc() { kubectl --namespace="$operator_namespace" "$@"; } - - catalog_source "$operator_namespace" olm-catalog-source "${index_image}" - operator_group "$operator_namespace" olm-operator-group "${target_namespaces[@]}" - - # Create a Subscription to install the operator. - # See https://godoc.org/github.com/operator-framework/api/pkg/operators/v1alpha1#Subscription - subscription_json=$(jq --null-input \ - --arg channel "$channel_name" \ - --arg namespace "$operator_namespace" \ - --arg package "$package_name" \ - --arg version "$csv_name" \ - '{ - apiVersion: "operators.coreos.com/v1alpha1", kind: "Subscription", - metadata: { name: $package }, - spec: { - name: $package, - sourceNamespace: $namespace, - source: "olm-catalog-source", - startingCSV: $version, - channel: $channel - } - }') - kc create --filename=- <<< "$subscription_json" - - # Wait for the InstallPlan to exist and be healthy. - for _ in $(seq 10); do - [ '[]' != "$( kc get installplan --output=jsonpath="{.items}" )" ] && - break || sleep 1s - done - if ! kc wait --for='condition=installed' --timeout='30s' installplan --all; then - subscription_uid="$( kc get subscription "$package_name" --output=jsonpath='{.metadata.uid}' )" - installplan_json="$( kc get installplan --output=json )" - - jq <<< "$installplan_json" --arg uid "$subscription_uid" \ - '.items[] | select(.metadata.ownerReferences[] | select(.uid == $uid)).status.conditions' - exit 1 - fi - - # Wait for Deployment to exist and be healthy. - for _ in $(seq 10); do - [ '[]' != "$( kc get deploy --selector="olm.owner=$csv_name" --output=jsonpath='{.items}' )" ] && - break || sleep 1s - done - if ! kc wait --for='condition=available' --timeout='30s' deploy --selector="olm.owner=$csv_name"; then - kc describe pod --selector="olm.owner=$csv_name" - - crashed_containers="$( kc get pod --selector="olm.owner=$csv_name" --output=json )" - crashed_containers="$( jq <<< "$crashed_containers" --raw-output \ - '.items[] | { - pod: .metadata.name, - container: .status.containerStatuses[] | select(.restartCount > 0).name - } | [.pod, .container] | @tsv' )" - - test -z "$crashed_containers" || while IFS=$'\t' read -r pod container; do - echo; echo "$pod/$container" restarted: - kc logs --container="$container" --previous --tail='-1' "pod/$pod" - done <<< "$crashed_containers" - - exit 1 - fi -) - -"$@" diff --git a/installers/olm/validate-directory.sh b/installers/olm/validate-directory.sh deleted file mode 100755 index 726f64946e..0000000000 --- a/installers/olm/validate-directory.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# vim: set noexpandtab : -set -eu - -if command -v oc > /dev/null; then - kubectl() { oc "$@"; } - kubectl version -else - kubectl version --short -fi - -push_trap_exit() { - local -a array - eval "array=($(trap -p EXIT))" - # shellcheck disable=SC2064 - trap "$1;${array[2]-}" EXIT -} - -validate_bundle_directory() { - local directory="$1" - local namespace - - namespace=$(kubectl create --filename=- --output='go-template={{.metadata.name}}' <<< '{ - "apiVersion": "v1", "kind": "Namespace", - "metadata": { - "generateName": "olm-test-", - "labels": { "olm-test": "bundle-directory" } - } - }') - echo 'namespace "'"${namespace}"'" created' - push_trap_exit "kubectl delete namespace '${namespace}'" - - # https://olm.operatorframework.io/docs/best-practices/common/ - # https://sdk.operatorframework.io/docs/advanced-topics/scorecard/scorecard/ - operator-sdk scorecard --namespace="${namespace}" "${directory}" -} - -validate_bundle_directory "$@" diff --git a/installers/olm/validate-image.sh b/installers/olm/validate-image.sh deleted file mode 100755 index 9d9adef6cf..0000000000 --- a/installers/olm/validate-image.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash -# vim: set noexpandtab : -set -eu - -push_trap_exit() { - local -a array - eval "array=($(trap -p EXIT))" - # shellcheck disable=SC2064 - trap "$1;${array[2]-}" EXIT -} - -# Store anything in a single temporary directory that gets cleaned up. -TMPDIR=$(mktemp -d) -push_trap_exit "rm -rf '${TMPDIR}'" -export TMPDIR - -validate_bundle_image() { - local container="$1" directory="$2" - directory=$(cd "${directory}" && pwd) - - cat > "${TMPDIR}/registry.config" <<-SSL - [req] - distinguished_name = req_distinguished_name - x509_extensions = v3_ext - prompt = no - [req_distinguished_name] - commonName = localhost - [v3_ext] - subjectAltName = @alt_names - [alt_names] - DNS.1 = localhost - SSL - - openssl ecparam -name prime256v1 -genkey -out "${TMPDIR}/registry.key" - openssl req -new -x509 -days 1 \ - -config "${TMPDIR}/registry.config" \ - -key "${TMPDIR}/registry.key" \ - -out "${TMPDIR}/registry.crt" - - # Start a local image registry. - local image port registry - registry=$(${container} run --detach --publish-all \ - --env='REGISTRY_HTTP_TLS_CERTIFICATE=/mnt/registry.crt' \ - --env='REGISTRY_HTTP_TLS_KEY=/mnt/registry.key' \ - --volume="${TMPDIR}:/mnt" \ - docker.io/library/registry:latest) - # https://github.com/containers/podman/issues/8524 - push_trap_exit "echo -n 'Removing '; ${container} rm '${registry}'" - push_trap_exit "echo -n 'Stopping '; ${container} stop '${registry}'" - - port=$(${container} inspect "${registry}" \ - --format='{{ (index .NetworkSettings.Ports "5000/tcp" 0).HostPort }}') - image="localhost:${port}/postgres-operator-bundle:latest" - - cat > "${TMPDIR}/registries.conf" <<-TOML - [[registry]] - location = "localhost:${port}" - insecure = true - TOML - - # Build the bundle image and push it to the local registry. - ${container} run --rm \ - --device='/dev/fuse:rw' --network='host' --security-opt='seccomp=unconfined' \ - --volume="${TMPDIR}/registries.conf:/etc/containers/registries.conf.d/localhost.conf:ro" \ - --volume="${directory}:/mnt:delegated" \ - --workdir='/mnt' \ - quay.io/buildah/stable:latest \ - buildah build-using-dockerfile \ - --format='docker' --layers --tag="docker://${image}" - - local -a opm - local opm_version - opm_version=$(opm version) - opm_version=$(sed -n 's#.*OpmVersion:"\([^"]*\)".*#\1# p' <<< "${opm_version}") - # shellcheck disable=SC2206 - opm=(${container} run --rm - --network='host' - --volume="${TMPDIR}/registry.crt:/usr/local/share/ca-certificates/registry.crt:ro" - --volume="${TMPDIR}:/mnt:delegated" - --workdir='/mnt' - quay.io/operator-framework/upstream-opm-builder:"${opm_version}" - sh -ceu 'update-ca-certificates && exec "$@"' - opm) - - # Validate the bundle image in the local registry. - # https://olm.operatorframework.io/docs/tasks/creating-operator-bundle/#validating-your-bundle - "${opm[@]}" alpha bundle validate --image-builder='none' \ - --optional-validators='operatorhub,bundle-objects' \ - --tag="${image}" -} - -validate_bundle_image "$@" diff --git a/installers/seal.svg b/installers/seal.svg deleted file mode 100644 index 28e875f48f..0000000000 --- a/installers/seal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/internal/bridge/client.go b/internal/bridge/client.go index 29bd009814..d5ad8470f7 100644 --- a/internal/bridge/client.go +++ b/internal/bridge/client.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/client_test.go b/internal/bridge/client_test.go index 5b1e6f6665..28728c701c 100644 --- a/internal/bridge/client_test.go +++ b/internal/bridge/client_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/crunchybridgecluster/apply.go b/internal/bridge/crunchybridgecluster/apply.go index 5276678fa5..d77d719d6a 100644 --- a/internal/bridge/crunchybridgecluster/apply.go +++ b/internal/bridge/crunchybridgecluster/apply.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller.go b/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller.go index 1743ffdb1c..03d67442be 100644 --- a/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller.go +++ b/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller_test.go b/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller_test.go index 106297ebb2..92d6b58d0e 100644 --- a/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller_test.go +++ b/internal/bridge/crunchybridgecluster/crunchybridgecluster_controller_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/delete.go b/internal/bridge/crunchybridgecluster/delete.go index ccbb1d5ed2..8dcada31cf 100644 --- a/internal/bridge/crunchybridgecluster/delete.go +++ b/internal/bridge/crunchybridgecluster/delete.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/delete_test.go b/internal/bridge/crunchybridgecluster/delete_test.go index 9dfa5b4924..28e6feb1f8 100644 --- a/internal/bridge/crunchybridgecluster/delete_test.go +++ b/internal/bridge/crunchybridgecluster/delete_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/helpers_test.go b/internal/bridge/crunchybridgecluster/helpers_test.go index a290934321..f40ad3d054 100644 --- a/internal/bridge/crunchybridgecluster/helpers_test.go +++ b/internal/bridge/crunchybridgecluster/helpers_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/mock_bridge_api.go b/internal/bridge/crunchybridgecluster/mock_bridge_api.go index 42116e3afb..5c6b243714 100644 --- a/internal/bridge/crunchybridgecluster/mock_bridge_api.go +++ b/internal/bridge/crunchybridgecluster/mock_bridge_api.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/postgres.go b/internal/bridge/crunchybridgecluster/postgres.go index 9fd36dafaa..024631de67 100644 --- a/internal/bridge/crunchybridgecluster/postgres.go +++ b/internal/bridge/crunchybridgecluster/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster @@ -27,7 +16,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/crunchydata/postgres-operator/internal/bridge" - "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/naming" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -45,11 +33,11 @@ func (r *CrunchyBridgeClusterReconciler) generatePostgresRoleSecret( Name: secretName, }} intent.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Secret")) - initialize.StringMap(&intent.StringData) - - intent.StringData["name"] = clusterRole.Name - intent.StringData["password"] = clusterRole.Password - intent.StringData["uri"] = clusterRole.URI + intent.StringData = map[string]string{ + "name": clusterRole.Name, + "password": clusterRole.Password, + "uri": clusterRole.URI, + } intent.Annotations = cluster.Spec.Metadata.GetAnnotationsOrNil() intent.Labels = naming.Merge( diff --git a/internal/bridge/crunchybridgecluster/postgres_test.go b/internal/bridge/crunchybridgecluster/postgres_test.go index a2a854be9f..66add7b789 100644 --- a/internal/bridge/crunchybridgecluster/postgres_test.go +++ b/internal/bridge/crunchybridgecluster/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/watches.go b/internal/bridge/crunchybridgecluster/watches.go index ff8f6a5a52..79687b3476 100644 --- a/internal/bridge/crunchybridgecluster/watches.go +++ b/internal/bridge/crunchybridgecluster/watches.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/crunchybridgecluster/watches_test.go b/internal/bridge/crunchybridgecluster/watches_test.go index a95bd58bc5..48dba2ba14 100644 --- a/internal/bridge/crunchybridgecluster/watches_test.go +++ b/internal/bridge/crunchybridgecluster/watches_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package crunchybridgecluster diff --git a/internal/bridge/installation.go b/internal/bridge/installation.go index 22122cbbcc..c76a073348 100644 --- a/internal/bridge/installation.go +++ b/internal/bridge/installation.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/installation_test.go b/internal/bridge/installation_test.go index e062de8d18..96223a2233 100644 --- a/internal/bridge/installation_test.go +++ b/internal/bridge/installation_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/naming.go b/internal/bridge/naming.go index 7a0124ae7a..cabe8e9cf6 100644 --- a/internal/bridge/naming.go +++ b/internal/bridge/naming.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/quantity.go b/internal/bridge/quantity.go index 1c1915b716..a948c6b4cf 100644 --- a/internal/bridge/quantity.go +++ b/internal/bridge/quantity.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/bridge/quantity_test.go b/internal/bridge/quantity_test.go index e9d2cce100..7cfebb4a86 100644 --- a/internal/bridge/quantity_test.go +++ b/internal/bridge/quantity_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package bridge diff --git a/internal/config/config.go b/internal/config/config.go index 3fe8a81068..e3f9ced215 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package config diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 66fc91e752..7b8ca2f863 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package config @@ -25,30 +14,6 @@ import ( "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) -func saveEnv(t testing.TB, key string) { - t.Helper() - previous, ok := os.LookupEnv(key) - t.Cleanup(func() { - if ok { - os.Setenv(key, previous) - } else { - os.Unsetenv(key) - } - }) -} - -func setEnv(t testing.TB, key, value string) { - t.Helper() - saveEnv(t, key) - assert.NilError(t, os.Setenv(key, value)) -} - -func unsetEnv(t testing.TB, key string) { - t.Helper() - saveEnv(t, key) - assert.NilError(t, os.Unsetenv(key)) -} - func TestFetchKeyCommand(t *testing.T) { spec1 := v1beta1.PostgresClusterSpec{} @@ -117,13 +82,14 @@ func TestFetchKeyCommand(t *testing.T) { func TestPGAdminContainerImage(t *testing.T) { cluster := &v1beta1.PostgresCluster{} - unsetEnv(t, "RELATED_IMAGE_PGADMIN") + t.Setenv("RELATED_IMAGE_PGADMIN", "") + os.Unsetenv("RELATED_IMAGE_PGADMIN") assert.Equal(t, PGAdminContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGADMIN", "") + t.Setenv("RELATED_IMAGE_PGADMIN", "") assert.Equal(t, PGAdminContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGADMIN", "env-var-pgadmin") + t.Setenv("RELATED_IMAGE_PGADMIN", "env-var-pgadmin") assert.Equal(t, PGAdminContainerImage(cluster), "env-var-pgadmin") assert.NilError(t, yaml.Unmarshal([]byte(`{ @@ -135,13 +101,14 @@ func TestPGAdminContainerImage(t *testing.T) { func TestPGBackRestContainerImage(t *testing.T) { cluster := &v1beta1.PostgresCluster{} - unsetEnv(t, "RELATED_IMAGE_PGBACKREST") + t.Setenv("RELATED_IMAGE_PGBACKREST", "") + os.Unsetenv("RELATED_IMAGE_PGBACKREST") assert.Equal(t, PGBackRestContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGBACKREST", "") + t.Setenv("RELATED_IMAGE_PGBACKREST", "") assert.Equal(t, PGBackRestContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGBACKREST", "env-var-pgbackrest") + t.Setenv("RELATED_IMAGE_PGBACKREST", "env-var-pgbackrest") assert.Equal(t, PGBackRestContainerImage(cluster), "env-var-pgbackrest") assert.NilError(t, yaml.Unmarshal([]byte(`{ @@ -153,13 +120,14 @@ func TestPGBackRestContainerImage(t *testing.T) { func TestPGBouncerContainerImage(t *testing.T) { cluster := &v1beta1.PostgresCluster{} - unsetEnv(t, "RELATED_IMAGE_PGBOUNCER") + t.Setenv("RELATED_IMAGE_PGBOUNCER", "") + os.Unsetenv("RELATED_IMAGE_PGBOUNCER") assert.Equal(t, PGBouncerContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGBOUNCER", "") + t.Setenv("RELATED_IMAGE_PGBOUNCER", "") assert.Equal(t, PGBouncerContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGBOUNCER", "env-var-pgbouncer") + t.Setenv("RELATED_IMAGE_PGBOUNCER", "env-var-pgbouncer") assert.Equal(t, PGBouncerContainerImage(cluster), "env-var-pgbouncer") assert.NilError(t, yaml.Unmarshal([]byte(`{ @@ -171,13 +139,14 @@ func TestPGBouncerContainerImage(t *testing.T) { func TestPGExporterContainerImage(t *testing.T) { cluster := &v1beta1.PostgresCluster{} - unsetEnv(t, "RELATED_IMAGE_PGEXPORTER") + t.Setenv("RELATED_IMAGE_PGEXPORTER", "") + os.Unsetenv("RELATED_IMAGE_PGEXPORTER") assert.Equal(t, PGExporterContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGEXPORTER", "") + t.Setenv("RELATED_IMAGE_PGEXPORTER", "") assert.Equal(t, PGExporterContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_PGEXPORTER", "env-var-pgexporter") + t.Setenv("RELATED_IMAGE_PGEXPORTER", "env-var-pgexporter") assert.Equal(t, PGExporterContainerImage(cluster), "env-var-pgexporter") assert.NilError(t, yaml.Unmarshal([]byte(`{ @@ -189,13 +158,14 @@ func TestPGExporterContainerImage(t *testing.T) { func TestStandalonePGAdminContainerImage(t *testing.T) { pgadmin := &v1beta1.PGAdmin{} - unsetEnv(t, "RELATED_IMAGE_STANDALONE_PGADMIN") + t.Setenv("RELATED_IMAGE_STANDALONE_PGADMIN", "") + os.Unsetenv("RELATED_IMAGE_STANDALONE_PGADMIN") assert.Equal(t, StandalonePGAdminContainerImage(pgadmin), "") - setEnv(t, "RELATED_IMAGE_STANDALONE_PGADMIN", "") + t.Setenv("RELATED_IMAGE_STANDALONE_PGADMIN", "") assert.Equal(t, StandalonePGAdminContainerImage(pgadmin), "") - setEnv(t, "RELATED_IMAGE_STANDALONE_PGADMIN", "env-var-pgadmin") + t.Setenv("RELATED_IMAGE_STANDALONE_PGADMIN", "env-var-pgadmin") assert.Equal(t, StandalonePGAdminContainerImage(pgadmin), "env-var-pgadmin") assert.NilError(t, yaml.Unmarshal([]byte(`{ @@ -208,13 +178,14 @@ func TestPostgresContainerImage(t *testing.T) { cluster := &v1beta1.PostgresCluster{} cluster.Spec.PostgresVersion = 12 - unsetEnv(t, "RELATED_IMAGE_POSTGRES_12") + t.Setenv("RELATED_IMAGE_POSTGRES_12", "") + os.Unsetenv("RELATED_IMAGE_POSTGRES_12") assert.Equal(t, PostgresContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_POSTGRES_12", "") + t.Setenv("RELATED_IMAGE_POSTGRES_12", "") assert.Equal(t, PostgresContainerImage(cluster), "") - setEnv(t, "RELATED_IMAGE_POSTGRES_12", "env-var-postgres") + t.Setenv("RELATED_IMAGE_POSTGRES_12", "env-var-postgres") assert.Equal(t, PostgresContainerImage(cluster), "env-var-postgres") cluster.Spec.Image = "spec-image" @@ -222,7 +193,7 @@ func TestPostgresContainerImage(t *testing.T) { cluster.Spec.Image = "" cluster.Spec.PostGISVersion = "3.0" - setEnv(t, "RELATED_IMAGE_POSTGRES_12_GIS_3.0", "env-var-postgis") + t.Setenv("RELATED_IMAGE_POSTGRES_12_GIS_3.0", "env-var-postgis") assert.Equal(t, PostgresContainerImage(cluster), "env-var-postgis") cluster.Spec.Image = "spec-image" @@ -233,7 +204,9 @@ func TestVerifyImageValues(t *testing.T) { cluster := &v1beta1.PostgresCluster{} verifyImageCheck := func(t *testing.T, envVar, errString string, cluster *v1beta1.PostgresCluster) { - unsetEnv(t, envVar) + + t.Setenv(envVar, "") + os.Unsetenv(envVar) err := VerifyImageValues(cluster) assert.ErrorContains(t, err, errString) } diff --git a/internal/controller/pgupgrade/apply.go b/internal/controller/pgupgrade/apply.go index 5e3719cb19..71cf65cd4f 100644 --- a/internal/controller/pgupgrade/apply.go +++ b/internal/controller/pgupgrade/apply.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/jobs.go b/internal/controller/pgupgrade/jobs.go index 045df3a929..a1722dfc12 100644 --- a/internal/controller/pgupgrade/jobs.go +++ b/internal/controller/pgupgrade/jobs.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade @@ -192,8 +182,8 @@ func (r *PGUpgradeReconciler) generateUpgradeJob( // The following will set these fields to null if not set in the spec job.Spec.Template.Spec.Affinity = upgrade.Spec.Affinity - job.Spec.Template.Spec.PriorityClassName = initialize.FromPointer( - upgrade.Spec.PriorityClassName) + job.Spec.Template.Spec.PriorityClassName = + initialize.FromPointer(upgrade.Spec.PriorityClassName) job.Spec.Template.Spec.Tolerations = upgrade.Spec.Tolerations r.setControllerReference(upgrade, job) @@ -302,8 +292,8 @@ func (r *PGUpgradeReconciler) generateRemoveDataJob( // The following will set these fields to null if not set in the spec job.Spec.Template.Spec.Affinity = upgrade.Spec.Affinity - job.Spec.Template.Spec.PriorityClassName = initialize.FromPointer( - upgrade.Spec.PriorityClassName) + job.Spec.Template.Spec.PriorityClassName = + initialize.FromPointer(upgrade.Spec.PriorityClassName) job.Spec.Template.Spec.Tolerations = upgrade.Spec.Tolerations r.setControllerReference(upgrade, job) diff --git a/internal/controller/pgupgrade/jobs_test.go b/internal/controller/pgupgrade/jobs_test.go index ebbd5b58c9..8dfc4731a2 100644 --- a/internal/controller/pgupgrade/jobs_test.go +++ b/internal/controller/pgupgrade/jobs_test.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade @@ -262,42 +252,17 @@ status: {} `)) } -// saveEnv preserves environment variables so that any modifications needed for -// the tests can be undone once completed. -func saveEnv(t testing.TB, key string) { - t.Helper() - previous, ok := os.LookupEnv(key) - t.Cleanup(func() { - if ok { - os.Setenv(key, previous) - } else { - os.Unsetenv(key) - } - }) -} - -func setEnv(t testing.TB, key, value string) { - t.Helper() - saveEnv(t, key) - assert.NilError(t, os.Setenv(key, value)) -} - -func unsetEnv(t testing.TB, key string) { - t.Helper() - saveEnv(t, key) - assert.NilError(t, os.Unsetenv(key)) -} - func TestPGUpgradeContainerImage(t *testing.T) { upgrade := &v1beta1.PGUpgrade{} - unsetEnv(t, "RELATED_IMAGE_PGUPGRADE") + t.Setenv("RELATED_IMAGE_PGUPGRADE", "") + os.Unsetenv("RELATED_IMAGE_PGUPGRADE") assert.Equal(t, pgUpgradeContainerImage(upgrade), "") - setEnv(t, "RELATED_IMAGE_PGUPGRADE", "") + t.Setenv("RELATED_IMAGE_PGUPGRADE", "") assert.Equal(t, pgUpgradeContainerImage(upgrade), "") - setEnv(t, "RELATED_IMAGE_PGUPGRADE", "env-var-pgbackrest") + t.Setenv("RELATED_IMAGE_PGUPGRADE", "env-var-pgbackrest") assert.Equal(t, pgUpgradeContainerImage(upgrade), "env-var-pgbackrest") assert.NilError(t, yaml.Unmarshal( @@ -309,7 +274,8 @@ func TestVerifyUpgradeImageValue(t *testing.T) { upgrade := &v1beta1.PGUpgrade{} t.Run("crunchy-postgres", func(t *testing.T) { - unsetEnv(t, "RELATED_IMAGE_PGUPGRADE") + t.Setenv("RELATED_IMAGE_PGUPGRADE", "") + os.Unsetenv("RELATED_IMAGE_PGUPGRADE") err := verifyUpgradeImageValue(upgrade) assert.ErrorContains(t, err, "crunchy-upgrade") }) diff --git a/internal/controller/pgupgrade/labels.go b/internal/controller/pgupgrade/labels.go index e7cf11bc0e..187fe6bf6f 100644 --- a/internal/controller/pgupgrade/labels.go +++ b/internal/controller/pgupgrade/labels.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/pgupgrade_controller.go b/internal/controller/pgupgrade/pgupgrade_controller.go index 8599b78a4b..d6d145b793 100644 --- a/internal/controller/pgupgrade/pgupgrade_controller.go +++ b/internal/controller/pgupgrade/pgupgrade_controller.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/registration.go b/internal/controller/pgupgrade/registration.go index 895f1a44a1..05d0d80cbd 100644 --- a/internal/controller/pgupgrade/registration.go +++ b/internal/controller/pgupgrade/registration.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/registration_test.go b/internal/controller/pgupgrade/registration_test.go index dccd9e893d..dc3a4144bc 100644 --- a/internal/controller/pgupgrade/registration_test.go +++ b/internal/controller/pgupgrade/registration_test.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/utils.go b/internal/controller/pgupgrade/utils.go index e5b62d1d46..292107e440 100644 --- a/internal/controller/pgupgrade/utils.go +++ b/internal/controller/pgupgrade/utils.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/world.go b/internal/controller/pgupgrade/world.go index a3e15e84c7..18d056fe25 100644 --- a/internal/controller/pgupgrade/world.go +++ b/internal/controller/pgupgrade/world.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/pgupgrade/world_test.go b/internal/controller/pgupgrade/world_test.go index d65da88df6..4aa24f714d 100644 --- a/internal/controller/pgupgrade/world_test.go +++ b/internal/controller/pgupgrade/world_test.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package pgupgrade diff --git a/internal/controller/postgrescluster/apply.go b/internal/controller/postgrescluster/apply.go index dbdf20d785..2dae1f7d80 100644 --- a/internal/controller/postgrescluster/apply.go +++ b/internal/controller/postgrescluster/apply.go @@ -1,33 +1,15 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster import ( "context" - "encoding/json" - "fmt" "reflect" - jsonpatch "github.com/evanphx/json-patch/v5" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/validation/field" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/crunchydata/postgres-operator/internal/kubeapi" @@ -57,11 +39,6 @@ func (r *Reconciler) apply(ctx context.Context, object client.Object) error { // does not match the intent, send a json-patch to get really specific. switch actual := object.(type) { case *corev1.Service: - // Changing Service.Spec.Type requires a special apply-patch sometimes. - if err != nil { - err = r.handleServiceError(ctx, object.(*corev1.Service), data, err) - } - applyServiceSpec(patch, actual.Spec, intent.(*corev1.Service).Spec, "spec") } @@ -72,53 +49,6 @@ func (r *Reconciler) apply(ctx context.Context, object client.Object) error { return err } -// handleServiceError inspects err for expected Kubernetes API responses to -// writing a Service. It returns err when it cannot resolve the issue, otherwise -// it returns nil. -func (r *Reconciler) handleServiceError( - ctx context.Context, service *corev1.Service, apply []byte, err error, -) error { - var status metav1.Status - if api := apierrors.APIStatus(nil); errors.As(err, &api) { - status = api.Status() - } - - // Service.Spec.Ports.NodePort must be cleared for ClusterIP prior to - // Kubernetes 1.20. When all the errors are about disallowed "nodePort", - // run a json-patch on the apply-patch to set them all to null. - // - https://issue.k8s.io/33766 - if service.Spec.Type == corev1.ServiceTypeClusterIP { - add := json.RawMessage(`"add"`) - null := json.RawMessage(`null`) - patch := make(jsonpatch.Patch, 0, len(service.Spec.Ports)) - - if apierrors.IsInvalid(err) && status.Details != nil { - for i, cause := range status.Details.Causes { - path := json.RawMessage(fmt.Sprintf(`"/spec/ports/%d/nodePort"`, i)) - - if cause.Type == metav1.CauseType(field.ErrorTypeForbidden) && - cause.Field == fmt.Sprintf("spec.ports[%d].nodePort", i) { - patch = append(patch, - jsonpatch.Operation{"op": &add, "value": &null, "path": &path}) - } - } - } - - // Amend the apply-patch when all the errors can be fixed. - if len(patch) == len(service.Spec.Ports) { - apply, err = patch.Apply(apply) - } - - // Send the apply-patch with force=true. - if err == nil { - patch := client.RawPatch(client.Apply.Type(), apply) - err = r.patch(ctx, service, patch, client.ForceOwnership) - } - } - - return err -} - // applyServiceSpec is called by Reconciler.apply to work around issues // with server-side apply. func applyServiceSpec( diff --git a/internal/controller/postgrescluster/apply_test.go b/internal/controller/postgrescluster/apply_test.go index 007aebbd9d..c163e8a5ab 100644 --- a/internal/controller/postgrescluster/apply_test.go +++ b/internal/controller/postgrescluster/apply_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -310,55 +299,4 @@ func TestServerSideApply(t *testing.T) { }) } }) - - t.Run("ServiceType", func(t *testing.T) { - constructor := func(name string) *corev1.Service { - var service corev1.Service - service.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Service")) - service.Namespace, service.Name = ns.Name, name - service.Spec.Ports = []corev1.ServicePort{ - {Name: "one", Port: 9999, Protocol: corev1.ProtocolTCP}, - {Name: "two", Port: 1234, Protocol: corev1.ProtocolTCP}, - } - return &service - } - - reconciler := Reconciler{Client: cc, Owner: client.FieldOwner(t.Name())} - - // Start as NodePort. - intent := constructor("node-port") - intent.Spec.Type = corev1.ServiceTypeNodePort - - // Create the Service. - before := intent.DeepCopy() - assert.NilError(t, - cc.Patch(ctx, before, client.Apply, client.ForceOwnership, reconciler.Owner)) - - // Change to ClusterIP. - intent.Spec.Type = corev1.ServiceTypeClusterIP - - // client.Apply cannot change it in old versions of Kubernetes. - after := intent.DeepCopy() - err := cc.Patch(ctx, after, client.Apply, client.ForceOwnership, reconciler.Owner) - - switch { - case serverVersion.LessThan(version.MustParseGeneric("1.20")): - - assert.ErrorContains(t, err, "nodePort: Forbidden", - "expected https://issue.k8s.io/33766") - - default: - assert.NilError(t, err) - assert.Equal(t, after.Spec.Type, intent.Spec.Type) - assert.Equal(t, after.Spec.ClusterIP, before.Spec.ClusterIP, - "expected to keep the same ClusterIP") - } - - // Our apply method changes it. - again := intent.DeepCopy() - assert.NilError(t, reconciler.apply(ctx, again)) - assert.Equal(t, again.Spec.Type, intent.Spec.Type) - assert.Equal(t, again.Spec.ClusterIP, before.Spec.ClusterIP, - "expected to keep the same ClusterIP") - }) } diff --git a/internal/controller/postgrescluster/cluster.go b/internal/controller/postgrescluster/cluster.go index 2018dc3f95..3ba6eab0e8 100644 --- a/internal/controller/postgrescluster/cluster.go +++ b/internal/controller/postgrescluster/cluster.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -26,6 +15,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/naming" "github.com/crunchydata/postgres-operator/internal/patroni" "github.com/crunchydata/postgres-operator/internal/pki" @@ -248,6 +238,8 @@ func (r *Reconciler) generateClusterReplicaService( } servicePort.NodePort = *spec.NodePort } + service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) + service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/internal/controller/postgrescluster/cluster_test.go b/internal/controller/postgrescluster/cluster_test.go index e6df7afead..be9e371a56 100644 --- a/internal/controller/postgrescluster/cluster_test.go +++ b/internal/controller/postgrescluster/cluster_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/controller.go b/internal/controller/postgrescluster/controller.go index c038d36e68..d459d30a10 100644 --- a/internal/controller/postgrescluster/controller.go +++ b/internal/controller/postgrescluster/controller.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -179,6 +168,7 @@ func (r *Reconciler) Reconcile( err error backupsSpecFound bool backupsReconciliationAllowed bool + dedicatedSnapshotPVC *corev1.PersistentVolumeClaim ) patchClusterStatus := func() error { @@ -375,7 +365,10 @@ func (r *Reconciler) Reconcile( } } if err == nil { - err = r.reconcileVolumeSnapshots(ctx, cluster, instances, clusterVolumes) + dedicatedSnapshotPVC, err = r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + } + if err == nil { + err = r.reconcileVolumeSnapshots(ctx, cluster, dedicatedSnapshotPVC) } if err == nil { err = r.reconcilePGBouncer(ctx, cluster, instances, primaryCertificate, rootCA) diff --git a/internal/controller/postgrescluster/controller_ref_manager.go b/internal/controller/postgrescluster/controller_ref_manager.go index e3ceb667db..8c4a34189f 100644 --- a/internal/controller/postgrescluster/controller_ref_manager.go +++ b/internal/controller/postgrescluster/controller_ref_manager.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/controller_ref_manager_test.go b/internal/controller/postgrescluster/controller_ref_manager_test.go index c03745fa12..8543fe390d 100644 --- a/internal/controller/postgrescluster/controller_ref_manager_test.go +++ b/internal/controller/postgrescluster/controller_ref_manager_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/controller_test.go b/internal/controller/postgrescluster/controller_test.go index 7cd8360a8b..e6fdc5cb86 100644 --- a/internal/controller/postgrescluster/controller_test.go +++ b/internal/controller/postgrescluster/controller_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/delete.go b/internal/controller/postgrescluster/delete.go index fdc85f73b1..63fc007f40 100644 --- a/internal/controller/postgrescluster/delete.go +++ b/internal/controller/postgrescluster/delete.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/helpers_test.go b/internal/controller/postgrescluster/helpers_test.go index 26123076ba..0536b466d4 100644 --- a/internal/controller/postgrescluster/helpers_test.go +++ b/internal/controller/postgrescluster/helpers_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -22,6 +11,7 @@ import ( "testing" "time" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -32,6 +22,7 @@ import ( "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/initialize" + "github.com/crunchydata/postgres-operator/internal/naming" "github.com/crunchydata/postgres-operator/internal/testing/require" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -110,6 +101,7 @@ func testVolumeClaimSpec() corev1.PersistentVolumeClaimSpec { }, } } + func testCluster() *v1beta1.PostgresCluster { // Defines a base cluster spec that can be used by tests to generate a // cluster with an expected number of instances @@ -149,6 +141,58 @@ func testCluster() *v1beta1.PostgresCluster { return cluster.DeepCopy() } +func testBackupJob(cluster *v1beta1.PostgresCluster) *batchv1.Job { + job := batchv1.Job{ + TypeMeta: metav1.TypeMeta{ + APIVersion: batchv1.SchemeGroupVersion.String(), + Kind: "Job", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "backup-job-1", + Namespace: cluster.Namespace, + Labels: map[string]string{ + naming.LabelCluster: cluster.Name, + naming.LabelPGBackRestBackup: "", + naming.LabelPGBackRestRepo: "repo1", + }, + }, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{Name: "test", Image: "test"}}, + RestartPolicy: corev1.RestartPolicyNever, + }, + }, + }, + } + + return job.DeepCopy() +} + +func testRestoreJob(cluster *v1beta1.PostgresCluster) *batchv1.Job { + job := batchv1.Job{ + TypeMeta: metav1.TypeMeta{ + APIVersion: batchv1.SchemeGroupVersion.String(), + Kind: "Job", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-job-1", + Namespace: cluster.Namespace, + Labels: naming.PGBackRestRestoreJobLabels(cluster.Name), + }, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{Name: "test", Image: "test"}}, + RestartPolicy: corev1.RestartPolicyNever, + }, + }, + }, + } + + return job.DeepCopy() +} + // setupManager creates the runtime manager used during controller testing func setupManager(t *testing.T, cfg *rest.Config, controllerSetup func(mgr manager.Manager)) (context.Context, context.CancelFunc) { diff --git a/internal/controller/postgrescluster/instance.go b/internal/controller/postgrescluster/instance.go index 8435f4a064..66321cc738 100644 --- a/internal/controller/postgrescluster/instance.go +++ b/internal/controller/postgrescluster/instance.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -1309,15 +1298,11 @@ func generateInstanceStatefulSetIntent(_ context.Context, sts.Spec.Template.Spec.Affinity = spec.Affinity sts.Spec.Template.Spec.Tolerations = spec.Tolerations sts.Spec.Template.Spec.TopologySpreadConstraints = spec.TopologySpreadConstraints - if spec.PriorityClassName != nil { - sts.Spec.Template.Spec.PriorityClassName = *spec.PriorityClassName - } + sts.Spec.Template.Spec.PriorityClassName = initialize.FromPointer(spec.PriorityClassName) // if default pod scheduling is not explicitly disabled, add the default // pod topology spread constraints - if cluster.Spec.DisableDefaultPodScheduling == nil || - (cluster.Spec.DisableDefaultPodScheduling != nil && - !*cluster.Spec.DisableDefaultPodScheduling) { + if !initialize.FromPointer(cluster.Spec.DisableDefaultPodScheduling) { sts.Spec.Template.Spec.TopologySpreadConstraints = append( sts.Spec.Template.Spec.TopologySpreadConstraints, defaultTopologySpreadConstraints( diff --git a/internal/controller/postgrescluster/instance.md b/internal/controller/postgrescluster/instance.md index 933ca9bbe3..f0de4c5d7a 100644 --- a/internal/controller/postgrescluster/instance.md +++ b/internal/controller/postgrescluster/instance.md @@ -1,16 +1,7 @@ ## Shutdown and Startup Logic Detail diff --git a/internal/controller/postgrescluster/instance_rollout_test.go b/internal/controller/postgrescluster/instance_rollout_test.go index 15e2abe2a3..e668907497 100644 --- a/internal/controller/postgrescluster/instance_rollout_test.go +++ b/internal/controller/postgrescluster/instance_rollout_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/instance_test.go b/internal/controller/postgrescluster/instance_test.go index a60a9c1698..f7f59f50a5 100644 --- a/internal/controller/postgrescluster/instance_test.go +++ b/internal/controller/postgrescluster/instance_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -1983,7 +1972,7 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name spec := &cluster.Spec.InstanceSets[0] - spec.MinAvailable = initialize.IntOrStringInt32(0) + spec.MinAvailable = initialize.Pointer(intstr.FromInt32(0)) assert.NilError(t, r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, spec)) assert.Assert(t, !foundPDB(cluster, spec)) }) @@ -1992,7 +1981,7 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name spec := &cluster.Spec.InstanceSets[0] - spec.MinAvailable = initialize.IntOrStringInt32(1) + spec.MinAvailable = initialize.Pointer(intstr.FromInt32(1)) assert.NilError(t, r.Client.Create(ctx, cluster)) t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) @@ -2001,7 +1990,7 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { assert.Assert(t, foundPDB(cluster, spec)) t.Run("deleted", func(t *testing.T) { - spec.MinAvailable = initialize.IntOrStringInt32(0) + spec.MinAvailable = initialize.Pointer(intstr.FromInt32(0)) err := r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, spec) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update @@ -2019,7 +2008,7 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name spec := &cluster.Spec.InstanceSets[0] - spec.MinAvailable = initialize.IntOrStringString("50%") + spec.MinAvailable = initialize.Pointer(intstr.FromString("50%")) assert.NilError(t, r.Client.Create(ctx, cluster)) t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) @@ -2028,7 +2017,7 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { assert.Assert(t, foundPDB(cluster, spec)) t.Run("deleted", func(t *testing.T) { - spec.MinAvailable = initialize.IntOrStringString("0%") + spec.MinAvailable = initialize.Pointer(intstr.FromString("0%")) err := r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, spec) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update @@ -2042,13 +2031,13 @@ func TestReconcileInstanceSetPodDisruptionBudget(t *testing.T) { }) t.Run("delete with 00%", func(t *testing.T) { - spec.MinAvailable = initialize.IntOrStringString("50%") + spec.MinAvailable = initialize.Pointer(intstr.FromString("50%")) assert.NilError(t, r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, spec)) assert.Assert(t, foundPDB(cluster, spec)) t.Run("deleted", func(t *testing.T) { - spec.MinAvailable = initialize.IntOrStringString("00%") + spec.MinAvailable = initialize.Pointer(intstr.FromString("00%")) err := r.reconcileInstanceSetPodDisruptionBudget(ctx, cluster, spec) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update @@ -2121,13 +2110,13 @@ func TestCleanupDisruptionBudgets(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name spec := &cluster.Spec.InstanceSets[0] - spec.MinAvailable = initialize.IntOrStringInt32(1) + spec.MinAvailable = initialize.Pointer(intstr.FromInt32(1)) assert.NilError(t, r.Client.Create(ctx, cluster)) t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) expectedPDB := generatePDB(t, cluster, spec, - initialize.IntOrStringInt32(1)) + initialize.Pointer(intstr.FromInt32(1))) assert.NilError(t, createPDB(expectedPDB)) t.Run("no instances were removed", func(t *testing.T) { @@ -2140,7 +2129,7 @@ func TestCleanupDisruptionBudgets(t *testing.T) { leftoverPDB := generatePDB(t, cluster, &v1beta1.PostgresInstanceSetSpec{ Name: "old-instance", Replicas: initialize.Int32(1), - }, initialize.IntOrStringInt32(1)) + }, initialize.Pointer(intstr.FromInt32(1))) assert.NilError(t, createPDB(leftoverPDB)) assert.Assert(t, foundPDB(expectedPDB)) diff --git a/internal/controller/postgrescluster/patroni.go b/internal/controller/postgrescluster/patroni.go index 62cd1f5b61..1c5ac93eed 100644 --- a/internal/controller/postgrescluster/patroni.go +++ b/internal/controller/postgrescluster/patroni.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -285,6 +274,8 @@ func (r *Reconciler) generatePatroniLeaderLeaseService( } servicePort.NodePort = *spec.NodePort } + service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) + service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/internal/controller/postgrescluster/patroni_test.go b/internal/controller/postgrescluster/patroni_test.go index be30469f21..b2a457685b 100644 --- a/internal/controller/postgrescluster/patroni_test.go +++ b/internal/controller/postgrescluster/patroni_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/pgadmin.go b/internal/controller/postgrescluster/pgadmin.go index 1145bedc21..c0a936ba1f 100644 --- a/internal/controller/postgrescluster/pgadmin.go +++ b/internal/controller/postgrescluster/pgadmin.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -169,7 +158,7 @@ func (r *Reconciler) generatePGAdminService( // requires updates to the pgAdmin service configuration. servicePort := corev1.ServicePort{ Name: naming.PortPGAdmin, - Port: *initialize.Int32(5050), + Port: 5050, Protocol: corev1.ProtocolTCP, TargetPort: intstr.FromString(naming.PortPGAdmin), } @@ -192,6 +181,8 @@ func (r *Reconciler) generatePGAdminService( } servicePort.NodePort = *spec.NodePort } + service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) + service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy } service.Spec.Ports = []corev1.ServicePort{servicePort} @@ -303,11 +294,8 @@ func (r *Reconciler) reconcilePGAdminStatefulSet( // Use scheduling constraints from the cluster spec. sts.Spec.Template.Spec.Affinity = cluster.Spec.UserInterface.PGAdmin.Affinity sts.Spec.Template.Spec.Tolerations = cluster.Spec.UserInterface.PGAdmin.Tolerations - - if cluster.Spec.UserInterface.PGAdmin.PriorityClassName != nil { - sts.Spec.Template.Spec.PriorityClassName = *cluster.Spec.UserInterface.PGAdmin.PriorityClassName - } - + sts.Spec.Template.Spec.PriorityClassName = + initialize.FromPointer(cluster.Spec.UserInterface.PGAdmin.PriorityClassName) sts.Spec.Template.Spec.TopologySpreadConstraints = cluster.Spec.UserInterface.PGAdmin.TopologySpreadConstraints diff --git a/internal/controller/postgrescluster/pgadmin_test.go b/internal/controller/postgrescluster/pgadmin_test.go index 361c9880f9..92ec6f42f1 100644 --- a/internal/controller/postgrescluster/pgadmin_test.go +++ b/internal/controller/postgrescluster/pgadmin_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/pgbackrest.go b/internal/controller/postgrescluster/pgbackrest.go index 01a06ae791..836df047fc 100644 --- a/internal/controller/postgrescluster/pgbackrest.go +++ b/internal/controller/postgrescluster/pgbackrest.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -43,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/crunchydata/postgres-operator/internal/config" + "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/logging" "github.com/crunchydata/postgres-operator/internal/naming" @@ -208,7 +198,7 @@ func (r *Reconciler) applyRepoVolumeIntent(ctx context.Context, // getPGBackRestResources returns the existing pgBackRest resources that should utilized by the // PostgresCluster controller during reconciliation. Any items returned are verified to be owned // by the PostgresCluster controller and still applicable per the current PostgresCluster spec. -// Additionally, and resources identified that no longer correspond to any current configuration +// Additionally, any resources identified that no longer correspond to any current configuration // are deleted. func (r *Reconciler) getPGBackRestResources(ctx context.Context, postgresCluster *v1beta1.PostgresCluster, @@ -385,6 +375,15 @@ func (r *Reconciler) cleanupRepoResources(ctx context.Context, if !backupsSpecFound { break } + + // If the restore job has the PGBackRestBackupJobCompletion annotation, it is + // used for volume snapshots and should not be deleted (volume snapshots code + // will clean it up when appropriate). + if _, ok := owned.GetAnnotations()[naming.PGBackRestBackupJobCompletion]; ok { + ownedNoDelete = append(ownedNoDelete, owned) + delete = false + } + // When a cluster is prepared for restore, the system identifier is removed from status // and the cluster is therefore no longer bootstrapped. Only once the restore Job is // complete will the cluster then be bootstrapped again, which means by the time we @@ -550,8 +549,9 @@ func (r *Reconciler) setScheduledJobStatus(ctx context.Context, for _, job := range jobList.Items { // we only care about the scheduled backup Jobs created by the // associated CronJobs - sbs := v1beta1.PGBackRestScheduledBackupStatus{} if job.GetLabels()[naming.LabelPGBackRestCronJob] != "" { + sbs := v1beta1.PGBackRestScheduledBackupStatus{} + if len(job.OwnerReferences) > 0 { sbs.CronJobName = job.OwnerReferences[0].Name } @@ -621,16 +621,12 @@ func (r *Reconciler) generateRepoHostIntent(ctx context.Context, postgresCluster repo.Spec.Template.Spec.Affinity = repoHost.Affinity repo.Spec.Template.Spec.Tolerations = repoHost.Tolerations repo.Spec.Template.Spec.TopologySpreadConstraints = repoHost.TopologySpreadConstraints - if repoHost.PriorityClassName != nil { - repo.Spec.Template.Spec.PriorityClassName = *repoHost.PriorityClassName - } + repo.Spec.Template.Spec.PriorityClassName = initialize.FromPointer(repoHost.PriorityClassName) } // if default pod scheduling is not explicitly disabled, add the default // pod topology spread constraints - if postgresCluster.Spec.DisableDefaultPodScheduling == nil || - (postgresCluster.Spec.DisableDefaultPodScheduling != nil && - !*postgresCluster.Spec.DisableDefaultPodScheduling) { + if !initialize.FromPointer(postgresCluster.Spec.DisableDefaultPodScheduling) { repo.Spec.Template.Spec.TopologySpreadConstraints = append( repo.Spec.Template.Spec.TopologySpreadConstraints, defaultTopologySpreadConstraints( @@ -773,7 +769,7 @@ func (r *Reconciler) generateRepoVolumeIntent(postgresCluster *v1beta1.PostgresC } // generateBackupJobSpecIntent generates a JobSpec for a pgBackRest backup job -func generateBackupJobSpecIntent(postgresCluster *v1beta1.PostgresCluster, +func generateBackupJobSpecIntent(ctx context.Context, postgresCluster *v1beta1.PostgresCluster, repo v1beta1.PGBackRestRepo, serviceAccountName string, labels, annotations map[string]string, opts ...string) *batchv1.JobSpec { @@ -782,6 +778,11 @@ func generateBackupJobSpecIntent(postgresCluster *v1beta1.PostgresCluster, "--stanza=" + pgbackrest.DefaultStanzaName, "--repo=" + repoIndex, } + // If VolumeSnapshots are enabled, use archive-copy and archive-check options + if postgresCluster.Spec.Backups.Snapshots != nil && feature.Enabled(ctx, feature.VolumeSnapshots) { + cmdOpts = append(cmdOpts, "--archive-copy=y", "--archive-check=y") + } + cmdOpts = append(cmdOpts, opts...) container := corev1.Container{ @@ -832,12 +833,10 @@ func generateBackupJobSpecIntent(postgresCluster *v1beta1.PostgresCluster, // set the priority class name, tolerations, and affinity, if they exist if postgresCluster.Spec.Backups.PGBackRest.Jobs != nil { - if postgresCluster.Spec.Backups.PGBackRest.Jobs.PriorityClassName != nil { - jobSpec.Template.Spec.PriorityClassName = - *postgresCluster.Spec.Backups.PGBackRest.Jobs.PriorityClassName - } jobSpec.Template.Spec.Tolerations = postgresCluster.Spec.Backups.PGBackRest.Jobs.Tolerations jobSpec.Template.Spec.Affinity = postgresCluster.Spec.Backups.PGBackRest.Jobs.Affinity + jobSpec.Template.Spec.PriorityClassName = + initialize.FromPointer(postgresCluster.Spec.Backups.PGBackRest.Jobs.PriorityClassName) } // Set the image pull secrets, if any exist. @@ -1329,9 +1328,7 @@ func (r *Reconciler) generateRestoreJobIntent(cluster *v1beta1.PostgresCluster, job.Spec.Template.Spec.SecurityContext = postgres.PodSecurityContext(cluster) // set the priority class name, if it exists - if dataSource.PriorityClassName != nil { - job.Spec.Template.Spec.PriorityClassName = *dataSource.PriorityClassName - } + job.Spec.Template.Spec.PriorityClassName = initialize.FromPointer(dataSource.PriorityClassName) job.SetGroupVersionKind(batchv1.SchemeGroupVersion.WithKind("Job")) if err := errors.WithStack(r.setControllerReference(cluster, job)); err != nil { @@ -1645,6 +1642,9 @@ func (r *Reconciler) reconcilePostgresClusterDataSource(ctx context.Context, return errors.WithStack(err) } + // TODO(snapshots): If pgdata is being sourced by a VolumeSnapshot then don't perform a typical restore job; + // we only want to replay the WAL. + // reconcile the pgBackRest restore Job to populate the cluster's data directory if err := r.reconcileRestoreJob(ctx, cluster, sourceCluster, pgdata, pgwal, pgtablespaces, dataSource, instanceName, instanceSetName, configHash, pgbackrest.DefaultStanzaName); err != nil { @@ -2373,7 +2373,7 @@ func (r *Reconciler) reconcileManualBackup(ctx context.Context, backupJob.ObjectMeta.Labels = labels backupJob.ObjectMeta.Annotations = annotations - spec := generateBackupJobSpecIntent(postgresCluster, repo, + spec := generateBackupJobSpecIntent(ctx, postgresCluster, repo, serviceAccount.GetName(), labels, annotations, backupOpts...) backupJob.Spec = *spec @@ -2534,7 +2534,7 @@ func (r *Reconciler) reconcileReplicaCreateBackup(ctx context.Context, backupJob.ObjectMeta.Labels = labels backupJob.ObjectMeta.Annotations = annotations - spec := generateBackupJobSpecIntent(postgresCluster, replicaCreateRepo, + spec := generateBackupJobSpecIntent(ctx, postgresCluster, replicaCreateRepo, serviceAccount.GetName(), labels, annotations) backupJob.Spec = *spec @@ -2689,8 +2689,7 @@ func (r *Reconciler) reconcileStanzaCreate(ctx context.Context, } // Always attempt to create pgBackRest stanza first - configHashMismatch, err := pgbackrest.Executor(exec).StanzaCreateOrUpgrade(ctx, configHash, - false, postgresCluster) + configHashMismatch, err := pgbackrest.Executor(exec).StanzaCreateOrUpgrade(ctx, configHash, postgresCluster) if err != nil { // record and log any errors resulting from running the stanza-create command r.Recorder.Event(postgresCluster, corev1.EventTypeWarning, EventUnableToCreateStanzas, @@ -2898,8 +2897,7 @@ func (r *Reconciler) reconcilePGBackRestCronJob( labels := naming.Merge( cluster.Spec.Metadata.GetLabelsOrNil(), cluster.Spec.Backups.PGBackRest.Metadata.GetLabelsOrNil(), - naming.PGBackRestCronJobLabels(cluster.Name, repo.Name, backupType), - ) + naming.PGBackRestCronJobLabels(cluster.Name, repo.Name, backupType)) objectmeta := naming.PGBackRestCronJob(cluster, backupType, repo.Name) // Look for an existing CronJob by the associated Labels. If one exists, @@ -2963,7 +2961,7 @@ func (r *Reconciler) reconcilePGBackRestCronJob( // set backup type (i.e. "full", "diff", "incr") backupOpts := []string{"--type=" + backupType} - jobSpec := generateBackupJobSpecIntent(cluster, repo, + jobSpec := generateBackupJobSpecIntent(ctx, cluster, repo, serviceAccount.GetName(), labels, annotations, backupOpts...) // Suspend cronjobs when shutdown or read-only. Any jobs that have already diff --git a/internal/controller/postgrescluster/pgbackrest_test.go b/internal/controller/postgrescluster/pgbackrest_test.go index 163f51999b..8e34dabb5e 100644 --- a/internal/controller/postgrescluster/pgbackrest_test.go +++ b/internal/controller/postgrescluster/pgbackrest_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -2449,8 +2438,9 @@ func TestCopyConfigurationResources(t *testing.T) { } func TestGenerateBackupJobIntent(t *testing.T) { + ctx := context.Background() t.Run("empty", func(t *testing.T) { - spec := generateBackupJobSpecIntent( + spec := generateBackupJobSpecIntent(ctx, &v1beta1.PostgresCluster{}, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2523,7 +2513,7 @@ volumes: ImagePullPolicy: corev1.PullAlways, }, } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2538,7 +2528,7 @@ volumes: cluster.Spec.Backups = v1beta1.Backups{ PGBackRest: v1beta1.PGBackRestArchive{}, } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2555,7 +2545,7 @@ volumes: }, }, } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2594,7 +2584,7 @@ volumes: }, }, } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2607,7 +2597,7 @@ volumes: cluster.Spec.Backups.PGBackRest.Jobs = &v1beta1.BackupJobs{ PriorityClassName: initialize.String("some-priority-class"), } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2625,7 +2615,7 @@ volumes: cluster.Spec.Backups.PGBackRest.Jobs = &v1beta1.BackupJobs{ Tolerations: tolerations, } - job := generateBackupJobSpecIntent( + job := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, @@ -2639,14 +2629,14 @@ volumes: t.Run("Undefined", func(t *testing.T) { cluster.Spec.Backups.PGBackRest.Jobs = nil - spec := generateBackupJobSpecIntent( + spec := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, ) assert.Assert(t, spec.TTLSecondsAfterFinished == nil) cluster.Spec.Backups.PGBackRest.Jobs = &v1beta1.BackupJobs{} - spec = generateBackupJobSpecIntent( + spec = generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, ) assert.Assert(t, spec.TTLSecondsAfterFinished == nil) @@ -2657,7 +2647,7 @@ volumes: TTLSecondsAfterFinished: initialize.Int32(0), } - spec := generateBackupJobSpecIntent( + spec := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, ) if assert.Check(t, spec.TTLSecondsAfterFinished != nil) { @@ -2670,7 +2660,7 @@ volumes: TTLSecondsAfterFinished: initialize.Int32(100), } - spec := generateBackupJobSpecIntent( + spec := generateBackupJobSpecIntent(ctx, cluster, v1beta1.PGBackRestRepo{}, "", nil, nil, ) if assert.Check(t, spec.TTLSecondsAfterFinished != nil) { diff --git a/internal/controller/postgrescluster/pgbouncer.go b/internal/controller/postgrescluster/pgbouncer.go index 3843b4e610..76207fac02 100644 --- a/internal/controller/postgrescluster/pgbouncer.go +++ b/internal/controller/postgrescluster/pgbouncer.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -315,12 +304,8 @@ func (r *Reconciler) generatePGBouncerService( } servicePort.NodePort = *spec.NodePort } - if spec.ExternalTrafficPolicy != nil { - service.Spec.ExternalTrafficPolicy = *spec.ExternalTrafficPolicy - } - if spec.InternalTrafficPolicy != nil { - service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy - } + service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) + service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy } service.Spec.Ports = []corev1.ServicePort{servicePort} @@ -410,25 +395,20 @@ func (r *Reconciler) generatePGBouncerDeployment( // - https://docs.k8s.io/concepts/workloads/controllers/deployment/#rolling-update-deployment deploy.Spec.Strategy.Type = appsv1.RollingUpdateDeploymentStrategyType deploy.Spec.Strategy.RollingUpdate = &appsv1.RollingUpdateDeployment{ - MaxUnavailable: intstr.ValueOrDefault(nil, intstr.FromInt(0)), + MaxUnavailable: initialize.Pointer(intstr.FromInt32(0)), } // Use scheduling constraints from the cluster spec. deploy.Spec.Template.Spec.Affinity = cluster.Spec.Proxy.PGBouncer.Affinity deploy.Spec.Template.Spec.Tolerations = cluster.Spec.Proxy.PGBouncer.Tolerations - - if cluster.Spec.Proxy.PGBouncer.PriorityClassName != nil { - deploy.Spec.Template.Spec.PriorityClassName = *cluster.Spec.Proxy.PGBouncer.PriorityClassName - } - + deploy.Spec.Template.Spec.PriorityClassName = + initialize.FromPointer(cluster.Spec.Proxy.PGBouncer.PriorityClassName) deploy.Spec.Template.Spec.TopologySpreadConstraints = cluster.Spec.Proxy.PGBouncer.TopologySpreadConstraints // if default pod scheduling is not explicitly disabled, add the default // pod topology spread constraints - if cluster.Spec.DisableDefaultPodScheduling == nil || - (cluster.Spec.DisableDefaultPodScheduling != nil && - !*cluster.Spec.DisableDefaultPodScheduling) { + if !initialize.FromPointer(cluster.Spec.DisableDefaultPodScheduling) { deploy.Spec.Template.Spec.TopologySpreadConstraints = append( deploy.Spec.Template.Spec.TopologySpreadConstraints, defaultTopologySpreadConstraints(*deploy.Spec.Selector)...) diff --git a/internal/controller/postgrescluster/pgbouncer_test.go b/internal/controller/postgrescluster/pgbouncer_test.go index 0b869943de..9bbced5247 100644 --- a/internal/controller/postgrescluster/pgbouncer_test.go +++ b/internal/controller/postgrescluster/pgbouncer_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -26,6 +15,7 @@ import ( policyv1 "k8s.io/api/policy/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" @@ -562,7 +552,7 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name cluster.Spec.Proxy.PGBouncer.Replicas = initialize.Int32(1) - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringInt32(0) + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromInt32(0)) assert.NilError(t, r.reconcilePGBouncerPodDisruptionBudget(ctx, cluster)) assert.Assert(t, !foundPDB(cluster)) }) @@ -571,7 +561,7 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name cluster.Spec.Proxy.PGBouncer.Replicas = initialize.Int32(1) - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringInt32(1) + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromInt32(1)) assert.NilError(t, r.Client.Create(ctx, cluster)) t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) @@ -580,7 +570,7 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { assert.Assert(t, foundPDB(cluster)) t.Run("deleted", func(t *testing.T) { - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringInt32(0) + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromInt32(0)) err := r.reconcilePGBouncerPodDisruptionBudget(ctx, cluster) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update @@ -598,7 +588,7 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { cluster := testCluster() cluster.Namespace = ns.Name cluster.Spec.Proxy.PGBouncer.Replicas = initialize.Int32(1) - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringString("50%") + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromString("50%")) assert.NilError(t, r.Client.Create(ctx, cluster)) t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) @@ -607,7 +597,7 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { assert.Assert(t, foundPDB(cluster)) t.Run("deleted", func(t *testing.T) { - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringString("0%") + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromString("0%")) err := r.reconcilePGBouncerPodDisruptionBudget(ctx, cluster) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update @@ -621,13 +611,13 @@ func TestReconcilePGBouncerDisruptionBudget(t *testing.T) { }) t.Run("delete with 00%", func(t *testing.T) { - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringString("50%") + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromString("50%")) assert.NilError(t, r.reconcilePGBouncerPodDisruptionBudget(ctx, cluster)) assert.Assert(t, foundPDB(cluster)) t.Run("deleted", func(t *testing.T) { - cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.IntOrStringString("00%") + cluster.Spec.Proxy.PGBouncer.MinAvailable = initialize.Pointer(intstr.FromString("00%")) err := r.reconcilePGBouncerPodDisruptionBudget(ctx, cluster) if apierrors.IsConflict(err) { // When running in an existing environment another controller will sometimes update diff --git a/internal/controller/postgrescluster/pgmonitor.go b/internal/controller/postgrescluster/pgmonitor.go index 5dc9303347..e1b5186cb4 100644 --- a/internal/controller/postgrescluster/pgmonitor.go +++ b/internal/controller/postgrescluster/pgmonitor.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -270,13 +259,34 @@ func addPGMonitorExporterToInstancePodSpec( withBuiltInCollectors := !strings.EqualFold(cluster.Annotations[naming.PostgresExporterCollectorsAnnotation], "None") + var cmd []string + // PG 17 does not include some of the columns found in stat_bgwriter with older PGs. + // Selectively turn off the collector for stat_bgwriter in PG 17, unless the user + // requests all collectors to be turned off. + switch { + case cluster.Spec.PostgresVersion == 17 && withBuiltInCollectors && certSecret == nil: + cmd = pgmonitor.ExporterStartCommand(withBuiltInCollectors, + pgmonitor.ExporterDeactivateStatBGWriterFlag) + case cluster.Spec.PostgresVersion == 17 && withBuiltInCollectors && certSecret != nil: + cmd = pgmonitor.ExporterStartCommand(withBuiltInCollectors, + pgmonitor.ExporterWebConfigFileFlag, + pgmonitor.ExporterDeactivateStatBGWriterFlag) + // If you're turning off all built-in collectors, we don't care which + // version of PG you're using. + case certSecret != nil: + cmd = pgmonitor.ExporterStartCommand(withBuiltInCollectors, + pgmonitor.ExporterWebConfigFileFlag) + default: + cmd = pgmonitor.ExporterStartCommand(withBuiltInCollectors) + } + securityContext := initialize.RestrictedSecurityContext() exporterContainer := corev1.Container{ Name: naming.ContainerPGMonitorExporter, Image: config.PGExporterContainerImage(cluster), ImagePullPolicy: cluster.Spec.ImagePullPolicy, Resources: cluster.Spec.Monitoring.PGMonitor.Exporter.Resources, - Command: pgmonitor.ExporterStartCommand(withBuiltInCollectors), + Command: cmd, Env: []corev1.EnvVar{ {Name: "DATA_SOURCE_URI", Value: fmt.Sprintf("%s:%d/%s", pgmonitor.ExporterHost, *cluster.Spec.Port, pgmonitor.ExporterDB)}, {Name: "DATA_SOURCE_USER", Value: pgmonitor.MonitoringUser}, @@ -368,8 +378,6 @@ func addPGMonitorExporterToInstancePodSpec( }} exporterContainer.VolumeMounts = append(exporterContainer.VolumeMounts, mounts...) - exporterContainer.Command = pgmonitor.ExporterStartCommand( - withBuiltInCollectors, pgmonitor.ExporterWebConfigFileFlag) } template.Spec.Containers = append(template.Spec.Containers, exporterContainer) diff --git a/internal/controller/postgrescluster/pgmonitor_test.go b/internal/controller/postgrescluster/pgmonitor_test.go index 4f01f10016..8d8c8281d0 100644 --- a/internal/controller/postgrescluster/pgmonitor_test.go +++ b/internal/controller/postgrescluster/pgmonitor_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -613,7 +602,7 @@ func TestReconcilePGMonitorExporterStatus(t *testing.T) { podExecCalled: false, // Status was generated manually for this test case // TODO (jmckulk): add code to generate status - status: v1beta1.MonitoringStatus{ExporterConfiguration: "7cdb484b6c"}, + status: v1beta1.MonitoringStatus{ExporterConfiguration: "6d874c58df"}, statusChangedAfterReconcile: false, }} { t.Run(test.name, func(t *testing.T) { diff --git a/internal/controller/postgrescluster/pki.go b/internal/controller/postgrescluster/pki.go index fd769cce7d..0314ad4406 100644 --- a/internal/controller/postgrescluster/pki.go +++ b/internal/controller/postgrescluster/pki.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/pki_test.go b/internal/controller/postgrescluster/pki_test.go index fe6bc12320..c2fe7af82a 100644 --- a/internal/controller/postgrescluster/pki_test.go +++ b/internal/controller/postgrescluster/pki_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/pod_disruption_budget.go b/internal/controller/postgrescluster/pod_disruption_budget.go index 56ac388fa2..4bff4a9743 100644 --- a/internal/controller/postgrescluster/pod_disruption_budget.go +++ b/internal/controller/postgrescluster/pod_disruption_budget.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -75,5 +64,5 @@ func getMinAvailable( } // If more than one replica is not defined, we will default to '0' - return initialize.IntOrStringInt32(expect) + return initialize.Pointer(intstr.FromInt32(expect)) } diff --git a/internal/controller/postgrescluster/pod_disruption_budget_test.go b/internal/controller/postgrescluster/pod_disruption_budget_test.go index 434d11f4ed..55e2bb63c6 100644 --- a/internal/controller/postgrescluster/pod_disruption_budget_test.go +++ b/internal/controller/postgrescluster/pod_disruption_budget_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -61,7 +50,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { "anno-key": "anno-value", }, } - minAvailable = initialize.IntOrStringInt32(1) + minAvailable = initialize.Pointer(intstr.FromInt32(1)) selector := metav1.LabelSelector{ MatchLabels: map[string]string{ "key": "value", @@ -89,19 +78,19 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { func TestGetMinAvailable(t *testing.T) { t.Run("minAvailable provided", func(t *testing.T) { // minAvailable is defined so use that value - ma := initialize.IntOrStringInt32(0) + ma := initialize.Pointer(intstr.FromInt32(0)) expect := getMinAvailable(ma, 1) assert.Equal(t, *expect, intstr.FromInt(0)) - ma = initialize.IntOrStringInt32(1) + ma = initialize.Pointer(intstr.FromInt32(1)) expect = getMinAvailable(ma, 2) assert.Equal(t, *expect, intstr.FromInt(1)) - ma = initialize.IntOrStringString("50%") + ma = initialize.Pointer(intstr.FromString("50%")) expect = getMinAvailable(ma, 3) assert.Equal(t, *expect, intstr.FromString("50%")) - ma = initialize.IntOrStringString("200%") + ma = initialize.Pointer(intstr.FromString("200%")) expect = getMinAvailable(ma, 2147483647) assert.Equal(t, *expect, intstr.FromString("200%")) }) diff --git a/internal/controller/postgrescluster/postgres.go b/internal/controller/postgrescluster/postgres.go index 0f2cbc0019..312079d824 100644 --- a/internal/controller/postgrescluster/postgres.go +++ b/internal/controller/postgrescluster/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -56,7 +45,7 @@ func (r *Reconciler) generatePostgresUserSecret( username := string(spec.Name) intent := &corev1.Secret{ObjectMeta: naming.PostgresUserSecret(cluster, username)} intent.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Secret")) - initialize.ByteMap(&intent.Data) + initialize.Map(&intent.Data) // Populate the Secret with libpq keywords for connecting through // the primary Service. diff --git a/internal/controller/postgrescluster/postgres_test.go b/internal/controller/postgrescluster/postgres_test.go index efa9d5a563..0780b0f577 100644 --- a/internal/controller/postgrescluster/postgres_test.go +++ b/internal/controller/postgrescluster/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/rbac.go b/internal/controller/postgrescluster/rbac.go index 80c7ccf678..38dd808c44 100644 --- a/internal/controller/postgrescluster/rbac.go +++ b/internal/controller/postgrescluster/rbac.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/snapshots.go b/internal/controller/postgrescluster/snapshots.go index 2bdb5baa96..76ad195600 100644 --- a/internal/controller/postgrescluster/snapshots.go +++ b/internal/controller/postgrescluster/snapshots.go @@ -1,22 +1,13 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster import ( "context" + "fmt" + "strings" "time" "github.com/pkg/errors" @@ -27,115 +18,137 @@ import ( volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" + "github.com/crunchydata/postgres-operator/internal/config" "github.com/crunchydata/postgres-operator/internal/feature" + "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/naming" + "github.com/crunchydata/postgres-operator/internal/pgbackrest" + "github.com/crunchydata/postgres-operator/internal/postgres" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) -// +kubebuilder:rbac:groups="snapshot.storage.k8s.io",resources="volumesnapshots",verbs={get,list,create,patch,delete} +//+kubebuilder:rbac:groups="snapshot.storage.k8s.io",resources="volumesnapshots",verbs={get,list,create,patch,delete} + +// The controller-runtime client sets up a cache that watches anything we "get" or "list". +//+kubebuilder:rbac:groups="snapshot.storage.k8s.io",resources="volumesnapshots",verbs={watch} // reconcileVolumeSnapshots creates and manages VolumeSnapshots if the proper VolumeSnapshot CRDs // are installed and VolumeSnapshots are enabled for the PostgresCluster. A VolumeSnapshot of the -// primary instance's pgdata volume will be created whenever a backup is completed. +// primary instance's pgdata volume will be created whenever a backup is completed. The steps to +// create snapshots include the following sequence: +// 1. We find the latest completed backup job and check the timestamp. +// 2. If the timestamp is later than what's on the dedicated snapshot PVC, a restore job runs in +// the dedicated snapshot volume. +// 3. When the restore job completes, an annotation is updated on the PVC. If the restore job +// fails, we don't run it again. +// 4. When the PVC annotation is updated, we see if there's a volume snapshot with an earlier +// timestamp. +// 5. If there are no snapshots at all, we take a snapshot and put the backup job's completion +// timestamp on the snapshot annotation. +// 6. If an earlier snapshot is found, we take a new snapshot, annotate it and delete the old +// snapshot. +// 7. When the snapshot job completes, we delete the restore job. func (r *Reconciler) reconcileVolumeSnapshots(ctx context.Context, - postgrescluster *v1beta1.PostgresCluster, instances *observedInstances, - clusterVolumes []corev1.PersistentVolumeClaim) error { + postgrescluster *v1beta1.PostgresCluster, pvc *corev1.PersistentVolumeClaim) error { - // Get feature gate state - volumeSnapshotsFeatureEnabled := feature.Enabled(ctx, feature.VolumeSnapshots) + // If VolumeSnapshots feature gate is disabled. Do nothing and return early. + if !feature.Enabled(ctx, feature.VolumeSnapshots) { + return nil + } // Check if the Kube cluster has VolumeSnapshots installed. If VolumeSnapshots - // are not installed we need to return early. If user is attempting to use + // are not installed, we need to return early. If user is attempting to use // VolumeSnapshots, return an error, otherwise return nil. - volumeSnapshotsExist, err := r.GroupVersionKindExists("snapshot.storage.k8s.io/v1", "VolumeSnapshot") + volumeSnapshotKindExists, err := r.GroupVersionKindExists("snapshot.storage.k8s.io/v1", "VolumeSnapshot") if err != nil { return err } - if !*volumeSnapshotsExist { - if postgrescluster.Spec.Backups.Snapshots != nil && volumeSnapshotsFeatureEnabled { + if !*volumeSnapshotKindExists { + if postgrescluster.Spec.Backups.Snapshots != nil { return errors.New("VolumeSnapshots are not installed/enabled in this Kubernetes cluster; cannot create snapshot.") } else { return nil } } - // Get all snapshots for this cluster + // If user is attempting to use snapshots and has tablespaces enabled, we + // need to create a warning event indicating that the two features are not + // currently compatible and return early. + if postgrescluster.Spec.Backups.Snapshots != nil && + clusterUsingTablespaces(ctx, postgrescluster) { + r.Recorder.Event(postgrescluster, corev1.EventTypeWarning, "IncompatibleFeatures", + "VolumeSnapshots not currently compatible with TablespaceVolumes; cannot create snapshot.") + return nil + } + + // Get all snapshots for the cluster. snapshots, err := r.getSnapshotsForCluster(ctx, postgrescluster) if err != nil { return err } // If snapshots are disabled, delete any existing snapshots and return early. - if postgrescluster.Spec.Backups.Snapshots == nil || !volumeSnapshotsFeatureEnabled { - for i := range snapshots.Items { - if err == nil { - err = errors.WithStack(client.IgnoreNotFound( - r.deleteControlled(ctx, postgrescluster, &snapshots.Items[i]))) - } - } - - return err + if postgrescluster.Spec.Backups.Snapshots == nil { + return r.deleteSnapshots(ctx, postgrescluster, snapshots) } - // Check snapshots for errors; if present, create an event. If there - // are multiple snapshots with errors, create event for the latest error. - latestSnapshotWithError := getLatestSnapshotWithError(snapshots) - if latestSnapshotWithError != nil { + // If we got here, then the snapshots are enabled (feature gate is enabled and the + // cluster has a Spec.Backups.Snapshots section defined). + + // Check snapshots for errors; if present, create an event. If there are + // multiple snapshots with errors, create event for the latest error and + // delete any older snapshots with error. + snapshotWithLatestError := getSnapshotWithLatestError(snapshots) + if snapshotWithLatestError != nil { r.Recorder.Event(postgrescluster, corev1.EventTypeWarning, "VolumeSnapshotError", - *latestSnapshotWithError.Status.Error.Message) + *snapshotWithLatestError.Status.Error.Message) + for _, snapshot := range snapshots.Items { + if snapshot.Status != nil && snapshot.Status.Error != nil && + snapshot.Status.Error.Time.Before(snapshotWithLatestError.Status.Error.Time) { + err = r.deleteControlled(ctx, postgrescluster, &snapshot) + if err != nil { + return err + } + } + } } - // Get all backup jobs for this cluster - jobs := &batchv1.JobList{} - selectJobs, err := naming.AsSelector(naming.ClusterBackupJobs(postgrescluster.Name)) - if err == nil { - err = errors.WithStack( - r.Client.List(ctx, jobs, - client.InNamespace(postgrescluster.Namespace), - client.MatchingLabelsSelector{Selector: selectJobs}, - )) - } - if err != nil { + // Get pvc backup job completion annotation. If it does not exist, there has not been + // a successful restore yet, so return early. + pvcUpdateTimeStamp, pvcAnnotationExists := pvc.GetAnnotations()[naming.PGBackRestBackupJobCompletion] + if !pvcAnnotationExists { return err } - // Find most recently completed backup job - backupJob := getLatestCompleteBackupJob(jobs) - - // Return early if no completed backup job found - if backupJob == nil { - return nil - } - - // Find snapshot associated with latest backup - snapshotFound := false - snapshotIdx := 0 + // Check to see if snapshot exists for the latest backup that has been restored into + // the dedicated pvc. + var snapshotForPvcUpdateIdx int + snapshotFoundForPvcUpdate := false for idx, snapshot := range snapshots.Items { - if snapshot.GetAnnotations()[naming.PGBackRestBackupJobId] == string(backupJob.UID) { - snapshotFound = true - snapshotIdx = idx + if snapshot.GetAnnotations()[naming.PGBackRestBackupJobCompletion] == pvcUpdateTimeStamp { + snapshotForPvcUpdateIdx = idx + snapshotFoundForPvcUpdate = true } } - // If snapshot exists for latest backup and it is Ready, delete all other snapshots. - // If it exists, but is not ready, do nothing. If it does not exist, create a snapshot. - if snapshotFound { - if *snapshots.Items[snapshotIdx].Status.ReadyToUse { - // Snapshot found and ready. We only keep one snapshot, so delete any other snapshots. - for idx := range snapshots.Items { - if idx != snapshotIdx { - err = r.deleteControlled(ctx, postgrescluster, &snapshots.Items[idx]) - if err != nil { - return err - } + // If a snapshot exists for the latest backup that has been restored into the dedicated pvc + // and the snapshot is Ready, delete all other snapshots. + if snapshotFoundForPvcUpdate && snapshots.Items[snapshotForPvcUpdateIdx].Status.ReadyToUse != nil && + *snapshots.Items[snapshotForPvcUpdateIdx].Status.ReadyToUse { + for idx, snapshot := range snapshots.Items { + if idx != snapshotForPvcUpdateIdx { + err = r.deleteControlled(ctx, postgrescluster, &snapshot) + if err != nil { + return err } } } - } else { - // Snapshot not found. Create snapshot. + } + + // If a snapshot for the latest backup/restore does not exist, create a snapshot. + if !snapshotFoundForPvcUpdate { var snapshot *volumesnapshotv1.VolumeSnapshot - snapshot, err = r.generateVolumeSnapshotOfPrimaryPgdata(postgrescluster, - instances, clusterVolumes, backupJob) + snapshot, err = r.generateSnapshotOfDedicatedSnapshotVolume(postgrescluster, pvc) if err == nil { err = errors.WithStack(r.apply(ctx, snapshot)) } @@ -144,49 +157,268 @@ func (r *Reconciler) reconcileVolumeSnapshots(ctx context.Context, return err } -// generateVolumeSnapshotOfPrimaryPgdata will generate a VolumeSnapshot of a -// PostgresCluster's primary instance's pgdata PersistentVolumeClaim and -// annotate it with the provided backup job's UID. -func (r *Reconciler) generateVolumeSnapshotOfPrimaryPgdata( - postgrescluster *v1beta1.PostgresCluster, instances *observedInstances, - clusterVolumes []corev1.PersistentVolumeClaim, backupJob *batchv1.Job, -) (*volumesnapshotv1.VolumeSnapshot, error) { +// +kubebuilder:rbac:groups="",resources="persistentvolumeclaims",verbs={get} +// +kubebuilder:rbac:groups="",resources="persistentvolumeclaims",verbs={create,delete,patch} + +// reconcileDedicatedSnapshotVolume reconciles the PersistentVolumeClaim that holds a +// copy of the pgdata and is dedicated for clean snapshots of the database. It creates +// and manages the volume as well as the restore jobs that bring the volume data forward +// after a successful backup. +func (r *Reconciler) reconcileDedicatedSnapshotVolume( + ctx context.Context, cluster *v1beta1.PostgresCluster, + clusterVolumes []corev1.PersistentVolumeClaim, +) (*corev1.PersistentVolumeClaim, error) { + + // If VolumeSnapshots feature gate is disabled, do nothing and return early. + if !feature.Enabled(ctx, feature.VolumeSnapshots) { + return nil, nil + } - // Find primary instance - primaryInstance := &Instance{} - for _, instance := range instances.forCluster { - if isPrimary, known := instance.IsPrimary(); isPrimary && known { - primaryInstance = instance + // Set appropriate labels for dedicated snapshot volume + labelMap := map[string]string{ + naming.LabelCluster: cluster.Name, + naming.LabelRole: naming.RoleSnapshot, + naming.LabelData: naming.DataPostgres, + } + + // If volume already exists, use existing name. Otherwise, generate a name. + var pvc *corev1.PersistentVolumeClaim + existingPVCName, err := getPGPVCName(labelMap, clusterVolumes) + if err != nil { + return nil, errors.WithStack(err) + } + if existingPVCName != "" { + pvc = &corev1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{ + Namespace: cluster.GetNamespace(), + Name: existingPVCName, + }} + } else { + pvc = &corev1.PersistentVolumeClaim{ObjectMeta: naming.ClusterDedicatedSnapshotVolume(cluster)} + } + pvc.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim")) + + // If snapshots are disabled, delete the PVC if it exists and return early. + // Check the client cache first using Get. + if cluster.Spec.Backups.Snapshots == nil { + key := client.ObjectKeyFromObject(pvc) + err := errors.WithStack(r.Client.Get(ctx, key, pvc)) + if err == nil { + err = errors.WithStack(r.deleteControlled(ctx, cluster, pvc)) } + return nil, client.IgnoreNotFound(err) } - // Return error if primary instance not found - if primaryInstance.Name == "" { - return nil, errors.New("Could not find primary instance. Cannot create volume snapshot.") + + // If we've got this far, snapshots are enabled so we should create/update/get + // the dedicated snapshot volume + pvc, err = r.createDedicatedSnapshotVolume(ctx, cluster, labelMap, pvc) + if err != nil { + return pvc, err } - // Find pvc associated with primary instance - primaryPvc := corev1.PersistentVolumeClaim{} - for _, pvc := range clusterVolumes { - pvcInstance := pvc.GetLabels()[naming.LabelInstance] - pvcRole := pvc.GetLabels()[naming.LabelRole] - if pvcRole == naming.RolePostgresData && pvcInstance == primaryInstance.Name { - primaryPvc = pvc + // Determine if we need to run a restore job, based on the most recent backup + // and an annotation on the PVC. + + // Find the most recently completed backup job. + backupJob, err := r.getLatestCompleteBackupJob(ctx, cluster) + if err != nil { + return pvc, err + } + + // Return early if no complete backup job is found. + if backupJob == nil { + return pvc, nil + } + + // Return early if the pvc is annotated with a timestamp newer or equal to the latest backup job. + // If the annotation value cannot be parsed, we want to proceed with a restore. + pvcAnnotationTimestampString := pvc.GetAnnotations()[naming.PGBackRestBackupJobCompletion] + if pvcAnnotationTime, err := time.Parse(time.RFC3339, pvcAnnotationTimestampString); err == nil { + if backupJob.Status.CompletionTime.Compare(pvcAnnotationTime) <= 0 { + return pvc, nil } } - // Return error if primary pvc not found - if primaryPvc.Name == "" { - return nil, errors.New("Could not find primary's pgdata pvc. Cannot create volume snapshot.") + + // If we've made it here, the pvc has not been restored with latest backup. + // Find the dedicated snapshot volume restore job if it exists. Since we delete + // successful restores after we annotate the PVC and stop making restore jobs + // if a failed DSV restore job exists, there should only ever be one DSV restore + // job in existence at a time. + // TODO(snapshots): Should this function throw an error or something if multiple + // DSV restores somehow exist? + restoreJob, err := r.getDedicatedSnapshotVolumeRestoreJob(ctx, cluster) + if err != nil { + return pvc, err } - // generate VolumeSnapshot - snapshot, err := r.generateVolumeSnapshot(postgrescluster, primaryPvc, + // If we don't find a restore job, we run one. + if restoreJob == nil { + err = r.dedicatedSnapshotVolumeRestore(ctx, cluster, pvc, backupJob) + return pvc, err + } + + // If we've made it here, we have found a restore job. If the restore job was + // successful, set/update the annotation on the PVC and delete the restore job. + if restoreJob.Status.Succeeded == 1 { + if pvc.GetAnnotations() == nil { + pvc.Annotations = map[string]string{} + } + pvc.Annotations[naming.PGBackRestBackupJobCompletion] = restoreJob.GetAnnotations()[naming.PGBackRestBackupJobCompletion] + annotations := fmt.Sprintf(`{"metadata":{"annotations":{"%s": "%s"}}}`, + naming.PGBackRestBackupJobCompletion, pvc.Annotations[naming.PGBackRestBackupJobCompletion]) + + patch := client.RawPatch(client.Merge.Type(), []byte(annotations)) + err = r.handlePersistentVolumeClaimError(cluster, + errors.WithStack(r.patch(ctx, pvc, patch))) + + if err != nil { + return pvc, err + } + + err = r.Client.Delete(ctx, restoreJob, client.PropagationPolicy(metav1.DeletePropagationBackground)) + return pvc, errors.WithStack(err) + } + + // If the restore job failed, create a warning event. + if restoreJob.Status.Failed == 1 { + r.Recorder.Event(cluster, corev1.EventTypeWarning, + "DedicatedSnapshotVolumeRestoreJobError", "restore job failed, check the logs") + return pvc, nil + } + + // If we made it here, the restore job is still running and we should do nothing. + return pvc, err +} + +// createDedicatedSnapshotVolume creates/updates/gets the dedicated snapshot volume. +// It expects that the volume name and GVK has already been set on the pvc that is passed in. +func (r *Reconciler) createDedicatedSnapshotVolume(ctx context.Context, + cluster *v1beta1.PostgresCluster, labelMap map[string]string, + pvc *corev1.PersistentVolumeClaim, +) (*corev1.PersistentVolumeClaim, error) { + var err error + + // An InstanceSet must be chosen to scale resources for the dedicated snapshot volume. + // TODO: We've chosen the first InstanceSet for the time being, but might want to consider + // making the choice configurable. + instanceSpec := cluster.Spec.InstanceSets[0] + + pvc.Annotations = naming.Merge( + cluster.Spec.Metadata.GetAnnotationsOrNil(), + instanceSpec.Metadata.GetAnnotationsOrNil()) + + pvc.Labels = naming.Merge( + cluster.Spec.Metadata.GetLabelsOrNil(), + instanceSpec.Metadata.GetLabelsOrNil(), + labelMap, + ) + + err = errors.WithStack(r.setControllerReference(cluster, pvc)) + if err != nil { + return pvc, err + } + + pvc.Spec = instanceSpec.DataVolumeClaimSpec + + // Set the snapshot volume to the same size as the pgdata volume. The size should scale with auto-grow. + r.setVolumeSize(ctx, cluster, pvc, instanceSpec.Name) + + // Clear any set limit before applying PVC. This is needed to allow the limit + // value to change later. + pvc.Spec.Resources.Limits = nil + + err = r.handlePersistentVolumeClaimError(cluster, + errors.WithStack(r.apply(ctx, pvc))) + if err != nil { + return pvc, err + } + + return pvc, err +} + +// dedicatedSnapshotVolumeRestore creates a Job that performs a restore into the dedicated +// snapshot volume. +// This function is very similar to reconcileRestoreJob, but specifically tailored to the +// dedicated snapshot volume. +func (r *Reconciler) dedicatedSnapshotVolumeRestore(ctx context.Context, + cluster *v1beta1.PostgresCluster, dedicatedSnapshotVolume *corev1.PersistentVolumeClaim, + backupJob *batchv1.Job, +) error { + + pgdata := postgres.DataDirectory(cluster) + repoName := backupJob.GetLabels()[naming.LabelPGBackRestRepo] + + opts := []string{ + "--stanza=" + pgbackrest.DefaultStanzaName, + "--pg1-path=" + pgdata, + "--repo=" + regexRepoIndex.FindString(repoName), + "--delta", + } + + cmd := pgbackrest.DedicatedSnapshotVolumeRestoreCommand(pgdata, strings.Join(opts, " ")) + + // Create the volume resources required for the Postgres data directory. + dataVolumeMount := postgres.DataVolumeMount() + dataVolume := corev1.Volume{ + Name: dataVolumeMount.Name, + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: dedicatedSnapshotVolume.GetName(), + }, + }, + } + volumes := []corev1.Volume{dataVolume} + volumeMounts := []corev1.VolumeMount{dataVolumeMount} + + _, configHash, err := pgbackrest.CalculateConfigHashes(cluster) + if err != nil { + return err + } + + // A DataSource is required to avoid a nil pointer exception. + fakeDataSource := &v1beta1.PostgresClusterDataSource{RepoName: ""} + + restoreJob := &batchv1.Job{} + instanceName := cluster.Status.StartupInstance + + if err := r.generateRestoreJobIntent(cluster, configHash, instanceName, cmd, + volumeMounts, volumes, fakeDataSource, restoreJob); err != nil { + return errors.WithStack(err) + } + + // Attempt the restore exactly once. If the restore job fails, we prompt the user to investigate. + restoreJob.Spec.BackoffLimit = initialize.Int32(0) + restoreJob.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyNever + + // Add pgBackRest configs to template. + pgbackrest.AddConfigToRestorePod(cluster, cluster, &restoreJob.Spec.Template.Spec) + + // Add nss_wrapper init container and add nss_wrapper env vars to the pgbackrest restore container. + addNSSWrapper( + config.PGBackRestContainerImage(cluster), + cluster.Spec.ImagePullPolicy, + &restoreJob.Spec.Template) + + addTMPEmptyDir(&restoreJob.Spec.Template) + + restoreJob.Annotations[naming.PGBackRestBackupJobCompletion] = backupJob.Status.CompletionTime.Format(time.RFC3339) + return errors.WithStack(r.apply(ctx, restoreJob)) +} + +// generateSnapshotOfDedicatedSnapshotVolume will generate a VolumeSnapshot of +// the dedicated snapshot PersistentVolumeClaim and annotate it with the +// provided backup job's UID. +func (r *Reconciler) generateSnapshotOfDedicatedSnapshotVolume( + postgrescluster *v1beta1.PostgresCluster, + dedicatedSnapshotVolume *corev1.PersistentVolumeClaim, +) (*volumesnapshotv1.VolumeSnapshot, error) { + + snapshot, err := r.generateVolumeSnapshot(postgrescluster, *dedicatedSnapshotVolume, postgrescluster.Spec.Backups.Snapshots.VolumeSnapshotClassName) if err == nil { - // Add annotation for associated backup job's UID if snapshot.Annotations == nil { snapshot.Annotations = map[string]string{} } - snapshot.Annotations[naming.PGBackRestBackupJobId] = string(backupJob.UID) + snapshot.Annotations[naming.PGBackRestBackupJobCompletion] = dedicatedSnapshotVolume.GetAnnotations()[naming.PGBackRestBackupJobCompletion] } return snapshot, err @@ -196,8 +428,8 @@ func (r *Reconciler) generateVolumeSnapshotOfPrimaryPgdata( // PersistentVolumeClaim and VolumeSnapshotClassName and will set the provided // PostgresCluster as the owner. func (r *Reconciler) generateVolumeSnapshot(postgrescluster *v1beta1.PostgresCluster, - pvc corev1.PersistentVolumeClaim, - volumeSnapshotClassName string) (*volumesnapshotv1.VolumeSnapshot, error) { + pvc corev1.PersistentVolumeClaim, volumeSnapshotClassName string, +) (*volumesnapshotv1.VolumeSnapshot, error) { snapshot := &volumesnapshotv1.VolumeSnapshot{ TypeMeta: metav1.TypeMeta{ @@ -220,10 +452,57 @@ func (r *Reconciler) generateVolumeSnapshot(postgrescluster *v1beta1.PostgresClu return snapshot, err } -// getLatestCompleteBackupJob takes a JobList and returns a pointer to the -// most recently completed backup job. If no completed backup job exists -// then it returns nil. -func getLatestCompleteBackupJob(jobs *batchv1.JobList) *batchv1.Job { +// getDedicatedSnapshotVolumeRestoreJob finds a dedicated snapshot volume (DSV) +// restore job if one exists. Since we delete successful restore jobs and stop +// creating new restore jobs when one fails, there should only ever be one DSV +// restore job present at a time. If a DSV restore cannot be found, we return nil. +func (r *Reconciler) getDedicatedSnapshotVolumeRestoreJob(ctx context.Context, + postgrescluster *v1beta1.PostgresCluster) (*batchv1.Job, error) { + + // Get all restore jobs for this cluster + jobs := &batchv1.JobList{} + selectJobs, err := naming.AsSelector(naming.ClusterRestoreJobs(postgrescluster.Name)) + if err == nil { + err = errors.WithStack( + r.Client.List(ctx, jobs, + client.InNamespace(postgrescluster.Namespace), + client.MatchingLabelsSelector{Selector: selectJobs}, + )) + } + if err != nil { + return nil, err + } + + // Get restore job that has PGBackRestBackupJobCompletion annotation + for _, job := range jobs.Items { + _, annotationExists := job.GetAnnotations()[naming.PGBackRestBackupJobCompletion] + if annotationExists { + return &job, nil + } + } + + return nil, nil +} + +// getLatestCompleteBackupJob finds the most recently completed +// backup job for a cluster +func (r *Reconciler) getLatestCompleteBackupJob(ctx context.Context, + postgrescluster *v1beta1.PostgresCluster) (*batchv1.Job, error) { + + // Get all backup jobs for this cluster + jobs := &batchv1.JobList{} + selectJobs, err := naming.AsSelector(naming.ClusterBackupJobs(postgrescluster.Name)) + if err == nil { + err = errors.WithStack( + r.Client.List(ctx, jobs, + client.InNamespace(postgrescluster.Namespace), + client.MatchingLabelsSelector{Selector: selectJobs}, + )) + } + if err != nil { + return nil, err + } + zeroTime := metav1.NewTime(time.Time{}) latestCompleteBackupJob := batchv1.Job{ Status: batchv1.JobStatus{ @@ -239,37 +518,39 @@ func getLatestCompleteBackupJob(jobs *batchv1.JobList) *batchv1.Job { } if latestCompleteBackupJob.Status.CompletionTime.Equal(&zeroTime) { - return nil + return nil, nil } - return &latestCompleteBackupJob + return &latestCompleteBackupJob, nil } -// getLatestSnapshotWithError takes a VolumeSnapshotList and returns a pointer to the -// most recently created snapshot that has an error. If no snapshot errors exist +// getSnapshotWithLatestError takes a VolumeSnapshotList and returns a pointer to the +// snapshot that has most recently had an error. If no snapshot errors exist // then it returns nil. -func getLatestSnapshotWithError(snapshots *volumesnapshotv1.VolumeSnapshotList) *volumesnapshotv1.VolumeSnapshot { +func getSnapshotWithLatestError(snapshots *volumesnapshotv1.VolumeSnapshotList) *volumesnapshotv1.VolumeSnapshot { zeroTime := metav1.NewTime(time.Time{}) - latestSnapshotWithError := volumesnapshotv1.VolumeSnapshot{ + snapshotWithLatestError := volumesnapshotv1.VolumeSnapshot{ Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: &zeroTime, + Error: &volumesnapshotv1.VolumeSnapshotError{ + Time: &zeroTime, + }, }, } for _, snapshot := range snapshots.Items { - if snapshot.Status.Error != nil && - latestSnapshotWithError.Status.CreationTime.Before(snapshot.Status.CreationTime) { - latestSnapshotWithError = snapshot + if snapshot.Status != nil && snapshot.Status.Error != nil && + snapshotWithLatestError.Status.Error.Time.Before(snapshot.Status.Error.Time) { + snapshotWithLatestError = snapshot } } - if latestSnapshotWithError.Status.CreationTime.Equal(&zeroTime) { + if snapshotWithLatestError.Status.Error.Time.Equal(&zeroTime) { return nil } - return &latestSnapshotWithError + return &snapshotWithLatestError } -// getSnapshotsForCluster gets all the VolumeSnapshots for a given postgrescluster +// getSnapshotsForCluster gets all the VolumeSnapshots for a given postgrescluster. func (r *Reconciler) getSnapshotsForCluster(ctx context.Context, cluster *v1beta1.PostgresCluster) ( *volumesnapshotv1.VolumeSnapshotList, error) { @@ -287,7 +568,7 @@ func (r *Reconciler) getSnapshotsForCluster(ctx context.Context, cluster *v1beta return snapshots, err } -// getLatestReadySnapshot takes a VolumeSnapshotList and returns the latest ready VolumeSnapshot +// getLatestReadySnapshot takes a VolumeSnapshotList and returns the latest ready VolumeSnapshot. func getLatestReadySnapshot(snapshots *volumesnapshotv1.VolumeSnapshotList) *volumesnapshotv1.VolumeSnapshot { zeroTime := metav1.NewTime(time.Time{}) latestReadySnapshot := volumesnapshotv1.VolumeSnapshot{ @@ -296,7 +577,7 @@ func getLatestReadySnapshot(snapshots *volumesnapshotv1.VolumeSnapshotList) *vol }, } for _, snapshot := range snapshots.Items { - if *snapshot.Status.ReadyToUse && + if snapshot.Status != nil && snapshot.Status.ReadyToUse != nil && *snapshot.Status.ReadyToUse && latestReadySnapshot.Status.CreationTime.Before(snapshot.Status.CreationTime) { latestReadySnapshot = snapshot } @@ -308,3 +589,29 @@ func getLatestReadySnapshot(snapshots *volumesnapshotv1.VolumeSnapshotList) *vol return &latestReadySnapshot } + +// deleteSnapshots takes a postgrescluster and a snapshot list and deletes all snapshots +// in the list that are controlled by the provided postgrescluster. +func (r *Reconciler) deleteSnapshots(ctx context.Context, + postgrescluster *v1beta1.PostgresCluster, snapshots *volumesnapshotv1.VolumeSnapshotList) error { + + for i := range snapshots.Items { + err := errors.WithStack(client.IgnoreNotFound( + r.deleteControlled(ctx, postgrescluster, &snapshots.Items[i]))) + if err != nil { + return err + } + } + return nil +} + +// tablespaceVolumesInUse determines if the TablespaceVolumes feature is enabled and the given +// cluster has tablespace volumes in place. +func clusterUsingTablespaces(ctx context.Context, postgrescluster *v1beta1.PostgresCluster) bool { + for _, instanceSet := range postgrescluster.Spec.InstanceSets { + if len(instanceSet.TablespaceVolumes) > 0 { + return feature.Enabled(ctx, feature.TablespaceVolumes) + } + } + return false +} diff --git a/internal/controller/postgrescluster/snapshots_test.go b/internal/controller/postgrescluster/snapshots_test.go index 1ac5ecda78..4c3d987ecd 100644 --- a/internal/controller/postgrescluster/snapshots_test.go +++ b/internal/controller/postgrescluster/snapshots_test.go @@ -1,67 +1,72 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster import ( "context" "testing" + "time" "github.com/pkg/errors" "gotest.tools/v3/assert" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/discovery" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/crunchydata/postgres-operator/internal/controller/runtime" "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/initialize" "github.com/crunchydata/postgres-operator/internal/naming" + "github.com/crunchydata/postgres-operator/internal/testing/cmp" + "github.com/crunchydata/postgres-operator/internal/testing/events" "github.com/crunchydata/postgres-operator/internal/testing/require" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" ) -func TestReconcileSnapshots(t *testing.T) { +func TestReconcileVolumeSnapshots(t *testing.T) { ctx := context.Background() cfg, cc := setupKubernetes(t) require.ParallelCapacity(t, 1) discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) assert.NilError(t, err) + recorder := events.NewRecorder(t, runtime.Scheme) r := &Reconciler{ Client: cc, Owner: client.FieldOwner(t.Name()), DiscoveryClient: discoveryClient, + Recorder: recorder, } ns := setupNamespace(t, cc) + // Enable snapshots feature gate + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.VolumeSnapshots: true, + })) + ctx = feature.NewContext(ctx, gate) + t.Run("SnapshotsDisabledDeleteSnapshots", func(t *testing.T) { + // Create cluster (without snapshots spec) cluster := testCluster() cluster.Namespace = ns.Name cluster.ObjectMeta.UID = "the-uid-123" + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) - instances := newObservedInstances(cluster, nil, nil) - volumes := []corev1.PersistentVolumeClaim{} - + // Create a snapshot pvc := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Name: "instance1-abc-def", + Name: "dedicated-snapshot-volume", }, } volumeSnapshotClassName := "my-snapshotclass" @@ -70,10 +75,7 @@ func TestReconcileSnapshots(t *testing.T) { err = errors.WithStack(r.apply(ctx, snapshot)) assert.NilError(t, err) - err = r.reconcileVolumeSnapshots(ctx, cluster, instances, volumes) - assert.NilError(t, err) - - // Get all snapshots for this cluster + // Get all snapshots for this cluster and assert 1 exists selectSnapshots, err := naming.AsSelector(naming.Cluster(cluster.Name)) assert.NilError(t, err) snapshots := &volumesnapshotv1.VolumeSnapshotList{} @@ -83,31 +85,98 @@ func TestReconcileSnapshots(t *testing.T) { client.MatchingLabelsSelector{Selector: selectSnapshots}, )) assert.NilError(t, err) + assert.Equal(t, len(snapshots.Items), 1) + + // Reconcile snapshots + err = r.reconcileVolumeSnapshots(ctx, cluster, pvc) + assert.NilError(t, err) + + // Get all snapshots for this cluster and assert 0 exist + assert.NilError(t, err) + snapshots = &volumesnapshotv1.VolumeSnapshotList{} + err = errors.WithStack( + r.Client.List(ctx, snapshots, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectSnapshots}, + )) + assert.NilError(t, err) assert.Equal(t, len(snapshots.Items), 0) }) - t.Run("SnapshotsEnabledNoJobsNoSnapshots", func(t *testing.T) { + t.Run("SnapshotsEnabledTablespacesEnabled", func(t *testing.T) { + // Enable both tablespaces and snapshots feature gates gate := feature.NewGate() assert.NilError(t, gate.SetFromMap(map[string]bool{ - feature.VolumeSnapshots: true, + feature.TablespaceVolumes: true, + feature.VolumeSnapshots: true, })) ctx := feature.NewContext(ctx, gate) + // Create a cluster with snapshots and tablespaces enabled + volumeSnapshotClassName := "my-snapshotclass" cluster := testCluster() cluster.Namespace = ns.Name - cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: volumeSnapshotClassName, + } + cluster.Spec.InstanceSets[0].TablespaceVolumes = []v1beta1.TablespaceVolume{{ + Name: "volume-1", + }} + + // Create pvc for reconcile + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dedicated-snapshot-volume", + }, + } + + // Reconcile + err = r.reconcileVolumeSnapshots(ctx, cluster, pvc) + assert.NilError(t, err) + + // Assert warning event was created and has expected attributes + if assert.Check(t, len(recorder.Events) > 0) { + assert.Equal(t, recorder.Events[0].Type, "Warning") + assert.Equal(t, recorder.Events[0].Regarding.Kind, "PostgresCluster") + assert.Equal(t, recorder.Events[0].Regarding.Name, "hippo") + assert.Equal(t, recorder.Events[0].Reason, "IncompatibleFeatures") + assert.Assert(t, cmp.Contains(recorder.Events[0].Note, "VolumeSnapshots not currently compatible with TablespaceVolumes")) + } + }) + + t.Run("SnapshotsEnabledNoPvcAnnotation", func(t *testing.T) { + // Create a volume snapshot class volumeSnapshotClassName := "my-snapshotclass" + volumeSnapshotClass := &volumesnapshotv1.VolumeSnapshotClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: volumeSnapshotClassName, + }, + DeletionPolicy: "Delete", + } + assert.NilError(t, r.Client.Create(ctx, volumeSnapshotClass)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, volumeSnapshotClass)) }) + + // Create a cluster with snapshots enabled + cluster := testCluster() + cluster.Namespace = ns.Name cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ VolumeSnapshotClassName: volumeSnapshotClassName, } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) - instances := newObservedInstances(cluster, nil, nil) - volumes := []corev1.PersistentVolumeClaim{} + // Create pvc for reconcile + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dedicated-snapshot-volume", + }, + } - err := r.reconcileVolumeSnapshots(ctx, cluster, instances, volumes) + // Reconcile + err = r.reconcileVolumeSnapshots(ctx, cluster, pvc) assert.NilError(t, err) - // Get all snapshots for this cluster + // Assert no snapshots exist selectSnapshots, err := naming.AsSelector(naming.Cluster(cluster.Name)) assert.NilError(t, err) snapshots := &volumesnapshotv1.VolumeSnapshotList{} @@ -119,335 +188,813 @@ func TestReconcileSnapshots(t *testing.T) { assert.NilError(t, err) assert.Equal(t, len(snapshots.Items), 0) }) -} - -func TestGenerateVolumeSnapshotOfPrimaryPgdata(t *testing.T) { - // ctx := context.Background() - _, cc := setupKubernetes(t) - require.ParallelCapacity(t, 1) - r := &Reconciler{ - Client: cc, - Owner: client.FieldOwner(t.Name()), - } - ns := setupNamespace(t, cc) + t.Run("SnapshotsEnabledReadySnapshotsExist", func(t *testing.T) { + // Create a volume snapshot class + volumeSnapshotClassName := "my-snapshotclass" + volumeSnapshotClass := &volumesnapshotv1.VolumeSnapshotClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: volumeSnapshotClassName, + }, + DeletionPolicy: "Delete", + } + assert.NilError(t, r.Client.Create(ctx, volumeSnapshotClass)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, volumeSnapshotClass)) }) - t.Run("NoPrimary", func(t *testing.T) { + // Create a cluster with snapshots enabled cluster := testCluster() cluster.Namespace = ns.Name - instances := newObservedInstances(cluster, nil, nil) - volumes := []corev1.PersistentVolumeClaim{} - backupJob := &batchv1.Job{} + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: volumeSnapshotClassName, + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) - snapshot, err := r.generateVolumeSnapshotOfPrimaryPgdata(cluster, instances, volumes, backupJob) - assert.Error(t, err, "Could not find primary instance. Cannot create volume snapshot.") - assert.Check(t, snapshot == nil) - }) + // Create pvc with annotation + pvcName := initialize.String("dedicated-snapshot-volume") + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: *pvcName, + Annotations: map[string]string{ + naming.PGBackRestBackupJobCompletion: "backup-timestamp", + }, + }, + } - t.Run("NoVolume", func(t *testing.T) { - cluster := testCluster() - cluster.Namespace = ns.Name - instances := newObservedInstances(cluster, - []appsv1.StatefulSet{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "instance1-abc", - Labels: map[string]string{ - "postgres-operator.crunchydata.com/instance-set": "00", - }, - }, + // Create snapshot with annotation matching the pvc annotation + snapshot1 := &volumesnapshotv1.VolumeSnapshot{ + TypeMeta: metav1.TypeMeta{ + APIVersion: volumesnapshotv1.SchemeGroupVersion.String(), + Kind: "VolumeSnapshot", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "first-snapshot", + Namespace: ns.Name, + Annotations: map[string]string{ + naming.PGBackRestBackupJobCompletion: "backup-timestamp", + }, + Labels: map[string]string{ + naming.LabelCluster: "hippo", }, }, - []corev1.Pod{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "some-pod-name", - Labels: map[string]string{ - "postgres-operator.crunchydata.com/instance-set": "00", - "postgres-operator.crunchydata.com/instance": "instance1-abc", - "postgres-operator.crunchydata.com/role": "master", - }, - }, + Spec: volumesnapshotv1.VolumeSnapshotSpec{ + Source: volumesnapshotv1.VolumeSnapshotSource{ + PersistentVolumeClaimName: pvcName, }, - }) - volumes := []corev1.PersistentVolumeClaim{} - backupJob := &batchv1.Job{} - - snapshot, err := r.generateVolumeSnapshotOfPrimaryPgdata(cluster, instances, volumes, backupJob) - assert.Error(t, err, "Could not find primary's pgdata pvc. Cannot create volume snapshot.") - assert.Check(t, snapshot == nil) - }) + }, + } + err := errors.WithStack(r.setControllerReference(cluster, snapshot1)) + assert.NilError(t, err) + err = r.apply(ctx, snapshot1) + assert.NilError(t, err) - t.Run("Success", func(t *testing.T) { - cluster := testCluster() - cluster.Namespace = ns.Name - cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ - VolumeSnapshotClassName: "my-volume-snapshot-class", + // Update snapshot status + truePtr := initialize.Bool(true) + snapshot1.Status = &volumesnapshotv1.VolumeSnapshotStatus{ + ReadyToUse: truePtr, } - cluster.ObjectMeta.UID = "the-uid-123" - instances := newObservedInstances(cluster, - []appsv1.StatefulSet{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "instance1-abc", - Labels: map[string]string{ - "postgres-operator.crunchydata.com/instance-set": "00", - }, - }, + err = r.Client.Status().Update(ctx, snapshot1) + assert.NilError(t, err) + + // Create second snapshot with different annotation value + snapshot2 := &volumesnapshotv1.VolumeSnapshot{ + TypeMeta: metav1.TypeMeta{ + APIVersion: volumesnapshotv1.SchemeGroupVersion.String(), + Kind: "VolumeSnapshot", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "second-snapshot", + Namespace: ns.Name, + Annotations: map[string]string{ + naming.PGBackRestBackupJobCompletion: "older-backup-timestamp", + }, + Labels: map[string]string{ + naming.LabelCluster: "hippo", }, }, - []corev1.Pod{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "some-pod-name", - Labels: map[string]string{ - "postgres-operator.crunchydata.com/instance-set": "00", - "postgres-operator.crunchydata.com/instance": "instance1-abc", - "postgres-operator.crunchydata.com/role": "master", - }, - }, + Spec: volumesnapshotv1.VolumeSnapshotSpec{ + Source: volumesnapshotv1.VolumeSnapshotSource{ + PersistentVolumeClaimName: pvcName, }, }, - ) - volumes := []corev1.PersistentVolumeClaim{{ + } + err = errors.WithStack(r.setControllerReference(cluster, snapshot2)) + assert.NilError(t, err) + err = r.apply(ctx, snapshot2) + assert.NilError(t, err) + + // Update second snapshot's status + snapshot2.Status = &volumesnapshotv1.VolumeSnapshotStatus{ + ReadyToUse: truePtr, + } + err = r.Client.Status().Update(ctx, snapshot2) + assert.NilError(t, err) + + // Reconcile + err = r.reconcileVolumeSnapshots(ctx, cluster, pvc) + assert.NilError(t, err) + + // Assert first snapshot exists and second snapshot was deleted + selectSnapshots, err := naming.AsSelector(naming.Cluster(cluster.Name)) + assert.NilError(t, err) + snapshots := &volumesnapshotv1.VolumeSnapshotList{} + err = errors.WithStack( + r.Client.List(ctx, snapshots, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectSnapshots}, + )) + assert.NilError(t, err) + assert.Equal(t, len(snapshots.Items), 1) + assert.Equal(t, snapshots.Items[0].Name, "first-snapshot") + + // Cleanup + err = r.deleteControlled(ctx, cluster, snapshot1) + assert.NilError(t, err) + }) + + t.Run("SnapshotsEnabledCreateSnapshot", func(t *testing.T) { + // Create a volume snapshot class + volumeSnapshotClassName := "my-snapshotclass" + volumeSnapshotClass := &volumesnapshotv1.VolumeSnapshotClass{ ObjectMeta: metav1.ObjectMeta{ - Name: "instance1-abc-def", - Labels: map[string]string{ - naming.LabelRole: naming.RolePostgresData, - naming.LabelInstanceSet: "instance1", - naming.LabelInstance: "instance1-abc"}, + Name: volumeSnapshotClassName, }, - }} - backupJob := &batchv1.Job{ + DeletionPolicy: "Delete", + } + assert.NilError(t, r.Client.Create(ctx, volumeSnapshotClass)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, volumeSnapshotClass)) }) + + // Create a cluster with snapshots enabled + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: volumeSnapshotClassName, + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) + + // Create pvc with annotation + pvcName := initialize.String("dedicated-snapshot-volume") + pvc := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Name: "backup1", - UID: "the-uid-456", + Name: *pvcName, + Annotations: map[string]string{ + naming.PGBackRestBackupJobCompletion: "another-backup-timestamp", + }, }, } - snapshot, err := r.generateVolumeSnapshotOfPrimaryPgdata(cluster, instances, volumes, backupJob) + // Reconcile + err = r.reconcileVolumeSnapshots(ctx, cluster, pvc) + assert.NilError(t, err) + + // Assert that a snapshot was created + selectSnapshots, err := naming.AsSelector(naming.Cluster(cluster.Name)) + assert.NilError(t, err) + snapshots := &volumesnapshotv1.VolumeSnapshotList{} + err = errors.WithStack( + r.Client.List(ctx, snapshots, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectSnapshots}, + )) assert.NilError(t, err) - assert.Equal(t, snapshot.Annotations[naming.PGBackRestBackupJobId], "the-uid-456") + assert.Equal(t, len(snapshots.Items), 1) + assert.Equal(t, snapshots.Items[0].Annotations[naming.PGBackRestBackupJobCompletion], + "another-backup-timestamp") }) } -func TestGenerateVolumeSnapshot(t *testing.T) { - // ctx := context.Background() - _, cc := setupKubernetes(t) - require.ParallelCapacity(t, 1) +func TestReconcileDedicatedSnapshotVolume(t *testing.T) { + ctx := context.Background() + cfg, cc := setupKubernetes(t) + discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) + assert.NilError(t, err) + recorder := events.NewRecorder(t, runtime.Scheme) r := &Reconciler{ - Client: cc, - Owner: client.FieldOwner(t.Name()), - } - ns := setupNamespace(t, cc) - - cluster := testCluster() - cluster.Namespace = ns.Name - - pvc := &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: "instance1-abc-def", - }, + Client: cc, + Owner: client.FieldOwner(t.Name()), + DiscoveryClient: discoveryClient, + Recorder: recorder, } - volumeSnapshotClassName := "my-snapshot" - snapshot, err := r.generateVolumeSnapshot(cluster, *pvc, volumeSnapshotClassName) - assert.NilError(t, err) - assert.Equal(t, *snapshot.Spec.VolumeSnapshotClassName, "my-snapshot") - assert.Equal(t, *snapshot.Spec.Source.PersistentVolumeClaimName, "instance1-abc-def") - assert.Equal(t, snapshot.Labels[naming.LabelCluster], "hippo") - assert.Equal(t, snapshot.ObjectMeta.OwnerReferences[0].Name, "hippo") -} + // Enable snapshots feature gate + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.VolumeSnapshots: true, + })) + ctx = feature.NewContext(ctx, gate) -func TestGetLatestCompleteBackupJob(t *testing.T) { - t.Run("NoJobs", func(t *testing.T) { - jobList := &batchv1.JobList{} - latestCompleteBackupJob := getLatestCompleteBackupJob(jobList) - assert.Check(t, latestCompleteBackupJob == nil) - }) + t.Run("SnapshotsDisabledDeletePvc", func(t *testing.T) { + // Create cluster without snapshots spec + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) - t.Run("NoCompleteJobs", func(t *testing.T) { - jobList := &batchv1.JobList{ - Items: []batchv1.Job{ - { - Status: batchv1.JobStatus{ - Succeeded: 0, - }, - }, - { - Status: batchv1.JobStatus{ - Succeeded: 0, - }, - }, + // Create a dedicated snapshot volume + pvc := &corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: corev1.SchemeGroupVersion.String(), }, - } - latestCompleteBackupJob := getLatestCompleteBackupJob(jobList) - assert.Check(t, latestCompleteBackupJob == nil) - }) - - t.Run("OneCompleteBackupJob", func(t *testing.T) { - currentTime := metav1.Now() - jobList := &batchv1.JobList{ - Items: []batchv1.Job{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "backup1", - UID: "something-here", - }, - Status: batchv1.JobStatus{ - Succeeded: 1, - CompletionTime: ¤tTime, - }, - }, - { - Status: batchv1.JobStatus{ - Succeeded: 0, - }, + ObjectMeta: metav1.ObjectMeta{ + Name: "dedicated-snapshot-volume", + Namespace: ns.Name, + Labels: map[string]string{ + naming.LabelCluster: cluster.Name, + naming.LabelRole: naming.RoleSnapshot, + naming.LabelData: naming.DataPostgres, }, }, + Spec: testVolumeClaimSpec(), } - latestCompleteBackupJob := getLatestCompleteBackupJob(jobList) - assert.Check(t, latestCompleteBackupJob.UID == "something-here") - }) + err = errors.WithStack(r.setControllerReference(cluster, pvc)) + assert.NilError(t, err) + err = r.apply(ctx, pvc) + assert.NilError(t, err) - t.Run("TwoCompleteBackupJobs", func(t *testing.T) { - currentTime := metav1.Now() - earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) - assert.Check(t, earlierTime.Before(¤tTime)) + // Assert that the pvc was created + selectPvcs, err := naming.AsSelector(naming.Cluster(cluster.Name)) + assert.NilError(t, err) + pvcs := &corev1.PersistentVolumeClaimList{} + err = errors.WithStack( + r.Client.List(ctx, pvcs, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectPvcs}, + )) + assert.NilError(t, err) + assert.Equal(t, len(pvcs.Items), 1) - jobList := &batchv1.JobList{ - Items: []batchv1.Job{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "backup2", - UID: "newer-one", - }, - Status: batchv1.JobStatus{ - Succeeded: 1, - CompletionTime: ¤tTime, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "backup1", - UID: "older-one", - }, - Status: batchv1.JobStatus{ - Succeeded: 1, - CompletionTime: &earlierTime, - }, - }, - }, + // Create volumes for reconcile + clusterVolumes := []corev1.PersistentVolumeClaim{*pvc} + + // Reconcile + returned, err := r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + assert.NilError(t, err) + assert.Check(t, returned == nil) + + // Assert that the pvc has been deleted or marked for deletion + key, fetched := client.ObjectKeyFromObject(pvc), &corev1.PersistentVolumeClaim{} + if err := r.Client.Get(ctx, key, fetched); err == nil { + assert.Assert(t, fetched.DeletionTimestamp != nil, "expected deleted") + } else { + assert.Assert(t, apierrors.IsNotFound(err), "expected NotFound, got %v", err) } - latestCompleteBackupJob := getLatestCompleteBackupJob(jobList) - assert.Check(t, latestCompleteBackupJob.UID == "newer-one") }) -} -func TestGetLatestSnapshotWithError(t *testing.T) { - t.Run("NoSnapshots", func(t *testing.T) { - snapshotList := &volumesnapshotv1.VolumeSnapshotList{} - latestSnapshotWithError := getLatestSnapshotWithError(snapshotList) - assert.Check(t, latestSnapshotWithError == nil) - }) + t.Run("SnapshotsEnabledCreatePvcNoBackupNoRestore", func(t *testing.T) { + // Create cluster with snapshots enabled + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: "my-snapshotclass", + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) - t.Run("NoSnapshotsWithErrors", func(t *testing.T) { - snapshotList := &volumesnapshotv1.VolumeSnapshotList{ - Items: []volumesnapshotv1.VolumeSnapshot{ - { - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - ReadyToUse: initialize.Bool(true), - }, - }, - { - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - ReadyToUse: initialize.Bool(false), - }, - }, - }, + // Create volumes for reconcile + clusterVolumes := []corev1.PersistentVolumeClaim{} + + // Reconcile + pvc, err := r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + assert.NilError(t, err) + assert.Assert(t, pvc != nil) + + // Assert pvc was created + selectPvcs, err := naming.AsSelector(naming.Cluster(cluster.Name)) + assert.NilError(t, err) + pvcs := &corev1.PersistentVolumeClaimList{} + err = errors.WithStack( + r.Client.List(ctx, pvcs, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectPvcs}, + )) + assert.NilError(t, err) + assert.Equal(t, len(pvcs.Items), 1) + }) + + t.Run("SnapshotsEnabledBackupExistsCreateRestore", func(t *testing.T) { + // Create cluster with snapshots enabled + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: "my-snapshotclass", + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) + + // Create successful backup job + backupJob := testBackupJob(cluster) + err = errors.WithStack(r.setControllerReference(cluster, backupJob)) + assert.NilError(t, err) + err = r.apply(ctx, backupJob) + assert.NilError(t, err) + + currentTime := metav1.Now() + backupJob.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: ¤tTime, } - latestSnapshotWithError := getLatestSnapshotWithError(snapshotList) - assert.Check(t, latestSnapshotWithError == nil) + err = r.Client.Status().Update(ctx, backupJob) + assert.NilError(t, err) + + // Create instance set and volumes for reconcile + sts := &appsv1.StatefulSet{} + generateInstanceStatefulSetIntent(ctx, cluster, &cluster.Spec.InstanceSets[0], "pod-service", "service-account", sts, 1) + clusterVolumes := []corev1.PersistentVolumeClaim{} + + // Reconcile + pvc, err := r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + assert.NilError(t, err) + assert.Assert(t, pvc != nil) + + // Assert restore job with annotation was created + restoreJobs := &batchv1.JobList{} + selectJobs, err := naming.AsSelector(naming.ClusterRestoreJobs(cluster.Name)) + assert.NilError(t, err) + err = errors.WithStack( + r.Client.List(ctx, restoreJobs, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectJobs}, + )) + assert.NilError(t, err) + assert.Equal(t, len(restoreJobs.Items), 1) + assert.Assert(t, restoreJobs.Items[0].Annotations[naming.PGBackRestBackupJobCompletion] != "") }) - t.Run("OneSnapshotWithError", func(t *testing.T) { + t.Run("SnapshotsEnabledSuccessfulRestoreExists", func(t *testing.T) { + // Create cluster with snapshots enabled + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: "my-snapshotclass", + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) + + // Create times for jobs currentTime := metav1.Now() - snapshotList := &volumesnapshotv1.VolumeSnapshotList{ - Items: []volumesnapshotv1.VolumeSnapshot{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "good-snapshot", - UID: "the-uid-123", - }, - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - ReadyToUse: initialize.Bool(true), - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "bad-snapshot", - UID: "the-uid-456", - }, - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: ¤tTime, - ReadyToUse: initialize.Bool(false), - Error: &volumesnapshotv1.VolumeSnapshotError{}, - }, - }, - }, + earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) + + // Create successful backup job + backupJob := testBackupJob(cluster) + err = errors.WithStack(r.setControllerReference(cluster, backupJob)) + assert.NilError(t, err) + err = r.apply(ctx, backupJob) + assert.NilError(t, err) + + backupJob.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: &earlierTime, + } + err = r.Client.Status().Update(ctx, backupJob) + assert.NilError(t, err) + + // Create successful restore job + restoreJob := testRestoreJob(cluster) + restoreJob.Annotations = map[string]string{ + naming.PGBackRestBackupJobCompletion: backupJob.Status.CompletionTime.Format(time.RFC3339), } - latestSnapshotWithError := getLatestSnapshotWithError(snapshotList) - assert.Equal(t, latestSnapshotWithError.ObjectMeta.Name, "bad-snapshot") + err = errors.WithStack(r.setControllerReference(cluster, restoreJob)) + assert.NilError(t, err) + err = r.apply(ctx, restoreJob) + assert.NilError(t, err) + + restoreJob.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: ¤tTime, + } + err = r.Client.Status().Update(ctx, restoreJob) + assert.NilError(t, err) + + // Create instance set and volumes for reconcile + sts := &appsv1.StatefulSet{} + generateInstanceStatefulSetIntent(ctx, cluster, &cluster.Spec.InstanceSets[0], "pod-service", "service-account", sts, 1) + clusterVolumes := []corev1.PersistentVolumeClaim{} + + // Reconcile + pvc, err := r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + assert.NilError(t, err) + assert.Assert(t, pvc != nil) + + // Assert restore job was deleted + restoreJobs := &batchv1.JobList{} + selectJobs, err := naming.AsSelector(naming.ClusterRestoreJobs(cluster.Name)) + assert.NilError(t, err) + err = errors.WithStack( + r.Client.List(ctx, restoreJobs, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectJobs}, + )) + assert.NilError(t, err) + assert.Equal(t, len(restoreJobs.Items), 0) + + // Assert pvc was annotated + assert.Equal(t, pvc.GetAnnotations()[naming.PGBackRestBackupJobCompletion], backupJob.Status.CompletionTime.Format(time.RFC3339)) }) - t.Run("TwoSnapshotsWithErrors", func(t *testing.T) { + t.Run("SnapshotsEnabledFailedRestoreExists", func(t *testing.T) { + // Create cluster with snapshots enabled + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: "my-snapshotclass", + } + assert.NilError(t, r.Client.Create(ctx, cluster)) + t.Cleanup(func() { assert.Check(t, r.Client.Delete(ctx, cluster)) }) + + // Create times for jobs currentTime := metav1.Now() earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) - snapshotList := &volumesnapshotv1.VolumeSnapshotList{ - Items: []volumesnapshotv1.VolumeSnapshot{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "first-bad-snapshot", - UID: "the-uid-123", - }, - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: &earlierTime, - ReadyToUse: initialize.Bool(false), - Error: &volumesnapshotv1.VolumeSnapshotError{}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "second-bad-snapshot", - UID: "the-uid-456", - }, - Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: ¤tTime, - ReadyToUse: initialize.Bool(false), - Error: &volumesnapshotv1.VolumeSnapshotError{}, - }, - }, + + // Create successful backup job + backupJob := testBackupJob(cluster) + err = errors.WithStack(r.setControllerReference(cluster, backupJob)) + assert.NilError(t, err) + err = r.apply(ctx, backupJob) + assert.NilError(t, err) + + backupJob.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: &earlierTime, + } + err = r.Client.Status().Update(ctx, backupJob) + assert.NilError(t, err) + + // Create failed restore job + restoreJob := testRestoreJob(cluster) + restoreJob.Annotations = map[string]string{ + naming.PGBackRestBackupJobCompletion: backupJob.Status.CompletionTime.Format(time.RFC3339), + } + err = errors.WithStack(r.setControllerReference(cluster, restoreJob)) + assert.NilError(t, err) + err = r.apply(ctx, restoreJob) + assert.NilError(t, err) + + restoreJob.Status = batchv1.JobStatus{ + Succeeded: 0, + Failed: 1, + CompletionTime: ¤tTime, + } + err = r.Client.Status().Update(ctx, restoreJob) + assert.NilError(t, err) + + // Setup instances and volumes for reconcile + sts := &appsv1.StatefulSet{} + generateInstanceStatefulSetIntent(ctx, cluster, &cluster.Spec.InstanceSets[0], "pod-service", "service-account", sts, 1) + clusterVolumes := []corev1.PersistentVolumeClaim{} + + // Reconcile + pvc, err := r.reconcileDedicatedSnapshotVolume(ctx, cluster, clusterVolumes) + assert.NilError(t, err) + assert.Assert(t, pvc != nil) + + // Assert warning event was created and has expected attributes + if assert.Check(t, len(recorder.Events) > 0) { + assert.Equal(t, recorder.Events[0].Type, "Warning") + assert.Equal(t, recorder.Events[0].Regarding.Kind, "PostgresCluster") + assert.Equal(t, recorder.Events[0].Regarding.Name, "hippo") + assert.Equal(t, recorder.Events[0].Reason, "DedicatedSnapshotVolumeRestoreJobError") + assert.Assert(t, cmp.Contains(recorder.Events[0].Note, "restore job failed, check the logs")) + } + }) +} + +func TestCreateDedicatedSnapshotVolume(t *testing.T) { + ctx := context.Background() + _, cc := setupKubernetes(t) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + + labelMap := map[string]string{ + naming.LabelCluster: cluster.Name, + naming.LabelRole: naming.RoleSnapshot, + naming.LabelData: naming.DataPostgres, + } + pvc := &corev1.PersistentVolumeClaim{ObjectMeta: naming.ClusterDedicatedSnapshotVolume(cluster)} + pvc.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim")) + + pvc, err := r.createDedicatedSnapshotVolume(ctx, cluster, labelMap, pvc) + assert.NilError(t, err) + assert.Assert(t, metav1.IsControlledBy(pvc, cluster)) + assert.Equal(t, pvc.Spec.Resources.Requests[corev1.ResourceStorage], resource.MustParse("1Gi")) +} + +func TestDedicatedSnapshotVolumeRestore(t *testing.T) { + ctx := context.Background() + _, cc := setupKubernetes(t) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + + ns := setupNamespace(t, cc) + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dedicated-snapshot-volume", + }, + } + + sts := &appsv1.StatefulSet{} + generateInstanceStatefulSetIntent(ctx, cluster, &cluster.Spec.InstanceSets[0], "pod-service", "service-account", sts, 1) + currentTime := metav1.Now() + backupJob := testBackupJob(cluster) + backupJob.Status.CompletionTime = ¤tTime + + err := r.dedicatedSnapshotVolumeRestore(ctx, cluster, pvc, backupJob) + assert.NilError(t, err) + + // Assert a restore job was created that has the correct annotation + jobs := &batchv1.JobList{} + selectJobs, err := naming.AsSelector(naming.ClusterRestoreJobs(cluster.Name)) + assert.NilError(t, err) + err = errors.WithStack( + r.Client.List(ctx, jobs, + client.InNamespace(cluster.Namespace), + client.MatchingLabelsSelector{Selector: selectJobs}, + )) + assert.NilError(t, err) + assert.Equal(t, len(jobs.Items), 1) + assert.Equal(t, jobs.Items[0].Annotations[naming.PGBackRestBackupJobCompletion], + backupJob.Status.CompletionTime.Format(time.RFC3339)) +} + +func TestGenerateSnapshotOfDedicatedSnapshotVolume(t *testing.T) { + _, cc := setupKubernetes(t) + require.ParallelCapacity(t, 1) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + ns := setupNamespace(t, cc) + + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.Spec.Backups.Snapshots = &v1beta1.VolumeSnapshots{ + VolumeSnapshotClassName: "my-snapshot", + } + + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + naming.PGBackRestBackupJobCompletion: "backup-completion-timestamp", }, + Name: "dedicated-snapshot-volume", + }, + } + + snapshot, err := r.generateSnapshotOfDedicatedSnapshotVolume(cluster, pvc) + assert.NilError(t, err) + assert.Equal(t, snapshot.GetAnnotations()[naming.PGBackRestBackupJobCompletion], + "backup-completion-timestamp") +} + +func TestGenerateVolumeSnapshot(t *testing.T) { + _, cc := setupKubernetes(t) + require.ParallelCapacity(t, 1) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + ns := setupNamespace(t, cc) + + cluster := testCluster() + cluster.Namespace = ns.Name + + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dedicated-snapshot-volume", + }, + } + volumeSnapshotClassName := "my-snapshot" + + snapshot, err := r.generateVolumeSnapshot(cluster, *pvc, volumeSnapshotClassName) + assert.NilError(t, err) + assert.Equal(t, *snapshot.Spec.VolumeSnapshotClassName, "my-snapshot") + assert.Equal(t, *snapshot.Spec.Source.PersistentVolumeClaimName, "dedicated-snapshot-volume") + assert.Equal(t, snapshot.Labels[naming.LabelCluster], "hippo") + assert.Equal(t, snapshot.ObjectMeta.OwnerReferences[0].Name, "hippo") +} + +func TestGetDedicatedSnapshotVolumeRestoreJob(t *testing.T) { + ctx := context.Background() + _, cc := setupKubernetes(t) + require.ParallelCapacity(t, 1) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + ns := setupNamespace(t, cc) + + cluster := testCluster() + cluster.Namespace = ns.Name + + t.Run("NoRestoreJobs", func(t *testing.T) { + dsvRestoreJob, err := r.getDedicatedSnapshotVolumeRestoreJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, dsvRestoreJob == nil) + }) + + t.Run("NoDsvRestoreJobs", func(t *testing.T) { + job1 := testRestoreJob(cluster) + job1.Namespace = ns.Name + + err := r.apply(ctx, job1) + assert.NilError(t, err) + + dsvRestoreJob, err := r.getDedicatedSnapshotVolumeRestoreJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, dsvRestoreJob == nil) + }) + + t.Run("DsvRestoreJobExists", func(t *testing.T) { + job2 := testRestoreJob(cluster) + job2.Name = "restore-job-2" + job2.Namespace = ns.Name + job2.Annotations = map[string]string{ + naming.PGBackRestBackupJobCompletion: "backup-timestamp", + } + + err := r.apply(ctx, job2) + assert.NilError(t, err) + + job3 := testRestoreJob(cluster) + job3.Name = "restore-job-3" + job3.Namespace = ns.Name + + err = r.apply(ctx, job3) + assert.NilError(t, err) + + dsvRestoreJob, err := r.getDedicatedSnapshotVolumeRestoreJob(ctx, cluster) + assert.NilError(t, err) + assert.Assert(t, dsvRestoreJob != nil) + assert.Equal(t, dsvRestoreJob.Name, "restore-job-2") + }) +} + +func TestGetLatestCompleteBackupJob(t *testing.T) { + ctx := context.Background() + _, cc := setupKubernetes(t) + // require.ParallelCapacity(t, 1) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + } + ns := setupNamespace(t, cc) + + cluster := testCluster() + cluster.Namespace = ns.Name + + t.Run("NoJobs", func(t *testing.T) { + latestCompleteBackupJob, err := r.getLatestCompleteBackupJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, latestCompleteBackupJob == nil) + }) + + t.Run("NoCompleteJobs", func(t *testing.T) { + job1 := testBackupJob(cluster) + job1.Namespace = ns.Name + + err := r.apply(ctx, job1) + assert.NilError(t, err) + + latestCompleteBackupJob, err := r.getLatestCompleteBackupJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, latestCompleteBackupJob == nil) + }) + + t.Run("OneCompleteBackupJob", func(t *testing.T) { + currentTime := metav1.Now() + + job1 := testBackupJob(cluster) + job1.Namespace = ns.Name + + err := r.apply(ctx, job1) + assert.NilError(t, err) + + job2 := testBackupJob(cluster) + job2.Namespace = ns.Name + job2.Name = "backup-job-2" + + err = r.apply(ctx, job2) + assert.NilError(t, err) + + // Get job1 and update Status. + err = r.Client.Get(ctx, client.ObjectKeyFromObject(job1), job1) + assert.NilError(t, err) + + job1.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: ¤tTime, + } + err = r.Client.Status().Update(ctx, job1) + assert.NilError(t, err) + + latestCompleteBackupJob, err := r.getLatestCompleteBackupJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, latestCompleteBackupJob.Name == "backup-job-1") + }) + + t.Run("TwoCompleteBackupJobs", func(t *testing.T) { + currentTime := metav1.Now() + earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) + assert.Check(t, earlierTime.Before(¤tTime)) + + job1 := testBackupJob(cluster) + job1.Namespace = ns.Name + + err := r.apply(ctx, job1) + assert.NilError(t, err) + + job2 := testBackupJob(cluster) + job2.Namespace = ns.Name + job2.Name = "backup-job-2" + + err = r.apply(ctx, job2) + assert.NilError(t, err) + + // Get job1 and update Status. + err = r.Client.Get(ctx, client.ObjectKeyFromObject(job1), job1) + assert.NilError(t, err) + + job1.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: ¤tTime, + } + err = r.Client.Status().Update(ctx, job1) + assert.NilError(t, err) + + // Get job2 and update Status. + err = r.Client.Get(ctx, client.ObjectKeyFromObject(job2), job2) + assert.NilError(t, err) + + job2.Status = batchv1.JobStatus{ + Succeeded: 1, + CompletionTime: &earlierTime, } - latestSnapshotWithError := getLatestSnapshotWithError(snapshotList) - assert.Equal(t, latestSnapshotWithError.ObjectMeta.Name, "second-bad-snapshot") + err = r.Client.Status().Update(ctx, job2) + assert.NilError(t, err) + + latestCompleteBackupJob, err := r.getLatestCompleteBackupJob(ctx, cluster) + assert.NilError(t, err) + assert.Check(t, latestCompleteBackupJob.Name == "backup-job-1") }) } -func TestGetLatestReadySnapshot(t *testing.T) { +func TestGetSnapshotWithLatestError(t *testing.T) { t.Run("NoSnapshots", func(t *testing.T) { snapshotList := &volumesnapshotv1.VolumeSnapshotList{} - latestReadySnapshot := getLatestReadySnapshot(snapshotList) - assert.Check(t, latestReadySnapshot == nil) + snapshotWithLatestError := getSnapshotWithLatestError(snapshotList) + assert.Check(t, snapshotWithLatestError == nil) }) - t.Run("NoReadySnapshots", func(t *testing.T) { + t.Run("NoSnapshotsWithStatus", func(t *testing.T) { + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + {}, + {}, + }, + } + snapshotWithLatestError := getSnapshotWithLatestError(snapshotList) + assert.Check(t, snapshotWithLatestError == nil) + }) + + t.Run("NoSnapshotsWithErrors", func(t *testing.T) { snapshotList := &volumesnapshotv1.VolumeSnapshotList{ Items: []volumesnapshotv1.VolumeSnapshot{ { Status: &volumesnapshotv1.VolumeSnapshotStatus{ - ReadyToUse: initialize.Bool(false), + ReadyToUse: initialize.Bool(true), }, }, { @@ -457,11 +1004,11 @@ func TestGetLatestReadySnapshot(t *testing.T) { }, }, } - latestSnapshotWithError := getLatestReadySnapshot(snapshotList) - assert.Check(t, latestSnapshotWithError == nil) + snapshotWithLatestError := getSnapshotWithLatestError(snapshotList) + assert.Check(t, snapshotWithLatestError == nil) }) - t.Run("OneReadySnapshot", func(t *testing.T) { + t.Run("OneSnapshotWithError", func(t *testing.T) { currentTime := metav1.Now() earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) snapshotList := &volumesnapshotv1.VolumeSnapshotList{ @@ -472,7 +1019,7 @@ func TestGetLatestReadySnapshot(t *testing.T) { UID: "the-uid-123", }, Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: &earlierTime, + CreationTime: ¤tTime, ReadyToUse: initialize.Bool(true), }, }, @@ -482,45 +1029,51 @@ func TestGetLatestReadySnapshot(t *testing.T) { UID: "the-uid-456", }, Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: ¤tTime, - ReadyToUse: initialize.Bool(false), + ReadyToUse: initialize.Bool(false), + Error: &volumesnapshotv1.VolumeSnapshotError{ + Time: &earlierTime, + }, }, }, }, } - latestReadySnapshot := getLatestReadySnapshot(snapshotList) - assert.Equal(t, latestReadySnapshot.ObjectMeta.Name, "good-snapshot") + snapshotWithLatestError := getSnapshotWithLatestError(snapshotList) + assert.Equal(t, snapshotWithLatestError.ObjectMeta.Name, "bad-snapshot") }) - t.Run("TwoReadySnapshots", func(t *testing.T) { + t.Run("TwoSnapshotsWithErrors", func(t *testing.T) { currentTime := metav1.Now() earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) snapshotList := &volumesnapshotv1.VolumeSnapshotList{ Items: []volumesnapshotv1.VolumeSnapshot{ { ObjectMeta: metav1.ObjectMeta{ - Name: "first-good-snapshot", + Name: "first-bad-snapshot", UID: "the-uid-123", }, Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: &earlierTime, - ReadyToUse: initialize.Bool(true), + ReadyToUse: initialize.Bool(false), + Error: &volumesnapshotv1.VolumeSnapshotError{ + Time: &earlierTime, + }, }, }, { ObjectMeta: metav1.ObjectMeta{ - Name: "second-good-snapshot", + Name: "second-bad-snapshot", UID: "the-uid-456", }, Status: &volumesnapshotv1.VolumeSnapshotStatus{ - CreationTime: ¤tTime, - ReadyToUse: initialize.Bool(true), + ReadyToUse: initialize.Bool(false), + Error: &volumesnapshotv1.VolumeSnapshotError{ + Time: ¤tTime, + }, }, }, }, } - latestReadySnapshot := getLatestReadySnapshot(snapshotList) - assert.Equal(t, latestReadySnapshot.ObjectMeta.Name, "second-good-snapshot") + snapshotWithLatestError := getSnapshotWithLatestError(snapshotList) + assert.Equal(t, snapshotWithLatestError.ObjectMeta.Name, "second-bad-snapshot") }) } @@ -653,3 +1206,271 @@ func TestGetSnapshotsForCluster(t *testing.T) { assert.Equal(t, len(snapshots.Items), 2) }) } + +func TestGetLatestReadySnapshot(t *testing.T) { + t.Run("NoSnapshots", func(t *testing.T) { + snapshotList := &volumesnapshotv1.VolumeSnapshotList{} + latestReadySnapshot := getLatestReadySnapshot(snapshotList) + assert.Assert(t, latestReadySnapshot == nil) + }) + + t.Run("NoSnapshotsWithStatus", func(t *testing.T) { + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + {}, + {}, + }, + } + latestReadySnapshot := getLatestReadySnapshot(snapshotList) + assert.Assert(t, latestReadySnapshot == nil) + }) + + t.Run("NoReadySnapshots", func(t *testing.T) { + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + { + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + ReadyToUse: initialize.Bool(false), + }, + }, + { + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + ReadyToUse: initialize.Bool(false), + }, + }, + }, + } + latestReadySnapshot := getLatestReadySnapshot(snapshotList) + assert.Assert(t, latestReadySnapshot == nil) + }) + + t.Run("OneReadySnapshot", func(t *testing.T) { + currentTime := metav1.Now() + earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "good-snapshot", + UID: "the-uid-123", + }, + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + CreationTime: &earlierTime, + ReadyToUse: initialize.Bool(true), + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "bad-snapshot", + UID: "the-uid-456", + }, + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + CreationTime: ¤tTime, + ReadyToUse: initialize.Bool(false), + }, + }, + }, + } + latestReadySnapshot := getLatestReadySnapshot(snapshotList) + assert.Equal(t, latestReadySnapshot.ObjectMeta.Name, "good-snapshot") + }) + + t.Run("TwoReadySnapshots", func(t *testing.T) { + currentTime := metav1.Now() + earlierTime := metav1.NewTime(currentTime.AddDate(-1, 0, 0)) + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "first-good-snapshot", + UID: "the-uid-123", + }, + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + CreationTime: &earlierTime, + ReadyToUse: initialize.Bool(true), + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "second-good-snapshot", + UID: "the-uid-456", + }, + Status: &volumesnapshotv1.VolumeSnapshotStatus{ + CreationTime: ¤tTime, + ReadyToUse: initialize.Bool(true), + }, + }, + }, + } + latestReadySnapshot := getLatestReadySnapshot(snapshotList) + assert.Equal(t, latestReadySnapshot.ObjectMeta.Name, "second-good-snapshot") + }) +} + +func TestDeleteSnapshots(t *testing.T) { + ctx := context.Background() + cfg, cc := setupKubernetes(t) + discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) + assert.NilError(t, err) + + r := &Reconciler{ + Client: cc, + Owner: client.FieldOwner(t.Name()), + DiscoveryClient: discoveryClient, + } + ns := setupNamespace(t, cc) + + cluster := testCluster() + cluster.Namespace = ns.Name + cluster.ObjectMeta.UID = "the-uid-123" + assert.NilError(t, r.Client.Create(ctx, cluster)) + + rhinoCluster := testCluster() + rhinoCluster.Name = "rhino" + rhinoCluster.Namespace = ns.Name + rhinoCluster.ObjectMeta.UID = "the-uid-456" + assert.NilError(t, r.Client.Create(ctx, rhinoCluster)) + + t.Cleanup(func() { + assert.Check(t, r.Client.Delete(ctx, cluster)) + assert.Check(t, r.Client.Delete(ctx, rhinoCluster)) + }) + + t.Run("NoSnapshots", func(t *testing.T) { + snapshotList := &volumesnapshotv1.VolumeSnapshotList{} + err := r.deleteSnapshots(ctx, cluster, snapshotList) + assert.NilError(t, err) + }) + + t.Run("NoSnapshotsControlledByHippo", func(t *testing.T) { + pvcName := initialize.String("dedicated-snapshot-volume") + snapshot1 := &volumesnapshotv1.VolumeSnapshot{ + TypeMeta: metav1.TypeMeta{ + APIVersion: volumesnapshotv1.SchemeGroupVersion.String(), + Kind: "VolumeSnapshot", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "first-snapshot", + Namespace: ns.Name, + }, + Spec: volumesnapshotv1.VolumeSnapshotSpec{ + Source: volumesnapshotv1.VolumeSnapshotSource{ + PersistentVolumeClaimName: pvcName, + }, + }, + } + err := errors.WithStack(r.setControllerReference(rhinoCluster, snapshot1)) + assert.NilError(t, err) + err = r.apply(ctx, snapshot1) + assert.NilError(t, err) + + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + *snapshot1, + }, + } + err = r.deleteSnapshots(ctx, cluster, snapshotList) + assert.NilError(t, err) + existingSnapshots := &volumesnapshotv1.VolumeSnapshotList{} + err = errors.WithStack( + r.Client.List(ctx, existingSnapshots, + client.InNamespace(ns.Namespace), + )) + assert.NilError(t, err) + assert.Equal(t, len(existingSnapshots.Items), 1) + }) + + t.Run("OneSnapshotControlledByHippo", func(t *testing.T) { + pvcName := initialize.String("dedicated-snapshot-volume") + snapshot1 := &volumesnapshotv1.VolumeSnapshot{ + TypeMeta: metav1.TypeMeta{ + APIVersion: volumesnapshotv1.SchemeGroupVersion.String(), + Kind: "VolumeSnapshot", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "first-snapshot", + Namespace: ns.Name, + }, + Spec: volumesnapshotv1.VolumeSnapshotSpec{ + Source: volumesnapshotv1.VolumeSnapshotSource{ + PersistentVolumeClaimName: pvcName, + }, + }, + } + err := errors.WithStack(r.setControllerReference(rhinoCluster, snapshot1)) + assert.NilError(t, err) + err = r.apply(ctx, snapshot1) + assert.NilError(t, err) + + snapshot2 := &volumesnapshotv1.VolumeSnapshot{ + TypeMeta: metav1.TypeMeta{ + APIVersion: volumesnapshotv1.SchemeGroupVersion.String(), + Kind: "VolumeSnapshot", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "second-snapshot", + Namespace: ns.Name, + }, + Spec: volumesnapshotv1.VolumeSnapshotSpec{ + Source: volumesnapshotv1.VolumeSnapshotSource{ + PersistentVolumeClaimName: pvcName, + }, + }, + } + err = errors.WithStack(r.setControllerReference(cluster, snapshot2)) + assert.NilError(t, err) + err = r.apply(ctx, snapshot2) + assert.NilError(t, err) + + snapshotList := &volumesnapshotv1.VolumeSnapshotList{ + Items: []volumesnapshotv1.VolumeSnapshot{ + *snapshot1, *snapshot2, + }, + } + err = r.deleteSnapshots(ctx, cluster, snapshotList) + assert.NilError(t, err) + existingSnapshots := &volumesnapshotv1.VolumeSnapshotList{} + err = errors.WithStack( + r.Client.List(ctx, existingSnapshots, + client.InNamespace(ns.Namespace), + )) + assert.NilError(t, err) + assert.Equal(t, len(existingSnapshots.Items), 1) + assert.Equal(t, existingSnapshots.Items[0].Name, "first-snapshot") + }) +} + +func TestClusterUsingTablespaces(t *testing.T) { + ctx := context.Background() + cluster := testCluster() + + t.Run("NoVolumesFeatureEnabled", func(t *testing.T) { + // Enable Tablespaces feature gate + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.TablespaceVolumes: true, + })) + ctx := feature.NewContext(ctx, gate) + + assert.Assert(t, !clusterUsingTablespaces(ctx, cluster)) + }) + + t.Run("VolumesInPlaceFeatureDisabled", func(t *testing.T) { + cluster.Spec.InstanceSets[0].TablespaceVolumes = []v1beta1.TablespaceVolume{{ + Name: "volume-1", + }} + + assert.Assert(t, !clusterUsingTablespaces(ctx, cluster)) + }) + + t.Run("VolumesInPlaceAndFeatureEnabled", func(t *testing.T) { + // Enable Tablespaces feature gate + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.TablespaceVolumes: true, + })) + ctx := feature.NewContext(ctx, gate) + + assert.Assert(t, clusterUsingTablespaces(ctx, cluster)) + }) +} diff --git a/internal/controller/postgrescluster/suite_test.go b/internal/controller/postgrescluster/suite_test.go index 1f289ed928..2a0e3d76ec 100644 --- a/internal/controller/postgrescluster/suite_test.go +++ b/internal/controller/postgrescluster/suite_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/topology.go b/internal/controller/postgrescluster/topology.go index a1a73d8581..58778be907 100644 --- a/internal/controller/postgrescluster/topology.go +++ b/internal/controller/postgrescluster/topology.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/topology_test.go b/internal/controller/postgrescluster/topology_test.go index 3e37a84c9c..40c8c0dd7f 100644 --- a/internal/controller/postgrescluster/topology_test.go +++ b/internal/controller/postgrescluster/topology_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/util.go b/internal/controller/postgrescluster/util.go index d1658ac42e..25120ab574 100644 --- a/internal/controller/postgrescluster/util.go +++ b/internal/controller/postgrescluster/util.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/util_test.go b/internal/controller/postgrescluster/util_test.go index e21b270027..51a32f1e85 100644 --- a/internal/controller/postgrescluster/util_test.go +++ b/internal/controller/postgrescluster/util_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/volumes.go b/internal/controller/postgrescluster/volumes.go index 752677423f..e40710d4ff 100644 --- a/internal/controller/postgrescluster/volumes.go +++ b/internal/controller/postgrescluster/volumes.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster @@ -510,10 +499,9 @@ func (r *Reconciler) reconcileMovePGDataDir(ctx context.Context, }, } // set the priority class name, if it exists - if len(cluster.Spec.InstanceSets) > 0 && - cluster.Spec.InstanceSets[0].PriorityClassName != nil { + if len(cluster.Spec.InstanceSets) > 0 { jobSpec.Template.Spec.PriorityClassName = - *cluster.Spec.InstanceSets[0].PriorityClassName + initialize.FromPointer(cluster.Spec.InstanceSets[0].PriorityClassName) } moveDirJob.Spec = *jobSpec @@ -628,10 +616,9 @@ func (r *Reconciler) reconcileMoveWALDir(ctx context.Context, }, } // set the priority class name, if it exists - if len(cluster.Spec.InstanceSets) > 0 && - cluster.Spec.InstanceSets[0].PriorityClassName != nil { + if len(cluster.Spec.InstanceSets) > 0 { jobSpec.Template.Spec.PriorityClassName = - *cluster.Spec.InstanceSets[0].PriorityClassName + initialize.FromPointer(cluster.Spec.InstanceSets[0].PriorityClassName) } moveDirJob.Spec = *jobSpec @@ -751,9 +738,7 @@ func (r *Reconciler) reconcileMoveRepoDir(ctx context.Context, } // set the priority class name, if it exists if repoHost := cluster.Spec.Backups.PGBackRest.RepoHost; repoHost != nil { - if repoHost.PriorityClassName != nil { - jobSpec.Template.Spec.PriorityClassName = *repoHost.PriorityClassName - } + jobSpec.Template.Spec.PriorityClassName = initialize.FromPointer(repoHost.PriorityClassName) } moveDirJob.Spec = *jobSpec diff --git a/internal/controller/postgrescluster/volumes_test.go b/internal/controller/postgrescluster/volumes_test.go index 3fa16f80c6..96eef5f916 100644 --- a/internal/controller/postgrescluster/volumes_test.go +++ b/internal/controller/postgrescluster/volumes_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/watches.go b/internal/controller/postgrescluster/watches.go index c6d592283d..0b5ba5fa87 100644 --- a/internal/controller/postgrescluster/watches.go +++ b/internal/controller/postgrescluster/watches.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/postgrescluster/watches_test.go b/internal/controller/postgrescluster/watches_test.go index 07988b1d4c..fdea498862 100644 --- a/internal/controller/postgrescluster/watches_test.go +++ b/internal/controller/postgrescluster/watches_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgrescluster diff --git a/internal/controller/runtime/client.go b/internal/controller/runtime/client.go index ae57c08472..4cc05c9835 100644 --- a/internal/controller/runtime/client.go +++ b/internal/controller/runtime/client.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/pod_client.go b/internal/controller/runtime/pod_client.go index 15485b0cbf..e842601aa7 100644 --- a/internal/controller/runtime/pod_client.go +++ b/internal/controller/runtime/pod_client.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/reconcile.go b/internal/controller/runtime/reconcile.go index bb278f0f46..a2196d1626 100644 --- a/internal/controller/runtime/reconcile.go +++ b/internal/controller/runtime/reconcile.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/reconcile_test.go b/internal/controller/runtime/reconcile_test.go index 4dd10e1700..925b3cf47d 100644 --- a/internal/controller/runtime/reconcile_test.go +++ b/internal/controller/runtime/reconcile_test.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/runtime.go b/internal/controller/runtime/runtime.go index 4ddbdd94f7..34bfeabf61 100644 --- a/internal/controller/runtime/runtime.go +++ b/internal/controller/runtime/runtime.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/ticker.go b/internal/controller/runtime/ticker.go index 850a3f9693..830179eafc 100644 --- a/internal/controller/runtime/ticker.go +++ b/internal/controller/runtime/ticker.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/runtime/ticker_test.go b/internal/controller/runtime/ticker_test.go index 86db74bdfd..49cecd79d7 100644 --- a/internal/controller/runtime/ticker_test.go +++ b/internal/controller/runtime/ticker_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package runtime diff --git a/internal/controller/standalone_pgadmin/apply.go b/internal/controller/standalone_pgadmin/apply.go index cad148c768..0eaa613df8 100644 --- a/internal/controller/standalone_pgadmin/apply.go +++ b/internal/controller/standalone_pgadmin/apply.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/config.go b/internal/controller/standalone_pgadmin/config.go index a842a296ab..ddd080985b 100644 --- a/internal/controller/standalone_pgadmin/config.go +++ b/internal/controller/standalone_pgadmin/config.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/configmap.go b/internal/controller/standalone_pgadmin/configmap.go index a76cb06bf7..d1ec39bf13 100644 --- a/internal/controller/standalone_pgadmin/configmap.go +++ b/internal/controller/standalone_pgadmin/configmap.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin @@ -63,7 +53,7 @@ func configmap(pgadmin *v1beta1.PGAdmin, naming.StandalonePGAdminLabels(pgadmin.Name)) // TODO(tjmoore4): Populate configuration details. - initialize.StringMap(&configmap.Data) + initialize.Map(&configmap.Data) configSettings, err := generateConfig(pgadmin) if err == nil { configmap.Data[settingsConfigMapKey] = configSettings diff --git a/internal/controller/standalone_pgadmin/configmap_test.go b/internal/controller/standalone_pgadmin/configmap_test.go index c5f22e53cb..5a844e520c 100644 --- a/internal/controller/standalone_pgadmin/configmap_test.go +++ b/internal/controller/standalone_pgadmin/configmap_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/controller.go b/internal/controller/standalone_pgadmin/controller.go index 38556e45c7..81d5fc2d40 100644 --- a/internal/controller/standalone_pgadmin/controller.go +++ b/internal/controller/standalone_pgadmin/controller.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin @@ -44,6 +34,7 @@ type PGAdminReconciler struct { IsOpenShift bool } +//+kubebuilder:rbac:groups="postgres-operator.crunchydata.com",resources="pgadmins",verbs={list,watch} //+kubebuilder:rbac:groups="postgres-operator.crunchydata.com",resources="postgresclusters",verbs={list,watch} //+kubebuilder:rbac:groups="",resources="persistentvolumeclaims",verbs={list,watch} //+kubebuilder:rbac:groups="",resources="secrets",verbs={list,watch} diff --git a/internal/controller/standalone_pgadmin/controller_test.go b/internal/controller/standalone_pgadmin/controller_test.go index c31ff59cd2..b0fe17cbe6 100644 --- a/internal/controller/standalone_pgadmin/controller_test.go +++ b/internal/controller/standalone_pgadmin/controller_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/helpers_test.go b/internal/controller/standalone_pgadmin/helpers_test.go index 1f099a2b53..9096edb5a1 100644 --- a/internal/controller/standalone_pgadmin/helpers_test.go +++ b/internal/controller/standalone_pgadmin/helpers_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/helpers_unit_test.go b/internal/controller/standalone_pgadmin/helpers_unit_test.go index d55881bd50..63887385fc 100644 --- a/internal/controller/standalone_pgadmin/helpers_unit_test.go +++ b/internal/controller/standalone_pgadmin/helpers_unit_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/pod.go b/internal/controller/standalone_pgadmin/pod.go index 1b43075c95..bbb39b9322 100644 --- a/internal/controller/standalone_pgadmin/pod.go +++ b/internal/controller/standalone_pgadmin/pod.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin @@ -20,6 +10,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/util/intstr" "github.com/crunchydata/postgres-operator/internal/config" "github.com/crunchydata/postgres-operator/internal/initialize" @@ -124,9 +115,18 @@ func pod( Name: "PGADMIN_SETUP_EMAIL", Value: fmt.Sprintf("admin@%s.%s.svc", inPGAdmin.Name, inPGAdmin.Namespace), }, + // Setting the KRB5_CONFIG for kerberos + // - https://web.mit.edu/kerberos/krb5-current/doc/admin/conf_files/krb5_conf.html + { + Name: "KRB5_CONFIG", + Value: configMountPath + "/krb5.conf", + }, + // In testing it was determined that we need to set this env var for the replay cache + // otherwise it defaults to the read-only location `/var/tmp/` + // - https://web.mit.edu/kerberos/krb5-current/doc/basic/rcache_def.html#replay-cache-types { - Name: "PGADMIN_LISTEN_PORT", - Value: fmt.Sprintf("%d", pgAdminPort), + Name: "KRB5RCACHEDIR", + Value: "/tmp", }, }, VolumeMounts: []corev1.VolumeMount{ @@ -160,7 +160,7 @@ func pod( readinessProbe := &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ - Port: *initialize.IntOrStringInt32(pgAdminPort), + Port: intstr.FromInt32(pgAdminPort), Path: "/login", Scheme: corev1.URISchemeHTTP, }, @@ -431,12 +431,11 @@ with open('` + configMountPath + `/` + gunicornConfigFilePath + `') as _f: script := strings.Join([]string{ // Use the initContainer to create this path to avoid the error noted here: - // - https://github.com/kubernetes/kubernetes/issues/121294 - `mkdir -p /etc/pgadmin/conf.d`, - // Write the system configuration into a read-only file. - `(umask a-w && echo "$1" > ` + scriptMountPath + `/config_system.py` + `)`, - // Write the server configuration into a read-only file. - `(umask a-w && echo "$2" > ` + scriptMountPath + `/gunicorn_config.py` + `)`, + // - https://issue.k8s.io/121294 + `mkdir -p ` + configMountPath, + // Write the system and server configurations. + `echo "$1" > ` + scriptMountPath + `/config_system.py`, + `echo "$2" > ` + scriptMountPath + `/gunicorn_config.py`, }, "\n") return append([]string{"bash", "-ceu", "--", script, "startup"}, args...) diff --git a/internal/controller/standalone_pgadmin/pod_test.go b/internal/controller/standalone_pgadmin/pod_test.go index 4bb74a5068..19cee52882 100644 --- a/internal/controller/standalone_pgadmin/pod_test.go +++ b/internal/controller/standalone_pgadmin/pod_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin @@ -104,8 +94,10 @@ containers: env: - name: PGADMIN_SETUP_EMAIL value: admin@pgadmin.postgres-operator.svc - - name: PGADMIN_LISTEN_PORT - value: "5050" + - name: KRB5_CONFIG + value: /etc/pgadmin/conf.d/krb5.conf + - name: KRB5RCACHEDIR + value: /tmp name: pgadmin ports: - containerPort: 5050 @@ -147,8 +139,8 @@ initContainers: - -- - |- mkdir -p /etc/pgadmin/conf.d - (umask a-w && echo "$1" > /etc/pgadmin/config_system.py) - (umask a-w && echo "$2" > /etc/pgadmin/gunicorn_config.py) + echo "$1" > /etc/pgadmin/config_system.py + echo "$2" > /etc/pgadmin/gunicorn_config.py - startup - | import glob, json, re, os @@ -287,8 +279,10 @@ containers: env: - name: PGADMIN_SETUP_EMAIL value: admin@pgadmin.postgres-operator.svc - - name: PGADMIN_LISTEN_PORT - value: "5050" + - name: KRB5_CONFIG + value: /etc/pgadmin/conf.d/krb5.conf + - name: KRB5RCACHEDIR + value: /tmp image: new-image imagePullPolicy: Always name: pgadmin @@ -334,8 +328,8 @@ initContainers: - -- - |- mkdir -p /etc/pgadmin/conf.d - (umask a-w && echo "$1" > /etc/pgadmin/config_system.py) - (umask a-w && echo "$2" > /etc/pgadmin/gunicorn_config.py) + echo "$1" > /etc/pgadmin/config_system.py + echo "$2" > /etc/pgadmin/gunicorn_config.py - startup - | import glob, json, re, os diff --git a/internal/controller/standalone_pgadmin/postgrescluster.go b/internal/controller/standalone_pgadmin/postgrescluster.go index 5ad48e915b..5327b8ae70 100644 --- a/internal/controller/standalone_pgadmin/postgrescluster.go +++ b/internal/controller/standalone_pgadmin/postgrescluster.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/service.go b/internal/controller/standalone_pgadmin/service.go index 7d96234f15..2453a6a1fa 100644 --- a/internal/controller/standalone_pgadmin/service.go +++ b/internal/controller/standalone_pgadmin/service.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/service_test.go b/internal/controller/standalone_pgadmin/service_test.go index 0db7ce3bbb..24b20c8247 100644 --- a/internal/controller/standalone_pgadmin/service_test.go +++ b/internal/controller/standalone_pgadmin/service_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/statefulset.go b/internal/controller/standalone_pgadmin/statefulset.go index 68a886efa1..e086e333f4 100644 --- a/internal/controller/standalone_pgadmin/statefulset.go +++ b/internal/controller/standalone_pgadmin/statefulset.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin @@ -104,10 +94,7 @@ func statefulset( // Use scheduling constraints from the cluster spec. sts.Spec.Template.Spec.Affinity = pgadmin.Spec.Affinity sts.Spec.Template.Spec.Tolerations = pgadmin.Spec.Tolerations - - if pgadmin.Spec.PriorityClassName != nil { - sts.Spec.Template.Spec.PriorityClassName = *pgadmin.Spec.PriorityClassName - } + sts.Spec.Template.Spec.PriorityClassName = initialize.FromPointer(pgadmin.Spec.PriorityClassName) // Restart containers any time they stop, die, are killed, etc. // - https://docs.k8s.io/concepts/workloads/pods/pod-lifecycle/#restart-policy diff --git a/internal/controller/standalone_pgadmin/statefulset_test.go b/internal/controller/standalone_pgadmin/statefulset_test.go index dea5b983b4..52c501b357 100644 --- a/internal/controller/standalone_pgadmin/statefulset_test.go +++ b/internal/controller/standalone_pgadmin/statefulset_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/users.go b/internal/controller/standalone_pgadmin/users.go index 6666a22556..3c9a3ce05b 100644 --- a/internal/controller/standalone_pgadmin/users.go +++ b/internal/controller/standalone_pgadmin/users.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/users_test.go b/internal/controller/standalone_pgadmin/users_test.go index 13bd30d74e..409fcea701 100644 --- a/internal/controller/standalone_pgadmin/users_test.go +++ b/internal/controller/standalone_pgadmin/users_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/volume.go b/internal/controller/standalone_pgadmin/volume.go index dd488b6c62..7615f6142b 100644 --- a/internal/controller/standalone_pgadmin/volume.go +++ b/internal/controller/standalone_pgadmin/volume.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/volume_test.go b/internal/controller/standalone_pgadmin/volume_test.go index 784f6e1c95..645c228277 100644 --- a/internal/controller/standalone_pgadmin/volume_test.go +++ b/internal/controller/standalone_pgadmin/volume_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/watches.go b/internal/controller/standalone_pgadmin/watches.go index c117a7cac9..49ac1ebd29 100644 --- a/internal/controller/standalone_pgadmin/watches.go +++ b/internal/controller/standalone_pgadmin/watches.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/controller/standalone_pgadmin/watches_test.go b/internal/controller/standalone_pgadmin/watches_test.go index 0afc097a7f..1419eb9efa 100644 --- a/internal/controller/standalone_pgadmin/watches_test.go +++ b/internal/controller/standalone_pgadmin/watches_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package standalone_pgadmin diff --git a/internal/feature/features.go b/internal/feature/features.go index 723e037503..db424ead42 100644 --- a/internal/feature/features.go +++ b/internal/feature/features.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 /* Package feature provides types and functions to enable and disable features @@ -105,7 +94,7 @@ func NewGate() MutableGate { if err := gate.Add(map[Feature]featuregate.FeatureSpec{ AppendCustomQueries: {Default: false, PreRelease: featuregate.Alpha}, - AutoCreateUserSchema: {Default: false, PreRelease: featuregate.Alpha}, + AutoCreateUserSchema: {Default: true, PreRelease: featuregate.Beta}, AutoGrowVolumes: {Default: false, PreRelease: featuregate.Alpha}, BridgeIdentifiers: {Default: false, PreRelease: featuregate.Alpha}, InstanceSidecars: {Default: false, PreRelease: featuregate.Alpha}, @@ -132,3 +121,12 @@ func Enabled(ctx context.Context, f Feature) bool { func NewContext(ctx context.Context, gate Gate) context.Context { return context.WithValue(ctx, contextKey{}, gate) } + +func ShowGates(ctx context.Context) string { + featuresEnabled := "" + gate, ok := ctx.Value(contextKey{}).(Gate) + if ok { + featuresEnabled = gate.String() + } + return featuresEnabled +} diff --git a/internal/feature/features_test.go b/internal/feature/features_test.go index aec06c90dd..f76dd216e6 100644 --- a/internal/feature/features_test.go +++ b/internal/feature/features_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package feature @@ -27,7 +16,7 @@ func TestDefaults(t *testing.T) { gate := NewGate() assert.Assert(t, false == gate.Enabled(AppendCustomQueries)) - assert.Assert(t, false == gate.Enabled(AutoCreateUserSchema)) + assert.Assert(t, true == gate.Enabled(AutoCreateUserSchema)) assert.Assert(t, false == gate.Enabled(AutoGrowVolumes)) assert.Assert(t, false == gate.Enabled(BridgeIdentifiers)) assert.Assert(t, false == gate.Enabled(InstanceSidecars)) @@ -64,10 +53,13 @@ func TestContext(t *testing.T) { t.Parallel() gate := NewGate() ctx := NewContext(context.Background(), gate) + assert.Equal(t, ShowGates(ctx), "") assert.NilError(t, gate.Set("TablespaceVolumes=true")) assert.Assert(t, true == Enabled(ctx, TablespaceVolumes)) + assert.Equal(t, ShowGates(ctx), "TablespaceVolumes=true") assert.NilError(t, gate.SetFromMap(map[string]bool{TablespaceVolumes: false})) assert.Assert(t, false == Enabled(ctx, TablespaceVolumes)) + assert.Equal(t, ShowGates(ctx), "TablespaceVolumes=false") } diff --git a/internal/initialize/doc.go b/internal/initialize/doc.go index 34e34e5cb9..aedd85846f 100644 --- a/internal/initialize/doc.go +++ b/internal/initialize/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package initialize provides functions to initialize some common fields and types. package initialize diff --git a/internal/initialize/intstr.go b/internal/initialize/intstr.go deleted file mode 100644 index d6efe71885..0000000000 --- a/internal/initialize/intstr.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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 initialize - -import ( - "k8s.io/apimachinery/pkg/util/intstr" -) - -// IntOrStringInt32 returns an *intstr.IntOrString containing i. -func IntOrStringInt32(i int32) *intstr.IntOrString { - return IntOrString(intstr.FromInt(int(i))) -} - -// IntOrStringString returns an *intstr.IntOrString containing s. -func IntOrStringString(s string) *intstr.IntOrString { - return IntOrString(intstr.FromString(s)) -} - -// IntOrString returns a pointer to the provided IntOrString -func IntOrString(ios intstr.IntOrString) *intstr.IntOrString { - return &ios -} diff --git a/internal/initialize/intstr_test.go b/internal/initialize/intstr_test.go deleted file mode 100644 index 388c3795b2..0000000000 --- a/internal/initialize/intstr_test.go +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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 initialize_test - -import ( - "testing" - - "gotest.tools/v3/assert" - "k8s.io/apimachinery/pkg/util/intstr" - - "github.com/crunchydata/postgres-operator/internal/initialize" -) - -func TestIntOrStringInt32(t *testing.T) { - // Same content as the upstream constructor. - upstream := intstr.FromInt(42) - n := initialize.IntOrStringInt32(42) - - assert.DeepEqual(t, &upstream, n) -} - -func TestIntOrStringString(t *testing.T) { - upstream := intstr.FromString("50%") - s := initialize.IntOrStringString("50%") - - assert.DeepEqual(t, &upstream, s) -} -func TestIntOrString(t *testing.T) { - upstream := intstr.FromInt(0) - - ios := initialize.IntOrString(intstr.FromInt(0)) - assert.DeepEqual(t, *ios, upstream) -} diff --git a/internal/initialize/metadata.go b/internal/initialize/metadata.go index f27d4c6751..d62530736a 100644 --- a/internal/initialize/metadata.go +++ b/internal/initialize/metadata.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize diff --git a/internal/initialize/metadata_test.go b/internal/initialize/metadata_test.go index 280b73abde..735e455a2e 100644 --- a/internal/initialize/metadata_test.go +++ b/internal/initialize/metadata_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize_test diff --git a/internal/initialize/primitives.go b/internal/initialize/primitives.go index e3954ba436..9bc264f88c 100644 --- a/internal/initialize/primitives.go +++ b/internal/initialize/primitives.go @@ -1,30 +1,12 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize // Bool returns a pointer to v. func Bool(v bool) *bool { return &v } -// ByteMap initializes m when it points to nil. -func ByteMap(m *map[string][]byte) { - if m != nil && *m == nil { - *m = make(map[string][]byte) - } -} - // FromPointer returns the value that p points to. // When p is nil, it returns the zero value of T. func FromPointer[T any](p *T) T { @@ -41,15 +23,17 @@ func Int32(v int32) *int32 { return &v } // Int64 returns a pointer to v. func Int64(v int64) *int64 { return &v } +// Map initializes m when it points to nil. +func Map[M ~map[K]V, K comparable, V any](m *M) { + // See https://pkg.go.dev/maps for similar type constraints. + + if m != nil && *m == nil { + *m = make(M) + } +} + // Pointer returns a pointer to v. func Pointer[T any](v T) *T { return &v } // String returns a pointer to v. func String(v string) *string { return &v } - -// StringMap initializes m when it points to nil. -func StringMap(m *map[string]string) { - if m != nil && *m == nil { - *m = make(map[string]string) - } -} diff --git a/internal/initialize/primitives_test.go b/internal/initialize/primitives_test.go index 45829374e7..e39898b4fe 100644 --- a/internal/initialize/primitives_test.go +++ b/internal/initialize/primitives_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize_test @@ -35,27 +24,6 @@ func TestBool(t *testing.T) { } } -func TestByteMap(t *testing.T) { - // Ignores nil pointer. - initialize.ByteMap(nil) - - var m map[string][]byte - - // Starts nil. - assert.Assert(t, m == nil) - - // Gets initialized. - initialize.ByteMap(&m) - assert.DeepEqual(t, m, map[string][]byte{}) - - // Now writable. - m["x"] = []byte("y") - - // Doesn't overwrite. - initialize.ByteMap(&m) - assert.DeepEqual(t, m, map[string][]byte{"x": []byte("y")}) -} - func TestFromPointer(t *testing.T) { t.Run("bool", func(t *testing.T) { assert.Equal(t, initialize.FromPointer((*bool)(nil)), false) @@ -118,6 +86,50 @@ func TestInt64(t *testing.T) { } } +func TestMap(t *testing.T) { + t.Run("map[string][]byte", func(t *testing.T) { + // Ignores nil pointer. + initialize.Map((*map[string][]byte)(nil)) + + var m map[string][]byte + + // Starts nil. + assert.Assert(t, m == nil) + + // Gets initialized. + initialize.Map(&m) + assert.DeepEqual(t, m, map[string][]byte{}) + + // Now writable. + m["x"] = []byte("y") + + // Doesn't overwrite. + initialize.Map(&m) + assert.DeepEqual(t, m, map[string][]byte{"x": []byte("y")}) + }) + + t.Run("map[string]string", func(t *testing.T) { + // Ignores nil pointer. + initialize.Map((*map[string]string)(nil)) + + var m map[string]string + + // Starts nil. + assert.Assert(t, m == nil) + + // Gets initialized. + initialize.Map(&m) + assert.DeepEqual(t, m, map[string]string{}) + + // Now writable. + m["x"] = "y" + + // Doesn't overwrite. + initialize.Map(&m) + assert.DeepEqual(t, m, map[string]string{"x": "y"}) + }) +} + func TestPointer(t *testing.T) { t.Run("bool", func(t *testing.T) { n := initialize.Pointer(false) @@ -189,24 +201,3 @@ func TestString(t *testing.T) { assert.Equal(t, *n, "sup") } } - -func TestStringMap(t *testing.T) { - // Ignores nil pointer. - initialize.StringMap(nil) - - var m map[string]string - - // Starts nil. - assert.Assert(t, m == nil) - - // Gets initialized. - initialize.StringMap(&m) - assert.DeepEqual(t, m, map[string]string{}) - - // Now writable. - m["x"] = "y" - - // Doesn't overwrite. - initialize.StringMap(&m) - assert.DeepEqual(t, m, map[string]string{"x": "y"}) -} diff --git a/internal/initialize/security.go b/internal/initialize/security.go index 49291db478..5dd52d7b1e 100644 --- a/internal/initialize/security.go +++ b/internal/initialize/security.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize diff --git a/internal/initialize/security_test.go b/internal/initialize/security_test.go index 86ff98f701..0a6409cf41 100644 --- a/internal/initialize/security_test.go +++ b/internal/initialize/security_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package initialize_test diff --git a/internal/kubeapi/patch.go b/internal/kubeapi/patch.go index 992040a8d3..973852c17a 100644 --- a/internal/kubeapi/patch.go +++ b/internal/kubeapi/patch.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package kubeapi diff --git a/internal/kubeapi/patch_test.go b/internal/kubeapi/patch_test.go index 5307531228..52f5787b8f 100644 --- a/internal/kubeapi/patch_test.go +++ b/internal/kubeapi/patch_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package kubeapi diff --git a/internal/logging/logr.go b/internal/logging/logr.go index fe29175f7e..c907997d40 100644 --- a/internal/logging/logr.go +++ b/internal/logging/logr.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package logging diff --git a/internal/logging/logr_test.go b/internal/logging/logr_test.go index 2d9002650a..1cbc818ad9 100644 --- a/internal/logging/logr_test.go +++ b/internal/logging/logr_test.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package logging diff --git a/internal/logging/logrus.go b/internal/logging/logrus.go index 0f3d441d20..9683a104d1 100644 --- a/internal/logging/logrus.go +++ b/internal/logging/logrus.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package logging diff --git a/internal/logging/logrus_test.go b/internal/logging/logrus_test.go index ee5777e6a0..3e73193d1a 100644 --- a/internal/logging/logrus_test.go +++ b/internal/logging/logrus_test.go @@ -1,17 +1,6 @@ -/* -Copyright 2021 - 2024 Crunchy Data Solutions, Inc. -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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package logging diff --git a/internal/naming/annotations.go b/internal/naming/annotations.go index 21e8bd084b..2179a5f084 100644 --- a/internal/naming/annotations.go +++ b/internal/naming/annotations.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming @@ -32,10 +21,11 @@ const ( // ID associated with a specific manual backup Job. PGBackRestBackup = annotationPrefix + "pgbackrest-backup" - // PGBackRestBackupJobId is the annotation that is added to a VolumeSnapshot to identify the - // backup job that is associated with it (a backup is always taken right before a - // VolumeSnapshot is taken). - PGBackRestBackupJobId = annotationPrefix + "pgbackrest-backup-job-id" + // PGBackRestBackupJobCompletion is the annotation that is added to restore jobs, pvcs, and + // VolumeSnapshots that are involved in the volume snapshot creation process. The annotation + // holds a RFC3339 formatted timestamp that corresponds to the completion time of the associated + // backup job. + PGBackRestBackupJobCompletion = annotationPrefix + "pgbackrest-backup-job-completion" // PGBackRestConfigHash is an annotation used to specify the hash value associated with a // repo configuration as needed to detect configuration changes that invalidate running Jobs diff --git a/internal/naming/annotations_test.go b/internal/naming/annotations_test.go index 1d7d302773..318dd5ab5c 100644 --- a/internal/naming/annotations_test.go +++ b/internal/naming/annotations_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming @@ -23,13 +12,15 @@ import ( ) func TestAnnotationsValid(t *testing.T) { + assert.Assert(t, nil == validation.IsQualifiedName(AuthorizeBackupRemovalAnnotation)) + assert.Assert(t, nil == validation.IsQualifiedName(AutoCreateUserSchemaAnnotation)) + assert.Assert(t, nil == validation.IsQualifiedName(CrunchyBridgeClusterAdoptionAnnotation)) assert.Assert(t, nil == validation.IsQualifiedName(Finalizer)) assert.Assert(t, nil == validation.IsQualifiedName(PatroniSwitchover)) assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestBackup)) - assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestBackupJobId)) + assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestBackupJobCompletion)) assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestConfigHash)) - assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestRestore)) assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestIPVersion)) + assert.Assert(t, nil == validation.IsQualifiedName(PGBackRestRestore)) assert.Assert(t, nil == validation.IsQualifiedName(PostgresExporterCollectorsAnnotation)) - assert.Assert(t, nil == validation.IsQualifiedName(CrunchyBridgeClusterAdoptionAnnotation)) } diff --git a/internal/naming/controllers.go b/internal/naming/controllers.go index 35a1f8dd48..3d492e8a3a 100644 --- a/internal/naming/controllers.go +++ b/internal/naming/controllers.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/dns.go b/internal/naming/dns.go index b013cd69c7..d3351a5d70 100644 --- a/internal/naming/dns.go +++ b/internal/naming/dns.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/dns_test.go b/internal/naming/dns_test.go index 70c38f71ca..e7e2ea9dc6 100644 --- a/internal/naming/dns_test.go +++ b/internal/naming/dns_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/doc.go b/internal/naming/doc.go index 336193e5b6..72cab8b0b0 100644 --- a/internal/naming/doc.go +++ b/internal/naming/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package naming provides functions and constants for the postgres-operator // naming and labeling scheme. diff --git a/internal/naming/labels.go b/internal/naming/labels.go index 100c93df2f..f25993122b 100644 --- a/internal/naming/labels.go +++ b/internal/naming/labels.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming @@ -119,6 +108,9 @@ const ( // RoleMonitoring is the LabelRole applied to Monitoring resources RoleMonitoring = "monitoring" + + // RoleSnapshot is the LabelRole applied to Snapshot resources. + RoleSnapshot = "snapshot" ) const ( diff --git a/internal/naming/labels_test.go b/internal/naming/labels_test.go index a49a02eb78..b8a7779858 100644 --- a/internal/naming/labels_test.go +++ b/internal/naming/labels_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/limitations.md b/internal/naming/limitations.md index 78d3721088..ba607215f7 100644 --- a/internal/naming/limitations.md +++ b/internal/naming/limitations.md @@ -1,16 +1,7 @@ # Definitions diff --git a/internal/naming/names.go b/internal/naming/names.go index 02f854d5b2..369591de91 100644 --- a/internal/naming/names.go +++ b/internal/naming/names.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming @@ -260,6 +249,15 @@ func ClusterReplicaService(cluster *v1beta1.PostgresCluster) metav1.ObjectMeta { } } +// ClusterDedicatedSnapshotVolume returns the ObjectMeta for the dedicated Snapshot +// volume for a cluster. +func ClusterDedicatedSnapshotVolume(cluster *v1beta1.PostgresCluster) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Namespace: cluster.GetNamespace(), + Name: cluster.GetName() + "-snapshot", + } +} + // ClusterVolumeSnapshot returns the ObjectMeta, including a random name, for a // new pgdata VolumeSnapshot. func ClusterVolumeSnapshot(cluster *v1beta1.PostgresCluster) metav1.ObjectMeta { diff --git a/internal/naming/names_test.go b/internal/naming/names_test.go index 578559a27f..27835c3e5d 100644 --- a/internal/naming/names_test.go +++ b/internal/naming/names_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/selectors.go b/internal/naming/selectors.go index 060be697fb..94dbc3a9fa 100644 --- a/internal/naming/selectors.go +++ b/internal/naming/selectors.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming @@ -46,6 +35,18 @@ func Cluster(cluster string) metav1.LabelSelector { } } +// ClusterRestoreJobs selects all existing restore jobs in a cluster. +func ClusterRestoreJobs(cluster string) metav1.LabelSelector { + return metav1.LabelSelector{ + MatchLabels: map[string]string{ + LabelCluster: cluster, + }, + MatchExpressions: []metav1.LabelSelectorRequirement{ + {Key: LabelPGBackRestRestore, Operator: metav1.LabelSelectorOpExists}, + }, + } +} + // ClusterBackupJobs selects things for all existing backup jobs in cluster. func ClusterBackupJobs(cluster string) metav1.LabelSelector { return metav1.LabelSelector{ diff --git a/internal/naming/selectors_test.go b/internal/naming/selectors_test.go index 233e736cb3..1f5f42ad96 100644 --- a/internal/naming/selectors_test.go +++ b/internal/naming/selectors_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/naming/telemetry.go b/internal/naming/telemetry.go index d786287fff..5825d6299f 100644 --- a/internal/naming/telemetry.go +++ b/internal/naming/telemetry.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package naming diff --git a/internal/patroni/api.go b/internal/patroni/api.go index b3824904a2..679da5f4af 100644 --- a/internal/patroni/api.go +++ b/internal/patroni/api.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/api_test.go b/internal/patroni/api_test.go index 2df86ce1aa..1603d2fc75 100644 --- a/internal/patroni/api_test.go +++ b/internal/patroni/api_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/certificates.go b/internal/patroni/certificates.go index f7e80c33e1..9aa1525769 100644 --- a/internal/patroni/certificates.go +++ b/internal/patroni/certificates.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/certificates.md b/internal/patroni/certificates.md index 633466d31c..f58786ce20 100644 --- a/internal/patroni/certificates.md +++ b/internal/patroni/certificates.md @@ -1,16 +1,7 @@ Server diff --git a/internal/patroni/certificates_test.go b/internal/patroni/certificates_test.go index bf47b95b46..3073f2247f 100644 --- a/internal/patroni/certificates_test.go +++ b/internal/patroni/certificates_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/config.go b/internal/patroni/config.go index 8fcd845b78..b4d7e54f68 100644 --- a/internal/patroni/config.go +++ b/internal/patroni/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/config.md b/internal/patroni/config.md index 4c261c40ab..18d28d8a4e 100644 --- a/internal/patroni/config.md +++ b/internal/patroni/config.md @@ -1,16 +1,7 @@ Patroni configuration is complicated. The daemon `patroni` and the client diff --git a/internal/patroni/config_test.go b/internal/patroni/config_test.go index 230d2dd6a4..a45568df8b 100644 --- a/internal/patroni/config_test.go +++ b/internal/patroni/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni @@ -715,24 +704,6 @@ func TestDynamicConfiguration(t *testing.T) { }, }, }, - { - name: "pg version 10", - cluster: &v1beta1.PostgresCluster{ - Spec: v1beta1.PostgresClusterSpec{ - PostgresVersion: 10, - }, - }, - expected: map[string]any{ - "loop_wait": int32(10), - "ttl": int32(30), - "postgresql": map[string]any{ - "parameters": map[string]any{}, - "pg_hba": []string{}, - "use_pg_rewind": false, - "use_slots": false, - }, - }, - }, { name: "tde enabled", cluster: &v1beta1.PostgresCluster{ diff --git a/internal/patroni/doc.go b/internal/patroni/doc.go index 8962a0af23..500305406d 100644 --- a/internal/patroni/doc.go +++ b/internal/patroni/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package patroni provides clients, utilities and resources for configuring and // interacting with Patroni inside of a PostgreSQL cluster diff --git a/internal/patroni/rbac.go b/internal/patroni/rbac.go index a476f3b08d..dcf3f18cea 100644 --- a/internal/patroni/rbac.go +++ b/internal/patroni/rbac.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni @@ -23,25 +12,25 @@ import ( ) // "list", "patch", and "watch" are required. Include "get" for good measure. -// +kubebuilder:rbac:namespace=patroni,groups="",resources="pods",verbs={get} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="pods",verbs={list,watch} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="pods",verbs={patch} +// +kubebuilder:rbac:groups="",resources="pods",verbs={get} +// +kubebuilder:rbac:groups="",resources="pods",verbs={list,watch} +// +kubebuilder:rbac:groups="",resources="pods",verbs={patch} // TODO(cbandy): Separate these so that one can choose ConfigMap over Endpoints. // When using Endpoints for DCS, "create", "list", "patch", and "watch" are // required. Include "get" for good measure. The `patronictl scaffold` and // `patronictl remove` commands require "deletecollection". -// +kubebuilder:rbac:namespace=patroni,groups="",resources="endpoints",verbs={get} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="endpoints",verbs={create,deletecollection} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="endpoints",verbs={list,watch} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="endpoints",verbs={patch} -// +kubebuilder:rbac:namespace=patroni,groups="",resources="services",verbs={create} +// +kubebuilder:rbac:groups="",resources="endpoints",verbs={get} +// +kubebuilder:rbac:groups="",resources="endpoints",verbs={create,deletecollection} +// +kubebuilder:rbac:groups="",resources="endpoints",verbs={list,watch} +// +kubebuilder:rbac:groups="",resources="endpoints",verbs={patch} +// +kubebuilder:rbac:groups="",resources="services",verbs={create} // The OpenShift RestrictedEndpointsAdmission plugin requires special // authorization to create Endpoints that contain Pod IPs. // - https://github.com/openshift/origin/pull/9383 -// +kubebuilder:rbac:namespace=patroni,groups="",resources="endpoints/restricted",verbs={create} +// +kubebuilder:rbac:groups="",resources="endpoints/restricted",verbs={create} // Permissions returns the RBAC rules Patroni needs for cluster. func Permissions(cluster *v1beta1.PostgresCluster) []rbacv1.PolicyRule { diff --git a/internal/patroni/rbac_test.go b/internal/patroni/rbac_test.go index e62c34709c..39a8dff245 100644 --- a/internal/patroni/rbac_test.go +++ b/internal/patroni/rbac_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/patroni/reconcile.go b/internal/patroni/reconcile.go index 06f5d6f1e6..4fbb08b67d 100644 --- a/internal/patroni/reconcile.go +++ b/internal/patroni/reconcile.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni @@ -46,7 +35,7 @@ func ClusterConfigMap(ctx context.Context, ) error { var err error - initialize.StringMap(&outClusterConfigMap.Data) + initialize.Map(&outClusterConfigMap.Data) outClusterConfigMap.Data[configMapFileKey], err = clusterYAML(inCluster, inHBAs, inParameters) @@ -62,7 +51,7 @@ func InstanceConfigMap(ctx context.Context, ) error { var err error - initialize.StringMap(&outInstanceConfigMap.Data) + initialize.Map(&outInstanceConfigMap.Data) command := pgbackrest.ReplicaCreateCommand(inCluster, inInstanceSpec) @@ -77,7 +66,7 @@ func InstanceCertificates(ctx context.Context, inRoot pki.Certificate, inDNS pki.Certificate, inDNSKey pki.PrivateKey, outInstanceCertificates *corev1.Secret, ) error { - initialize.ByteMap(&outInstanceCertificates.Data) + initialize.Map(&outInstanceCertificates.Data) var err error outInstanceCertificates.Data[certAuthorityFileKey], err = certFile(inRoot) diff --git a/internal/patroni/reconcile_test.go b/internal/patroni/reconcile_test.go index 89b3920334..5d2a2c0ad5 100644 --- a/internal/patroni/reconcile_test.go +++ b/internal/patroni/reconcile_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package patroni diff --git a/internal/pgadmin/config.go b/internal/pgadmin/config.go index 4552b77d29..553a90f656 100644 --- a/internal/pgadmin/config.go +++ b/internal/pgadmin/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin diff --git a/internal/pgadmin/config_test.go b/internal/pgadmin/config_test.go index cdb3e1b569..87cd7847c2 100644 --- a/internal/pgadmin/config_test.go +++ b/internal/pgadmin/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin diff --git a/internal/pgadmin/reconcile.go b/internal/pgadmin/reconcile.go index a4c7cefc0c..af62c482f2 100644 --- a/internal/pgadmin/reconcile.go +++ b/internal/pgadmin/reconcile.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin @@ -144,7 +133,7 @@ func ConfigMap( return nil } - initialize.StringMap(&outConfigMap.Data) + initialize.Map(&outConfigMap.Data) // To avoid spurious reconciles, the following value must not change when // the spec does not change. [json.Encoder] and [json.Marshal] do this by diff --git a/internal/pgadmin/reconcile_test.go b/internal/pgadmin/reconcile_test.go index fe7697829d..f91a9b807f 100644 --- a/internal/pgadmin/reconcile_test.go +++ b/internal/pgadmin/reconcile_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin diff --git a/internal/pgadmin/users.go b/internal/pgadmin/users.go index 9c66cb36f2..7ce69ce211 100644 --- a/internal/pgadmin/users.go +++ b/internal/pgadmin/users.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin diff --git a/internal/pgadmin/users_test.go b/internal/pgadmin/users_test.go index 0bfa73d55d..69619667af 100644 --- a/internal/pgadmin/users_test.go +++ b/internal/pgadmin/users_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgadmin diff --git a/internal/pgaudit/postgres.go b/internal/pgaudit/postgres.go index 0941b40434..07867d020e 100644 --- a/internal/pgaudit/postgres.go +++ b/internal/pgaudit/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgaudit diff --git a/internal/pgaudit/postgres_test.go b/internal/pgaudit/postgres_test.go index 170a3b691e..3734e511f0 100644 --- a/internal/pgaudit/postgres_test.go +++ b/internal/pgaudit/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgaudit diff --git a/internal/pgbackrest/certificates.go b/internal/pgbackrest/certificates.go index e9bf93cf73..bb2633dfe7 100644 --- a/internal/pgbackrest/certificates.go +++ b/internal/pgbackrest/certificates.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/certificates.md b/internal/pgbackrest/certificates.md index ef6a1dd7b0..344616486b 100644 --- a/internal/pgbackrest/certificates.md +++ b/internal/pgbackrest/certificates.md @@ -1,16 +1,7 @@ Server diff --git a/internal/pgbackrest/certificates_test.go b/internal/pgbackrest/certificates_test.go index 0903deef4d..4ef41b2879 100644 --- a/internal/pgbackrest/certificates_test.go +++ b/internal/pgbackrest/certificates_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/config.go b/internal/pgbackrest/config.go index 0588eff156..f50b2690ee 100644 --- a/internal/pgbackrest/config.go +++ b/internal/pgbackrest/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -99,7 +88,7 @@ func CreatePGBackRestConfigMapIntent(postgresCluster *v1beta1.PostgresCluster, } // create an empty map for the config data - initialize.StringMap(&cm.Data) + initialize.Map(&cm.Data) pgdataDir := postgres.DataDirectory(postgresCluster) // Port will always be populated, since the API will set a default of 5432 if not provided @@ -274,6 +263,42 @@ mv "${pgdata}" "${pgdata}_bootstrap"` return append([]string{"bash", "-ceu", "--", restoreScript, "-", pgdata}, args...) } +// DedicatedSnapshotVolumeRestoreCommand returns the command for performing a pgBackRest delta restore +// into a dedicated snapshot volume. In addition to calling the pgBackRest restore command with any +// pgBackRest options provided, the script also removes the patroni.dynamic.json file if present. This +// ensures the configuration from the cluster being restored from is not utilized when bootstrapping a +// new cluster, and the configuration for the new cluster is utilized instead. +func DedicatedSnapshotVolumeRestoreCommand(pgdata string, args ...string) []string { + + // The postmaster.pid file is removed, if it exists, before attempting a restore. + // This allows the restore to be tried more than once without the causing an + // error due to the presence of the file in subsequent attempts. + + // Wrap pgbackrest restore command in backup_label checks. If pre/post + // backup_labels are different, restore moved database forward, so return 0 + // so that the Job is successful and we know to proceed with snapshot. + // Otherwise return 1, Job will fail, and we will not proceed with snapshot. + restoreScript := `declare -r pgdata="$1" opts="$2" +BACKUP_LABEL=$([[ ! -e "${pgdata}/backup_label" ]] || md5sum "${pgdata}/backup_label") +echo "Starting pgBackRest delta restore" + +install --directory --mode=0700 "${pgdata}" +rm -f "${pgdata}/postmaster.pid" +bash -xc "pgbackrest restore ${opts}" +rm -f "${pgdata}/patroni.dynamic.json" + +BACKUP_LABEL_POST=$([[ ! -e "${pgdata}/backup_label" ]] || md5sum "${pgdata}/backup_label") +if [[ "${BACKUP_LABEL}" != "${BACKUP_LABEL_POST}" ]] +then + exit 0 +fi +echo Database was not advanced by restore. No snapshot will be taken. +echo Check that your last backup was successful. +exit 1` + + return append([]string{"bash", "-ceu", "--", restoreScript, "-", pgdata}, args...) +} + // populatePGInstanceConfigurationMap returns options representing the pgBackRest configuration for // a PostgreSQL instance func populatePGInstanceConfigurationMap( diff --git a/internal/pgbackrest/config.md b/internal/pgbackrest/config.md index 498348eb90..2101535b3a 100644 --- a/internal/pgbackrest/config.md +++ b/internal/pgbackrest/config.md @@ -1,16 +1,7 @@ # pgBackRest Configuration Overview diff --git a/internal/pgbackrest/config_test.go b/internal/pgbackrest/config_test.go index a518e95299..b74bf9a4a8 100644 --- a/internal/pgbackrest/config_test.go +++ b/internal/pgbackrest/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -376,6 +365,36 @@ func TestRestoreCommandTDE(t *testing.T) { assert.Assert(t, strings.Contains(string(b), "encryption_key_command = 'echo testValue'"), "expected encryption_key_command setting, got:\n%s", b) } + +func TestDedicatedSnapshotVolumeRestoreCommand(t *testing.T) { + shellcheck := require.ShellCheck(t) + + pgdata := "/pgdata/pg13" + opts := []string{ + "--stanza=" + DefaultStanzaName, "--pg1-path=" + pgdata, + "--repo=1"} + command := DedicatedSnapshotVolumeRestoreCommand(pgdata, strings.Join(opts, " ")) + + assert.DeepEqual(t, command[:3], []string{"bash", "-ceu", "--"}) + assert.Assert(t, len(command) > 3) + + dir := t.TempDir() + file := filepath.Join(dir, "script.bash") + assert.NilError(t, os.WriteFile(file, []byte(command[3]), 0o600)) + + cmd := exec.Command(shellcheck, "--enable=all", file) + output, err := cmd.CombinedOutput() + assert.NilError(t, err, "%q\n%s", cmd.Args, output) +} + +func TestDedicatedSnapshotVolumeRestoreCommandPrettyYAML(t *testing.T) { + b, err := yaml.Marshal(DedicatedSnapshotVolumeRestoreCommand("/dir", "--options")) + + assert.NilError(t, err) + assert.Assert(t, strings.Contains(string(b), "\n- |"), + "expected literal block scalar, got:\n%s", b) +} + func TestServerConfig(t *testing.T) { cluster := &v1beta1.PostgresCluster{} cluster.UID = "shoe" diff --git a/internal/pgbackrest/iana.go b/internal/pgbackrest/iana.go index 9d36385ed6..c6e2f71e6c 100644 --- a/internal/pgbackrest/iana.go +++ b/internal/pgbackrest/iana.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/options.go b/internal/pgbackrest/options.go index 54cb7dac37..2439901e47 100644 --- a/internal/pgbackrest/options.go +++ b/internal/pgbackrest/options.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/options_test.go b/internal/pgbackrest/options_test.go index f31853781c..374737ec7f 100644 --- a/internal/pgbackrest/options_test.go +++ b/internal/pgbackrest/options_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/pgbackrest.go b/internal/pgbackrest/pgbackrest.go index 759b103bd0..21124b9744 100644 --- a/internal/pgbackrest/pgbackrest.go +++ b/internal/pgbackrest/pgbackrest.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -20,7 +9,6 @@ import ( "context" "fmt" "io" - "strings" "github.com/pkg/errors" @@ -35,10 +23,6 @@ const ( // errMsgStaleReposWithVolumesConfig is the error message displayed when a volume-backed repo has been // configured, but the configuration has not yet propagated into the container. errMsgStaleReposWithVolumesConfig = "postgres operator error: pgBackRest stale volume-backed repo configuration" - - // errMsgBackupDbMismatch is the error message returned from pgBackRest when PG versions - // or PG system identifiers do not match between the PG instance and the existing stanza - errMsgBackupDbMismatch = "backup and archive info files exist but do not match the database" ) // Executor calls "pgbackrest" commands @@ -57,15 +41,10 @@ type Executor func( // from running (with a config mismatch indicating that the pgBackRest configuration as stored in // the cluster's pgBackRest ConfigMap has not yet propagated to the Pod). func (exec Executor) StanzaCreateOrUpgrade(ctx context.Context, configHash string, - upgrade bool, postgresCluster *v1beta1.PostgresCluster) (bool, error) { + postgresCluster *v1beta1.PostgresCluster) (bool, error) { var stdout, stderr bytes.Buffer - stanzaCmd := "create" - if upgrade { - stanzaCmd = "upgrade" - } - var reposWithVolumes []v1beta1.PGBackRestRepo for _, repo := range postgresCluster.Spec.Backups.PGBackRest.Repos { if repo.Volume != nil { @@ -94,18 +73,18 @@ func (exec Executor) StanzaCreateOrUpgrade(ctx context.Context, configHash strin // Otherwise, it runs the pgbackrest command, which will either be "stanza-create" or // "stanza-upgrade", depending on the value of the boolean "upgrade" parameter. const script = ` -declare -r hash="$1" stanza="$2" hash_msg="$3" vol_msg="$4" cmd="$5" check_repo_cmd="$6" +declare -r hash="$1" stanza="$2" hash_msg="$3" vol_msg="$4" check_repo_cmd="$5" if [[ "$(< /etc/pgbackrest/conf.d/config-hash)" != "${hash}" ]]; then printf >&2 "%s" "${hash_msg}"; exit 1; elif ! bash -c "${check_repo_cmd}"; then printf >&2 "%s" "${vol_msg}"; exit 1; else - pgbackrest "${cmd}" --stanza="${stanza}" + pgbackrest stanza-create --stanza="${stanza}" || pgbackrest stanza-upgrade --stanza="${stanza}" fi ` if err := exec(ctx, nil, &stdout, &stderr, "bash", "-ceu", "--", script, "-", configHash, DefaultStanzaName, errMsgConfigHashMismatch, errMsgStaleReposWithVolumesConfig, - fmt.Sprintf("stanza-%s", stanzaCmd), checkRepoCmd); err != nil { + checkRepoCmd); err != nil { errReturn := stderr.String() @@ -122,12 +101,6 @@ fi return true, nil } - // if the err returned from pgbackrest command is about a version mismatch - // then we should run upgrade rather than create - if strings.Contains(errReturn, errMsgBackupDbMismatch) { - return exec.StanzaCreateOrUpgrade(ctx, configHash, true, postgresCluster) - } - // if none of the above errors, return the err return false, errors.WithStack(fmt.Errorf("%w: %v", err, errReturn)) } diff --git a/internal/pgbackrest/pgbackrest_test.go b/internal/pgbackrest/pgbackrest_test.go index 670a829451..33c97913cf 100644 --- a/internal/pgbackrest/pgbackrest_test.go +++ b/internal/pgbackrest/pgbackrest_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -39,18 +28,17 @@ func TestStanzaCreateOrUpgrade(t *testing.T) { ctx := context.Background() configHash := "7f5d4d5bdc" expectedCommand := []string{"bash", "-ceu", "--", ` -declare -r hash="$1" stanza="$2" hash_msg="$3" vol_msg="$4" cmd="$5" check_repo_cmd="$6" +declare -r hash="$1" stanza="$2" hash_msg="$3" vol_msg="$4" check_repo_cmd="$5" if [[ "$(< /etc/pgbackrest/conf.d/config-hash)" != "${hash}" ]]; then printf >&2 "%s" "${hash_msg}"; exit 1; elif ! bash -c "${check_repo_cmd}"; then printf >&2 "%s" "${vol_msg}"; exit 1; else - pgbackrest "${cmd}" --stanza="${stanza}" + pgbackrest stanza-create --stanza="${stanza}" || pgbackrest stanza-upgrade --stanza="${stanza}" fi `, "-", "7f5d4d5bdc", "db", "postgres operator error: pgBackRest config hash mismatch", "postgres operator error: pgBackRest stale volume-backed repo configuration", - "stanza-create", "grep repo1-path /etc/pgbackrest/conf.d/pgbackrest_instance.conf", } @@ -95,7 +83,7 @@ fi }, } - configHashMismatch, err := Executor(stanzaExec).StanzaCreateOrUpgrade(ctx, configHash, false, postgresCluster) + configHashMismatch, err := Executor(stanzaExec).StanzaCreateOrUpgrade(ctx, configHash, postgresCluster) assert.NilError(t, err) assert.Assert(t, !configHashMismatch) diff --git a/internal/pgbackrest/postgres.go b/internal/pgbackrest/postgres.go index 566630657b..ab5c71868c 100644 --- a/internal/pgbackrest/postgres.go +++ b/internal/pgbackrest/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/postgres_test.go b/internal/pgbackrest/postgres_test.go index 559388e926..b87b35631a 100644 --- a/internal/pgbackrest/postgres_test.go +++ b/internal/pgbackrest/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/rbac.go b/internal/pgbackrest/rbac.go index 5fe4cc4b96..950f10ef8b 100644 --- a/internal/pgbackrest/rbac.go +++ b/internal/pgbackrest/rbac.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -22,8 +11,8 @@ import ( "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) -// +kubebuilder:rbac:namespace=pgbackrest,groups="",resources="pods",verbs={list} -// +kubebuilder:rbac:namespace=pgbackrest,groups="",resources="pods/exec",verbs={create} +// +kubebuilder:rbac:groups="",resources="pods",verbs={list} +// +kubebuilder:rbac:groups="",resources="pods/exec",verbs={create} // Permissions returns the RBAC rules pgBackRest needs for a cluster. func Permissions(cluster *v1beta1.PostgresCluster) []rbacv1.PolicyRule { diff --git a/internal/pgbackrest/rbac_test.go b/internal/pgbackrest/rbac_test.go index 6b213df664..a620276f64 100644 --- a/internal/pgbackrest/rbac_test.go +++ b/internal/pgbackrest/rbac_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/reconcile.go b/internal/pgbackrest/reconcile.go index 6b2fea43b5..d22bccc3c0 100644 --- a/internal/pgbackrest/reconcile.go +++ b/internal/pgbackrest/reconcile.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest @@ -417,7 +406,7 @@ func InstanceCertificates(ctx context.Context, ) error { var err error - initialize.ByteMap(&outInstanceCertificates.Data) + initialize.Map(&outInstanceCertificates.Data) if err == nil { outInstanceCertificates.Data[certInstanceSecretKey], err = certFile(inDNS) @@ -484,7 +473,7 @@ func RestoreConfig( sourceConfigMap, targetConfigMap *corev1.ConfigMap, sourceSecret, targetSecret *corev1.Secret, ) { - initialize.StringMap(&targetConfigMap.Data) + initialize.Map(&targetConfigMap.Data) // Use the repository definitions from the source cluster. // @@ -496,7 +485,7 @@ func RestoreConfig( targetConfigMap.Data[CMInstanceKey] = sourceConfigMap.Data[CMInstanceKey] if sourceSecret != nil && targetSecret != nil { - initialize.ByteMap(&targetSecret.Data) + initialize.Map(&targetSecret.Data) // - https://golang.org/issue/45038 bytesClone := func(b []byte) []byte { return append([]byte(nil), b...) } @@ -520,7 +509,7 @@ func Secret(ctx context.Context, // Save the CA and generate a TLS client certificate for the entire cluster. if inRepoHost != nil { - initialize.ByteMap(&outSecret.Data) + initialize.Map(&outSecret.Data) // The server verifies its "tls-server-auth" option contains the common // name (CN) of the certificate presented by a client. The entire diff --git a/internal/pgbackrest/reconcile_test.go b/internal/pgbackrest/reconcile_test.go index ac5ea6ea83..4957d58f7b 100644 --- a/internal/pgbackrest/reconcile_test.go +++ b/internal/pgbackrest/reconcile_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/restore.md b/internal/pgbackrest/restore.md index dc1b500811..8828576921 100644 --- a/internal/pgbackrest/restore.md +++ b/internal/pgbackrest/restore.md @@ -1,16 +1,7 @@ ## Target Action diff --git a/internal/pgbackrest/tls-server.md b/internal/pgbackrest/tls-server.md index 2020eb40cd..b572cc1ea4 100644 --- a/internal/pgbackrest/tls-server.md +++ b/internal/pgbackrest/tls-server.md @@ -1,16 +1,7 @@ # pgBackRest TLS Server diff --git a/internal/pgbackrest/util.go b/internal/pgbackrest/util.go index 392949c32b..4fc2266c56 100644 --- a/internal/pgbackrest/util.go +++ b/internal/pgbackrest/util.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbackrest/util_test.go b/internal/pgbackrest/util_test.go index ca32af55f3..eb0f4dec29 100644 --- a/internal/pgbackrest/util_test.go +++ b/internal/pgbackrest/util_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbackrest diff --git a/internal/pgbouncer/certificates.go b/internal/pgbouncer/certificates.go index 4fb0c4926e..31f91c503a 100644 --- a/internal/pgbouncer/certificates.go +++ b/internal/pgbouncer/certificates.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/certificates_test.go b/internal/pgbouncer/certificates_test.go index 20607ecd6a..5955c3de9c 100644 --- a/internal/pgbouncer/certificates_test.go +++ b/internal/pgbouncer/certificates_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/config.go b/internal/pgbouncer/config.go index 494a269928..a203144817 100644 --- a/internal/pgbouncer/config.go +++ b/internal/pgbouncer/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/config.md b/internal/pgbouncer/config.md index 8c6ee87012..abfec12518 100644 --- a/internal/pgbouncer/config.md +++ b/internal/pgbouncer/config.md @@ -1,16 +1,7 @@ PgBouncer is configured through INI files. It will reload these files when diff --git a/internal/pgbouncer/config_test.go b/internal/pgbouncer/config_test.go index a86e311a05..7a96da571c 100644 --- a/internal/pgbouncer/config_test.go +++ b/internal/pgbouncer/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/postgres.go b/internal/pgbouncer/postgres.go index 9fbf00f98b..cbc2e29916 100644 --- a/internal/pgbouncer/postgres.go +++ b/internal/pgbouncer/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/postgres_test.go b/internal/pgbouncer/postgres_test.go index f90c60df71..f2ce419753 100644 --- a/internal/pgbouncer/postgres_test.go +++ b/internal/pgbouncer/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgbouncer/reconcile.go b/internal/pgbouncer/reconcile.go index 572c4525ab..999d6524a5 100644 --- a/internal/pgbouncer/reconcile.go +++ b/internal/pgbouncer/reconcile.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer @@ -41,7 +30,7 @@ func ConfigMap( return } - initialize.StringMap(&outConfigMap.Data) + initialize.Map(&outConfigMap.Data) outConfigMap.Data[emptyConfigMapKey] = "" outConfigMap.Data[iniFileConfigMapKey] = clusterINI(inCluster) @@ -61,7 +50,7 @@ func Secret(ctx context.Context, } var err error - initialize.ByteMap(&outSecret.Data) + initialize.Map(&outSecret.Data) // Use the existing password and verifier. Generate both when either is missing. // NOTE(cbandy): We don't have a function to compare a plaintext password diff --git a/internal/pgbouncer/reconcile_test.go b/internal/pgbouncer/reconcile_test.go index 55c2635809..a53de8cf64 100644 --- a/internal/pgbouncer/reconcile_test.go +++ b/internal/pgbouncer/reconcile_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgbouncer diff --git a/internal/pgmonitor/exporter.go b/internal/pgmonitor/exporter.go index f2a831220e..9d7a1fc3c6 100644 --- a/internal/pgmonitor/exporter.go +++ b/internal/pgmonitor/exporter.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor @@ -43,7 +32,8 @@ const ( // postgres_exporter command flags var ( - ExporterWebConfigFileFlag = "--web.config.file=/web-config/web-config.yml" + ExporterWebConfigFileFlag = "--web.config.file=/web-config/web-config.yml" + ExporterDeactivateStatBGWriterFlag = "--no-collector.stat_bgwriter" ) // Defaults for certain values used in queries.yml diff --git a/internal/pgmonitor/exporter_test.go b/internal/pgmonitor/exporter_test.go index f65272ca87..5ba14e0993 100644 --- a/internal/pgmonitor/exporter_test.go +++ b/internal/pgmonitor/exporter_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor diff --git a/internal/pgmonitor/postgres.go b/internal/pgmonitor/postgres.go index d433fc08e0..8aed164a18 100644 --- a/internal/pgmonitor/postgres.go +++ b/internal/pgmonitor/postgres.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor diff --git a/internal/pgmonitor/postgres_test.go b/internal/pgmonitor/postgres_test.go index d4caaefd68..655fa936ae 100644 --- a/internal/pgmonitor/postgres_test.go +++ b/internal/pgmonitor/postgres_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor diff --git a/internal/pgmonitor/util.go b/internal/pgmonitor/util.go index 410594eea4..f5606ccd08 100644 --- a/internal/pgmonitor/util.go +++ b/internal/pgmonitor/util.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor diff --git a/internal/pgmonitor/util_test.go b/internal/pgmonitor/util_test.go index 55c6bd0fcf..8d16d74bae 100644 --- a/internal/pgmonitor/util_test.go +++ b/internal/pgmonitor/util_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pgmonitor diff --git a/internal/pki/common.go b/internal/pki/common.go index 13c573cd2b..fbe9421f8b 100644 --- a/internal/pki/common.go +++ b/internal/pki/common.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pki diff --git a/internal/pki/doc.go b/internal/pki/doc.go index bfbe34e3c1..71f8c0a1bc 100644 --- a/internal/pki/doc.go +++ b/internal/pki/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package pki provides types and functions to support the public key // infrastructure of the Postgres Operator. It enforces a two layer system diff --git a/internal/pki/encoding.go b/internal/pki/encoding.go index b7ebe4eed1..2d2cd851e3 100644 --- a/internal/pki/encoding.go +++ b/internal/pki/encoding.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pki diff --git a/internal/pki/encoding_test.go b/internal/pki/encoding_test.go index dc116a2947..cdf7c0de5a 100644 --- a/internal/pki/encoding_test.go +++ b/internal/pki/encoding_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pki diff --git a/internal/pki/pki.go b/internal/pki/pki.go index 9f923bb9f7..7048810654 100644 --- a/internal/pki/pki.go +++ b/internal/pki/pki.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pki diff --git a/internal/pki/pki_test.go b/internal/pki/pki_test.go index 1905c417ae..cd13896450 100644 --- a/internal/pki/pki_test.go +++ b/internal/pki/pki_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package pki diff --git a/internal/postgis/postgis.go b/internal/postgis/postgis.go index aaf88f6a8e..f54da0dd93 100644 --- a/internal/postgis/postgis.go +++ b/internal/postgis/postgis.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgis diff --git a/internal/postgis/postgis_test.go b/internal/postgis/postgis_test.go index 97cd338daa..5f604abc90 100644 --- a/internal/postgis/postgis_test.go +++ b/internal/postgis/postgis_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgis diff --git a/internal/postgres/config.go b/internal/postgres/config.go index 224fb48668..ce1acde3fb 100644 --- a/internal/postgres/config.go +++ b/internal/postgres/config.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/config_test.go b/internal/postgres/config_test.go index 147311c117..cd4c92d185 100644 --- a/internal/postgres/config_test.go +++ b/internal/postgres/config_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/databases.go b/internal/postgres/databases.go index 8c46b3e19f..0d70170527 100644 --- a/internal/postgres/databases.go +++ b/internal/postgres/databases.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/databases_test.go b/internal/postgres/databases_test.go index f6f276ab0b..e025e86788 100644 --- a/internal/postgres/databases_test.go +++ b/internal/postgres/databases_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/doc.go b/internal/postgres/doc.go index e84fce010a..bd616b5916 100644 --- a/internal/postgres/doc.go +++ b/internal/postgres/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package postgres is a collection of resources that interact with PostgreSQL // or provide functionality that makes it easier for other resources to interact diff --git a/internal/postgres/exec.go b/internal/postgres/exec.go index 326588bdff..a846a8aa57 100644 --- a/internal/postgres/exec.go +++ b/internal/postgres/exec.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/exec_test.go b/internal/postgres/exec_test.go index c2f56e7fd0..df9b862577 100644 --- a/internal/postgres/exec_test.go +++ b/internal/postgres/exec_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/hba.go b/internal/postgres/hba.go index fd358ea96b..d9b5ce2680 100644 --- a/internal/postgres/hba.go +++ b/internal/postgres/hba.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/hba_test.go b/internal/postgres/hba_test.go index 5f7a5c0075..9744479fdd 100644 --- a/internal/postgres/hba_test.go +++ b/internal/postgres/hba_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/huge_pages.go b/internal/postgres/huge_pages.go index 0e97e094d9..ee13c0d11b 100644 --- a/internal/postgres/huge_pages.go +++ b/internal/postgres/huge_pages.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/huge_pages_test.go b/internal/postgres/huge_pages_test.go index c21f96750e..58a6a6aa57 100644 --- a/internal/postgres/huge_pages_test.go +++ b/internal/postgres/huge_pages_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/iana.go b/internal/postgres/iana.go index e43cec1fd8..4392b549f1 100644 --- a/internal/postgres/iana.go +++ b/internal/postgres/iana.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/parameters.go b/internal/postgres/parameters.go index 35cc30aa9c..434d9fd1dd 100644 --- a/internal/postgres/parameters.go +++ b/internal/postgres/parameters.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/parameters_test.go b/internal/postgres/parameters_test.go index f87738ed77..c6228d7958 100644 --- a/internal/postgres/parameters_test.go +++ b/internal/postgres/parameters_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/password/doc.go b/internal/postgres/password/doc.go index 3abf99d988..eef7ed7db2 100644 --- a/internal/postgres/password/doc.go +++ b/internal/postgres/password/doc.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // package password lets one create the appropriate password hashes and // verifiers that are used for adding the information into PostgreSQL diff --git a/internal/postgres/password/md5.go b/internal/postgres/password/md5.go index 648d4edc24..884dfb655e 100644 --- a/internal/postgres/password/md5.go +++ b/internal/postgres/password/md5.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/password/md5_test.go b/internal/postgres/password/md5_test.go index 11ee6465a2..80cb7742d6 100644 --- a/internal/postgres/password/md5_test.go +++ b/internal/postgres/password/md5_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/password/password.go b/internal/postgres/password/password.go index 07ec826a9a..337282cc74 100644 --- a/internal/postgres/password/password.go +++ b/internal/postgres/password/password.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/password/password_test.go b/internal/postgres/password/password_test.go index 9688616b01..3401dec4ac 100644 --- a/internal/postgres/password/password_test.go +++ b/internal/postgres/password/password_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/password/scram.go b/internal/postgres/password/scram.go index 66f5cd8151..8264cd87a0 100644 --- a/internal/postgres/password/scram.go +++ b/internal/postgres/password/scram.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/password/scram_test.go b/internal/postgres/password/scram_test.go index 6f2ca2505f..0552e519b7 100644 --- a/internal/postgres/password/scram_test.go +++ b/internal/postgres/password/scram_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package password diff --git a/internal/postgres/reconcile.go b/internal/postgres/reconcile.go index 866217195b..344f91dd9f 100644 --- a/internal/postgres/reconcile.go +++ b/internal/postgres/reconcile.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/reconcile_test.go b/internal/postgres/reconcile_test.go index 1f05cab84a..138b5c7b3e 100644 --- a/internal/postgres/reconcile_test.go +++ b/internal/postgres/reconcile_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/users.go b/internal/postgres/users.go index aaa67e0655..be8785a4e5 100644 --- a/internal/postgres/users.go +++ b/internal/postgres/users.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/users_test.go b/internal/postgres/users_test.go index 61074a67be..141175c78e 100644 --- a/internal/postgres/users_test.go +++ b/internal/postgres/users_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package postgres diff --git a/internal/postgres/wal.md b/internal/postgres/wal.md index dc1e0c54a2..afb094c20e 100644 --- a/internal/postgres/wal.md +++ b/internal/postgres/wal.md @@ -1,16 +1,7 @@ PostgreSQL commits transactions by storing changes in its [write-ahead log][WAL]. diff --git a/internal/registration/interface.go b/internal/registration/interface.go index a7fa28ff5f..578a064e2b 100644 --- a/internal/registration/interface.go +++ b/internal/registration/interface.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package registration diff --git a/internal/registration/runner.go b/internal/registration/runner.go index e34412c07d..0d607e1e94 100644 --- a/internal/registration/runner.go +++ b/internal/registration/runner.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package registration @@ -86,8 +76,14 @@ func NewRunner(publicKey, tokenPath string, changed func()) (*Runner, error) { } // CheckToken loads and verifies the configured token, returning an error when -// the file exists but cannot be verified. -func (r *Runner) CheckToken() error { +// the file exists but cannot be verified, and +// returning the token if it can be verified. +// NOTE(upgradecheck): return the token/nil so that we can use the token +// in upgradecheck; currently a refresh of the token will cause a restart of the pod +// meaning that the token used in upgradecheck is always the current token. +// But if the restart behavior changes, we might drop the token return in main.go +// and change upgradecheck to retrieve the token itself +func (r *Runner) CheckToken() (*jwt.Token, error) { data, errFile := os.ReadFile(r.tokenPath) key := func(*jwt.Token) (any, error) { return r.publicKey, nil } @@ -96,7 +92,7 @@ func (r *Runner) CheckToken() error { r.token.Lock() defer r.token.Unlock() - _, errToken := jwt.ParseWithClaims(string(data), &r.token, key, + token, errToken := jwt.ParseWithClaims(string(data), &r.token, key, jwt.WithExpirationRequired(), jwt.WithValidMethods([]string{"RS256"}), ) @@ -112,11 +108,11 @@ func (r *Runner) CheckToken() error { switch { case !r.enabled || !r.token.Exists: - return nil + return nil, nil case errFile != nil: - return errFile + return nil, errFile default: - return errToken + return token, errToken } } @@ -178,7 +174,7 @@ func (r *Runner) Start(ctx context.Context) error { select { case <-ticks: _, before := r.state() - if err := r.CheckToken(); err != nil { + if _, err := r.CheckToken(); err != nil { log.Error(err, "Unable to validate token") } if _, after := r.state(); before != after && r.changed != nil { diff --git a/internal/registration/runner_test.go b/internal/registration/runner_test.go index 28ef26c502..8e75848986 100644 --- a/internal/registration/runner_test.go +++ b/internal/registration/runner_test.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package registration @@ -111,19 +101,22 @@ func TestRunnerCheckToken(t *testing.T) { t.Run("SafeToCallDisabled", func(t *testing.T) { r := Runner{enabled: false} - assert.NilError(t, r.CheckToken()) + _, err := r.CheckToken() + assert.NilError(t, err) }) t.Run("FileMissing", func(t *testing.T) { r := Runner{enabled: true, tokenPath: filepath.Join(dir, "nope")} - assert.NilError(t, r.CheckToken()) + _, err := r.CheckToken() + assert.NilError(t, err) }) t.Run("FileUnreadable", func(t *testing.T) { r := Runner{enabled: true, tokenPath: filepath.Join(dir, "nope")} assert.NilError(t, os.WriteFile(r.tokenPath, nil, 0o200)) // Writeable - assert.ErrorContains(t, r.CheckToken(), "permission") + _, err := r.CheckToken() + assert.ErrorContains(t, err, "permission") assert.Assert(t, r.token.ExpiresAt == nil) }) @@ -131,7 +124,8 @@ func TestRunnerCheckToken(t *testing.T) { r := Runner{enabled: true, tokenPath: filepath.Join(dir, "empty")} assert.NilError(t, os.WriteFile(r.tokenPath, nil, 0o400)) // Readable - assert.ErrorContains(t, r.CheckToken(), "malformed") + _, err := r.CheckToken() + assert.ErrorContains(t, err, "malformed") assert.Assert(t, r.token.ExpiresAt == nil) }) @@ -150,7 +144,8 @@ func TestRunnerCheckToken(t *testing.T) { assert.NilError(t, err) assert.NilError(t, os.WriteFile(r.tokenPath, []byte(data), 0o400)) // Readable - assert.Assert(t, r.CheckToken() != nil, "HMAC algorithm should be rejected") + _, err = r.CheckToken() + assert.Assert(t, err != nil, "HMAC algorithm should be rejected") assert.Assert(t, r.token.ExpiresAt == nil) }) @@ -165,7 +160,7 @@ func TestRunnerCheckToken(t *testing.T) { assert.NilError(t, err) assert.NilError(t, os.WriteFile(r.tokenPath, []byte(data), 0o400)) // Readable - err = r.CheckToken() + _, err = r.CheckToken() assert.ErrorContains(t, err, "exp claim is required") assert.Assert(t, r.token.ExpiresAt == nil) }) @@ -183,7 +178,7 @@ func TestRunnerCheckToken(t *testing.T) { assert.NilError(t, err) assert.NilError(t, os.WriteFile(r.tokenPath, []byte(data), 0o400)) // Readable - err = r.CheckToken() + _, err = r.CheckToken() assert.ErrorContains(t, err, "is expired") assert.Assert(t, r.token.ExpiresAt == nil) }) @@ -195,14 +190,20 @@ func TestRunnerCheckToken(t *testing.T) { tokenPath: filepath.Join(dir, "valid"), } + expiration := jwt.NewNumericDate(time.Now().Add(time.Hour)) data, err := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ - "exp": jwt.NewNumericDate(time.Now().Add(time.Hour)), + "exp": expiration, }).SignedString(key) assert.NilError(t, err) assert.NilError(t, os.WriteFile(r.tokenPath, []byte(data), 0o400)) // Readable - assert.NilError(t, r.CheckToken()) + token, err := r.CheckToken() + assert.NilError(t, err) assert.Assert(t, r.token.ExpiresAt != nil) + assert.Assert(t, token.Valid) + exp, err := token.Claims.GetExpirationTime() + assert.NilError(t, err) + assert.Equal(t, exp.Time, expiration.Time) }) } @@ -557,7 +558,8 @@ func TestRunnerStart(t *testing.T) { // Begin with an invalid token. assert.NilError(t, os.WriteFile(runner.tokenPath, nil, 0o600)) - assert.Assert(t, runner.CheckToken() != nil) + _, err = runner.CheckToken() + assert.Assert(t, err != nil) // Replace it with a valid token. assert.NilError(t, os.WriteFile(runner.tokenPath, []byte(token), 0o600)) diff --git a/internal/registration/testing.go b/internal/registration/testing.go index fb9e9e4f4b..1418f6d2d3 100644 --- a/internal/registration/testing.go +++ b/internal/registration/testing.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package registration diff --git a/internal/testing/cmp/cmp.go b/internal/testing/cmp/cmp.go index 58e0a1e4de..265a598064 100644 --- a/internal/testing/cmp/cmp.go +++ b/internal/testing/cmp/cmp.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package cmp diff --git a/internal/testing/events/recorder.go b/internal/testing/events/recorder.go index 273a506521..23c03a4c40 100644 --- a/internal/testing/events/recorder.go +++ b/internal/testing/events/recorder.go @@ -1,17 +1,6 @@ -/* - Copyright 2022 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2022 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package events diff --git a/internal/testing/require/exec.go b/internal/testing/require/exec.go index 983bd49711..c182e84996 100644 --- a/internal/testing/require/exec.go +++ b/internal/testing/require/exec.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package require diff --git a/internal/testing/require/kubernetes.go b/internal/testing/require/kubernetes.go index 0139b0fc45..df21bca058 100644 --- a/internal/testing/require/kubernetes.go +++ b/internal/testing/require/kubernetes.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package require diff --git a/internal/testing/require/parallel.go b/internal/testing/require/parallel.go index 72c8dbd932..4fbdf42284 100644 --- a/internal/testing/require/parallel.go +++ b/internal/testing/require/parallel.go @@ -1,17 +1,6 @@ -/* - Copyright 2022 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2022 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package require diff --git a/internal/testing/validation/postgrescluster_test.go b/internal/testing/validation/postgrescluster_test.go index f05906af3e..e71ff22b2e 100644 --- a/internal/testing/validation/postgrescluster_test.go +++ b/internal/testing/validation/postgrescluster_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package validation diff --git a/internal/upgradecheck/header.go b/internal/upgradecheck/header.go index 401d03f7a0..a1d56ef442 100644 --- a/internal/upgradecheck/header.go +++ b/internal/upgradecheck/header.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package upgradecheck @@ -19,6 +8,7 @@ import ( "context" "encoding/json" "net/http" + "os" googleuuid "github.com/google/uuid" corev1 "k8s.io/api/core/v1" @@ -28,6 +18,8 @@ import ( "k8s.io/client-go/rest" crclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/crunchydata/postgres-operator/internal/controller/postgrescluster" + "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/logging" "github.com/crunchydata/postgres-operator/internal/naming" "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" @@ -44,24 +36,36 @@ var ( // Extensible struct for client upgrade data type clientUpgradeData struct { - DeploymentID string `json:"deployment_id"` - KubernetesEnv string `json:"kubernetes_env"` - PGOClustersTotal int `json:"pgo_clusters_total"` - PGOVersion string `json:"pgo_version"` - IsOpenShift bool `json:"is_open_shift"` + BridgeClustersTotal int `json:"bridge_clusters_total"` + BuildSource string `json:"build_source"` + DeploymentID string `json:"deployment_id"` + FeatureGatesEnabled string `json:"feature_gates_enabled"` + IsOpenShift bool `json:"is_open_shift"` + KubernetesEnv string `json:"kubernetes_env"` + PGOClustersTotal int `json:"pgo_clusters_total"` + PGOInstaller string `json:"pgo_installer"` + PGOInstallerOrigin string `json:"pgo_installer_origin"` + PGOVersion string `json:"pgo_version"` + RegistrationToken string `json:"registration_token"` } // generateHeader aggregates data and returns a struct of that data // If any errors are encountered, it logs those errors and uses the default values func generateHeader(ctx context.Context, cfg *rest.Config, crClient crclient.Client, - pgoVersion string, isOpenShift bool) *clientUpgradeData { + pgoVersion string, isOpenShift bool, registrationToken string) *clientUpgradeData { return &clientUpgradeData{ - PGOVersion: pgoVersion, - IsOpenShift: isOpenShift, - DeploymentID: ensureDeploymentID(ctx, crClient), - PGOClustersTotal: getManagedClusters(ctx, crClient), - KubernetesEnv: getServerVersion(ctx, cfg), + BridgeClustersTotal: getBridgeClusters(ctx, crClient), + BuildSource: os.Getenv("BUILD_SOURCE"), + DeploymentID: ensureDeploymentID(ctx, crClient), + FeatureGatesEnabled: feature.ShowGates(ctx), + IsOpenShift: isOpenShift, + KubernetesEnv: getServerVersion(ctx, cfg), + PGOClustersTotal: getManagedClusters(ctx, crClient), + PGOInstaller: os.Getenv("PGO_INSTALLER"), + PGOInstallerOrigin: os.Getenv("PGO_INSTALLER_ORIGIN"), + PGOVersion: pgoVersion, + RegistrationToken: registrationToken, } } @@ -125,7 +129,7 @@ func manageUpgradeCheckConfigMap(ctx context.Context, crClient crclient.Client, } } - err = applyConfigMap(ctx, crClient, cm, currentID) + err = applyConfigMap(ctx, crClient, cm, postgrescluster.ControllerName) if err != nil { log.V(1).Info("upgrade check issue: could not apply configmap", "response", err.Error()) @@ -169,6 +173,22 @@ func getManagedClusters(ctx context.Context, crClient crclient.Client) int { return count } +// getBridgeClusters returns a count of Bridge clusters managed by this PGO instance +// Any errors encountered will be logged and the count result will be 0 +func getBridgeClusters(ctx context.Context, crClient crclient.Client) int { + var count int + clusters := &v1beta1.CrunchyBridgeClusterList{} + err := crClient.List(ctx, clusters) + if err != nil { + log := logging.FromContext(ctx) + log.V(1).Info("upgrade check issue: could not count bridge clusters", + "response", err.Error()) + } else { + count = len(clusters.Items) + } + return count +} + // getServerVersion returns the stringified server version (i.e., the same info `kubectl version` // returns for the server) // Any errors encountered will be logged and will return an empty string diff --git a/internal/upgradecheck/header_test.go b/internal/upgradecheck/header_test.go index f884af3cda..c144e7629b 100644 --- a/internal/upgradecheck/header_test.go +++ b/internal/upgradecheck/header_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package upgradecheck @@ -19,6 +8,7 @@ import ( "context" "encoding/json" "net/http" + "strings" "testing" "gotest.tools/v3/assert" @@ -31,6 +21,7 @@ import ( "k8s.io/client-go/rest" "github.com/crunchydata/postgres-operator/internal/controller/postgrescluster" + "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/naming" "github.com/crunchydata/postgres-operator/internal/testing/cmp" "github.com/crunchydata/postgres-operator/internal/testing/require" @@ -50,6 +41,10 @@ func TestGenerateHeader(t *testing.T) { reconciler := postgrescluster.Reconciler{Client: cc} + t.Setenv("PGO_INSTALLER", "test") + t.Setenv("PGO_INSTALLER_ORIGIN", "test-origin") + t.Setenv("BUILD_SOURCE", "developer") + t.Run("error ensuring ID", func(t *testing.T) { fakeClientWithOptionalError := &fakeClientWithError{ cc, "patch error", @@ -57,7 +52,7 @@ func TestGenerateHeader(t *testing.T) { ctx, calls := setupLogCapture(ctx) res := generateHeader(ctx, cfg, fakeClientWithOptionalError, - "1.2.3", reconciler.IsOpenShift) + "1.2.3", reconciler.IsOpenShift, "") assert.Equal(t, len(*calls), 1) assert.Assert(t, cmp.Contains((*calls)[0], `upgrade check issue: could not apply configmap`)) assert.Equal(t, res.IsOpenShift, reconciler.IsOpenShift) @@ -66,8 +61,15 @@ func TestGenerateHeader(t *testing.T) { err := cc.List(ctx, &pgoList) assert.NilError(t, err) assert.Equal(t, len(pgoList.Items), res.PGOClustersTotal) + bridgeList := v1beta1.CrunchyBridgeClusterList{} + err = cc.List(ctx, &bridgeList) + assert.NilError(t, err) + assert.Equal(t, len(bridgeList.Items), res.BridgeClustersTotal) assert.Equal(t, "1.2.3", res.PGOVersion) assert.Equal(t, server.String(), res.KubernetesEnv) + assert.Equal(t, "test", res.PGOInstaller) + assert.Equal(t, "test-origin", res.PGOInstallerOrigin) + assert.Equal(t, "developer", res.BuildSource) }) t.Run("error getting cluster count", func(t *testing.T) { @@ -77,14 +79,21 @@ func TestGenerateHeader(t *testing.T) { ctx, calls := setupLogCapture(ctx) res := generateHeader(ctx, cfg, fakeClientWithOptionalError, - "1.2.3", reconciler.IsOpenShift) - assert.Equal(t, len(*calls), 1) - assert.Assert(t, cmp.Contains((*calls)[0], `upgrade check issue: could not count postgres clusters`)) + "1.2.3", reconciler.IsOpenShift, "") + assert.Equal(t, len(*calls), 2) + // Aggregating the logs since we cannot determine which call will be first + callsAggregate := strings.Join(*calls, " ") + assert.Assert(t, cmp.Contains(callsAggregate, `upgrade check issue: could not count postgres clusters`)) + assert.Assert(t, cmp.Contains(callsAggregate, `upgrade check issue: could not count bridge clusters`)) assert.Equal(t, res.IsOpenShift, reconciler.IsOpenShift) assert.Equal(t, deploymentID, res.DeploymentID) assert.Equal(t, 0, res.PGOClustersTotal) + assert.Equal(t, 0, res.BridgeClustersTotal) assert.Equal(t, "1.2.3", res.PGOVersion) assert.Equal(t, server.String(), res.KubernetesEnv) + assert.Equal(t, "test", res.PGOInstaller) + assert.Equal(t, "test-origin", res.PGOInstallerOrigin) + assert.Equal(t, "developer", res.BuildSource) }) t.Run("error getting server version info", func(t *testing.T) { @@ -92,7 +101,7 @@ func TestGenerateHeader(t *testing.T) { badcfg := &rest.Config{} res := generateHeader(ctx, badcfg, cc, - "1.2.3", reconciler.IsOpenShift) + "1.2.3", reconciler.IsOpenShift, "") assert.Equal(t, len(*calls), 1) assert.Assert(t, cmp.Contains((*calls)[0], `upgrade check issue: could not retrieve server version`)) assert.Equal(t, res.IsOpenShift, reconciler.IsOpenShift) @@ -103,13 +112,21 @@ func TestGenerateHeader(t *testing.T) { assert.Equal(t, len(pgoList.Items), res.PGOClustersTotal) assert.Equal(t, "1.2.3", res.PGOVersion) assert.Equal(t, "", res.KubernetesEnv) + assert.Equal(t, "test", res.PGOInstaller) + assert.Equal(t, "test-origin", res.PGOInstallerOrigin) + assert.Equal(t, "developer", res.BuildSource) }) t.Run("success", func(t *testing.T) { ctx, calls := setupLogCapture(ctx) + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.TablespaceVolumes: true, + })) + ctx = feature.NewContext(ctx, gate) res := generateHeader(ctx, cfg, cc, - "1.2.3", reconciler.IsOpenShift) + "1.2.3", reconciler.IsOpenShift, "") assert.Equal(t, len(*calls), 0) assert.Equal(t, res.IsOpenShift, reconciler.IsOpenShift) assert.Equal(t, deploymentID, res.DeploymentID) @@ -119,6 +136,10 @@ func TestGenerateHeader(t *testing.T) { assert.Equal(t, len(pgoList.Items), res.PGOClustersTotal) assert.Equal(t, "1.2.3", res.PGOVersion) assert.Equal(t, server.String(), res.KubernetesEnv) + assert.Equal(t, "TablespaceVolumes=true", res.FeatureGatesEnabled) + assert.Equal(t, "test", res.PGOInstaller) + assert.Equal(t, "test-origin", res.PGOInstallerOrigin) + assert.Equal(t, "developer", res.BuildSource) }) } @@ -511,12 +532,35 @@ func TestGetManagedClusters(t *testing.T) { } ctx, calls := setupLogCapture(ctx) count := getManagedClusters(ctx, fakeClientWithOptionalError) - assert.Equal(t, len(*calls), 1) + assert.Assert(t, len(*calls) > 0) assert.Assert(t, cmp.Contains((*calls)[0], `upgrade check issue: could not count postgres clusters`)) assert.Assert(t, count == 0) }) } +func TestGetBridgeClusters(t *testing.T) { + ctx := context.Background() + + t.Run("success", func(t *testing.T) { + fakeClient := setupFakeClientWithPGOScheme(t, true) + ctx, calls := setupLogCapture(ctx) + count := getBridgeClusters(ctx, fakeClient) + assert.Equal(t, len(*calls), 0) + assert.Assert(t, count == 2) + }) + + t.Run("list throw error", func(t *testing.T) { + fakeClientWithOptionalError := &fakeClientWithError{ + setupFakeClientWithPGOScheme(t, true), "list error", + } + ctx, calls := setupLogCapture(ctx) + count := getBridgeClusters(ctx, fakeClientWithOptionalError) + assert.Assert(t, len(*calls) > 0) + assert.Assert(t, cmp.Contains((*calls)[0], `upgrade check issue: could not count bridge clusters`)) + assert.Assert(t, count == 0) + }) +} + func TestGetServerVersion(t *testing.T) { t.Run("success", func(t *testing.T) { expect, server := setupVersionServer(t, true) diff --git a/internal/upgradecheck/helpers_test.go b/internal/upgradecheck/helpers_test.go index c2a5b3a258..63184184db 100644 --- a/internal/upgradecheck/helpers_test.go +++ b/internal/upgradecheck/helpers_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package upgradecheck @@ -38,11 +27,13 @@ import ( "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) +// fakeClientWithError is a controller runtime client and an error type to force type fakeClientWithError struct { crclient.Client errorType string } +// Get returns the client.get OR an Error (`get error`) if the fakeClientWithError is set to error that way func (f *fakeClientWithError) Get(ctx context.Context, key types.NamespacedName, obj crclient.Object, opts ...crclient.GetOption) error { switch f.errorType { case "get error": @@ -52,6 +43,7 @@ func (f *fakeClientWithError) Get(ctx context.Context, key types.NamespacedName, } } +// Patch returns the client.get OR an Error (`patch error`) if the fakeClientWithError is set to error that way // TODO: PatchType is not supported currently by fake // - https://github.com/kubernetes/client-go/issues/970 // Once that gets fixed, we can test without envtest @@ -65,6 +57,7 @@ func (f *fakeClientWithError) Patch(ctx context.Context, obj crclient.Object, } } +// List returns the client.get OR an Error (`list error`) if the fakeClientWithError is set to error that way func (f *fakeClientWithError) List(ctx context.Context, objList crclient.ObjectList, opts ...crclient.ListOption) error { switch f.errorType { @@ -75,12 +68,16 @@ func (f *fakeClientWithError) List(ctx context.Context, objList crclient.ObjectL } } +// setupDeploymentID returns a UUID func setupDeploymentID(t *testing.T) string { t.Helper() deploymentID = string(uuid.NewUUID()) return deploymentID } +// setupFakeClientWithPGOScheme returns a fake client with the PGO scheme added; +// if `includeCluster` is true, also adds some empty PostgresCluster and CrunchyBridgeCluster +// items to the client func setupFakeClientWithPGOScheme(t *testing.T, includeCluster bool) crclient.Client { t.Helper() if includeCluster { @@ -98,11 +95,31 @@ func setupFakeClientWithPGOScheme(t *testing.T, includeCluster bool) crclient.Cl }, }, } - return fake.NewClientBuilder().WithScheme(runtime.Scheme).WithLists(pc).Build() + + bcl := &v1beta1.CrunchyBridgeClusterList{ + Items: []v1beta1.CrunchyBridgeCluster{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "hippo", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "elephant", + }, + }, + }, + } + + return fake.NewClientBuilder(). + WithScheme(runtime.Scheme). + WithLists(pc, bcl). + Build() } return fake.NewClientBuilder().WithScheme(runtime.Scheme).Build() } +// setupVersionServer sets up and tears down a server and version info for testing func setupVersionServer(t *testing.T, works bool) (version.Info, *httptest.Server) { t.Helper() expect := version.Info{ @@ -127,6 +144,7 @@ func setupVersionServer(t *testing.T, works bool) (version.Info, *httptest.Serve return expect, server } +// setupLogCapture captures the logs and keeps count of the logs captured func setupLogCapture(ctx context.Context) (context.Context, *[]string) { calls := []string{} testlog := funcr.NewJSON(func(object string) { diff --git a/internal/upgradecheck/http.go b/internal/upgradecheck/http.go index 6e05499490..71a3c465c0 100644 --- a/internal/upgradecheck/http.go +++ b/internal/upgradecheck/http.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package upgradecheck @@ -22,6 +11,7 @@ import ( "net/http" "time" + "github.com/golang-jwt/jwt/v5" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/rest" crclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -77,7 +67,7 @@ func init() { func checkForUpgrades(ctx context.Context, url, versionString string, backoff wait.Backoff, crclient crclient.Client, cfg *rest.Config, - isOpenShift bool) (message string, header string, err error) { + isOpenShift bool, registrationToken string) (message string, header string, err error) { var headerPayloadStruct *clientUpgradeData // Prep request @@ -86,7 +76,7 @@ func checkForUpgrades(ctx context.Context, url, versionString string, backoff wa // generateHeader always returns some sort of struct, using defaults/nil values // in case some of the checks return errors headerPayloadStruct = generateHeader(ctx, cfg, crclient, - versionString, isOpenShift) + versionString, isOpenShift, registrationToken) req, err = addHeader(req, headerPayloadStruct) } @@ -136,24 +126,37 @@ type CheckForUpgradesScheduler struct { Client crclient.Client Config *rest.Config - OpenShift bool - Refresh time.Duration - URL, Version string + OpenShift bool + Refresh time.Duration + RegistrationToken string + URL, Version string } // ManagedScheduler creates a [CheckForUpgradesScheduler] and adds it to m. -func ManagedScheduler(m manager.Manager, openshift bool, url, version string) error { +// NOTE(registration): This takes a token/nil parameter when the operator is started. +// Currently the operator restarts when the token is updated, +// so this token is always current; but if that restart behavior is changed, +// we will want the upgrade mechanism to instantiate its own registration runner +// or otherwise get the most recent token. +func ManagedScheduler(m manager.Manager, openshift bool, + url, version string, registrationToken *jwt.Token) error { if url == "" { url = upgradeCheckURL } + var token string + if registrationToken != nil { + token = registrationToken.Raw + } + return m.Add(&CheckForUpgradesScheduler{ - Client: m.GetClient(), - Config: m.GetConfig(), - OpenShift: openshift, - Refresh: 24 * time.Hour, - URL: url, - Version: version, + Client: m.GetClient(), + Config: m.GetConfig(), + OpenShift: openshift, + Refresh: 24 * time.Hour, + RegistrationToken: token, + URL: url, + Version: version, }) } @@ -188,7 +191,7 @@ func (s *CheckForUpgradesScheduler) check(ctx context.Context) { }() info, header, err := checkForUpgrades(ctx, - s.URL, s.Version, backoff, s.Client, s.Config, s.OpenShift) + s.URL, s.Version, backoff, s.Client, s.Config, s.OpenShift, s.RegistrationToken) if err != nil { log.V(1).Info("could not complete upgrade check", "response", err.Error()) diff --git a/internal/upgradecheck/http_test.go b/internal/upgradecheck/http_test.go index b2264f4b9b..9535f942ea 100644 --- a/internal/upgradecheck/http_test.go +++ b/internal/upgradecheck/http_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package upgradecheck @@ -32,6 +21,7 @@ import ( "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/manager" + "github.com/crunchydata/postgres-operator/internal/feature" "github.com/crunchydata/postgres-operator/internal/logging" "github.com/crunchydata/postgres-operator/internal/testing/cmp" ) @@ -58,10 +48,16 @@ func (m *MockClient) Do(req *http.Request) (*http.Response, error) { } func TestCheckForUpgrades(t *testing.T) { - fakeClient := setupFakeClientWithPGOScheme(t, false) - ctx := logging.NewContext(context.Background(), logging.Discard()) + fakeClient := setupFakeClientWithPGOScheme(t, true) cfg := &rest.Config{} + ctx := logging.NewContext(context.Background(), logging.Discard()) + gate := feature.NewGate() + assert.NilError(t, gate.SetFromMap(map[string]bool{ + feature.TablespaceVolumes: true, + })) + ctx = feature.NewContext(ctx, gate) + // Pass *testing.T to allows the correct messages from the assert package // in the event of certain failures. checkData := func(t *testing.T, header string) { @@ -70,6 +66,10 @@ func TestCheckForUpgrades(t *testing.T) { assert.NilError(t, err) assert.Assert(t, data.DeploymentID != "") assert.Equal(t, data.PGOVersion, "4.7.3") + assert.Equal(t, data.RegistrationToken, "speakFriend") + assert.Equal(t, data.BridgeClustersTotal, 2) + assert.Equal(t, data.PGOClustersTotal, 2) + assert.Equal(t, data.FeatureGatesEnabled, "TablespaceVolumes=true") } t.Run("success", func(t *testing.T) { @@ -83,7 +83,7 @@ func TestCheckForUpgrades(t *testing.T) { } res, header, err := checkForUpgrades(ctx, "", "4.7.3", backoff, - fakeClient, cfg, false) + fakeClient, cfg, false, "speakFriend") assert.NilError(t, err) assert.Equal(t, res, `{"pgo_versions":[{"tag":"v5.0.4"},{"tag":"v5.0.3"},{"tag":"v5.0.2"},{"tag":"v5.0.1"},{"tag":"v5.0.0"}]}`) checkData(t, header) @@ -98,7 +98,7 @@ func TestCheckForUpgrades(t *testing.T) { } res, header, err := checkForUpgrades(ctx, "", "4.7.3", backoff, - fakeClient, cfg, false) + fakeClient, cfg, false, "speakFriend") // Two failed calls because of env var assert.Equal(t, counter, 2) assert.Equal(t, res, "") @@ -118,7 +118,7 @@ func TestCheckForUpgrades(t *testing.T) { } res, header, err := checkForUpgrades(ctx, "", "4.7.3", backoff, - fakeClient, cfg, false) + fakeClient, cfg, false, "speakFriend") assert.Equal(t, res, "") // Two failed calls because of env var assert.Equal(t, counter, 2) @@ -147,7 +147,7 @@ func TestCheckForUpgrades(t *testing.T) { } res, header, err := checkForUpgrades(ctx, "", "4.7.3", backoff, - fakeClient, cfg, false) + fakeClient, cfg, false, "speakFriend") assert.Equal(t, counter, 2) assert.NilError(t, err) assert.Equal(t, res, `{"pgo_versions":[{"tag":"v5.0.4"},{"tag":"v5.0.3"},{"tag":"v5.0.2"},{"tag":"v5.0.1"},{"tag":"v5.0.0"}]}`) diff --git a/internal/util/secrets.go b/internal/util/secrets.go index 203f6bcfea..82768c9386 100644 --- a/internal/util/secrets.go +++ b/internal/util/secrets.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package util diff --git a/internal/util/secrets_test.go b/internal/util/secrets_test.go index 39538d7368..5d549ca89e 100644 --- a/internal/util/secrets_test.go +++ b/internal/util/secrets_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package util diff --git a/internal/util/util.go b/internal/util/util.go index 2199b584fd..72634ebbc6 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,17 +1,6 @@ -/* - Copyright 2017 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2017 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package util diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/crunchy_bridgecluster_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/crunchy_bridgecluster_types.go index c72ca07471..0b94a4dae1 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/crunchy_bridgecluster_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/crunchy_bridgecluster_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 @@ -34,7 +23,7 @@ type CrunchyBridgeClusterSpec struct { // Whether the cluster is protected. Protected clusters can't be destroyed until // their protected flag is removed - // +optional + // +kubebuilder:validation:Optional IsProtected bool `json:"isProtected,omitempty"` // The name of the cluster @@ -53,10 +42,10 @@ type CrunchyBridgeClusterSpec struct { Plan string `json:"plan"` // The ID of the cluster's major Postgres version. - // Currently Bridge offers 13-16 + // Currently Bridge offers 13-17 // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=13 - // +kubebuilder:validation:Maximum=16 + // +kubebuilder:validation:Maximum=17 // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1 PostgresVersion int `json:"majorVersion"` @@ -76,14 +65,14 @@ type CrunchyBridgeClusterSpec struct { // are retrieved from the Bridge API. An empty list creates no role secrets. // Removing a role from this list does NOT drop the role nor revoke their // access, but it will delete that role's secret from the kube cluster. + // +kubebuilder:validation:Optional // +listType=map // +listMapKey=name - // +optional Roles []*CrunchyBridgeClusterRoleSpec `json:"roles,omitempty"` // The name of the secret containing the API key and team id // +kubebuilder:validation:Required - Secret string `json:"secret,omitempty"` + Secret string `json:"secret"` // The amount of storage available to the cluster in gigabytes. // The amount must be an integer, followed by Gi (gibibytes) or G (gigabytes) to match Kubernetes conventions. @@ -97,9 +86,11 @@ type CrunchyBridgeClusterSpec struct { type CrunchyBridgeClusterRoleSpec struct { // Name of the role within Crunchy Bridge. // More info: https://docs.crunchybridge.com/concepts/users + // +kubebuilder:validation:Required Name string `json:"name"` // The name of the Secret that will hold the role credentials. + // +kubebuilder:validation:Required // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` // +kubebuilder:validation:MaxLength=253 // +kubebuilder:validation:Type=string diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/groupversion_info.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/groupversion_info.go index 0c8e247bbd..15773a1815 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/groupversion_info.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/groupversion_info.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Package v1beta1 contains API Schema definitions for the postgres-operator v1beta1 API group // +kubebuilder:object:generate=true diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/patroni_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/patroni_types.go index 111c4fb805..2f01399372 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/patroni_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/patroni_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgadmin_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgadmin_types.go index 6f83b713c9..06c7321bc4 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgadmin_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgadmin_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go index 9aef438408..3e3098a602 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 @@ -60,15 +49,15 @@ type PGBackRestJobStatus struct { type PGBackRestScheduledBackupStatus struct { // The name of the associated pgBackRest scheduled backup CronJob - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional CronJobName string `json:"cronJobName,omitempty"` // The name of the associated pgBackRest repository - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional RepoName string `json:"repo,omitempty"` // The pgBackRest backup type for this Job - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional Type string `json:"type,omitempty"` // Represents the time the manual backup Job was acknowledged by the Job controller. @@ -353,7 +342,20 @@ type RepoHostStatus struct { type RepoPVC struct { // Defines a PersistentVolumeClaim spec used to create and/or bind a volume + // --- // +kubebuilder:validation:Required + // + // NOTE(validation): Every PVC must have at least one accessMode. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.accessModes`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2098-L2100 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2292-L2294 + // +kubebuilder:validation:XValidation:rule=`has(self.accessModes) && size(self.accessModes) > 0`,message=`missing accessModes` + // + // NOTE(validation): Every PVC must have a positive storage request. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.resources.requests.storage`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2126-L2133 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2318-L2325 + // +kubebuilder:validation:XValidation:rule=`has(self.resources) && has(self.resources.requests) && has(self.resources.requests.storage)`,message=`missing storage request` VolumeClaimSpec corev1.PersistentVolumeClaimSpec `json:"volumeClaimSpec"` } diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go index 38a4eebd2d..e940a9300d 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgmonitor_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgmonitor_types.go index 000ea72ba0..f2cd78335a 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgmonitor_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgmonitor_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgupgrade_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgupgrade_types.go index 1b221abe5f..8e99f8239f 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgupgrade_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgupgrade_types.go @@ -1,16 +1,6 @@ // Copyright 2021 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package v1beta1 @@ -58,8 +48,8 @@ type PGUpgradeSpec struct { // The major version of PostgreSQL before the upgrade. // +kubebuilder:validation:Required - // +kubebuilder:validation:Minimum=10 - // +kubebuilder:validation:Maximum=16 + // +kubebuilder:validation:Minimum=11 + // +kubebuilder:validation:Maximum=17 FromPostgresVersion int `json:"fromPostgresVersion"` // TODO(benjaminjb): define webhook validation to make sure @@ -69,8 +59,8 @@ type PGUpgradeSpec struct { // The major version of PostgreSQL to be upgraded to. // +kubebuilder:validation:Required - // +kubebuilder:validation:Minimum=10 - // +kubebuilder:validation:Maximum=16 + // +kubebuilder:validation:Minimum=11 + // +kubebuilder:validation:Maximum=17 ToPostgresVersion int `json:"toPostgresVersion"` // The image name to use for PostgreSQL containers after upgrade. diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgres_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgres_types.go index ff792ea986..b7baa72942 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgres_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgres_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_test.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_test.go index bfb8892ed4..83396902d0 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_test.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go index 0e50f3f0f7..54e42baa3b 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 @@ -122,8 +111,8 @@ type PostgresClusterSpec struct { // The major version of PostgreSQL installed in the PostgreSQL image // +kubebuilder:validation:Required - // +kubebuilder:validation:Minimum=10 - // +kubebuilder:validation:Maximum=16 + // +kubebuilder:validation:Minimum=11 + // +kubebuilder:validation:Maximum=17 // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1 PostgresVersion int `json:"postgresVersion"` @@ -166,7 +155,17 @@ type PostgresClusterSpec struct { // A list of group IDs applied to the process of a container. These can be // useful when accessing shared file systems with constrained permissions. // More info: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context - // +optional + // --- + // +kubebuilder:validation:Optional + // + // Containers should not run with a root GID. + // - https://kubernetes.io/docs/concepts/security/pod-security-standards/ + // +kubebuilder:validation:items:Minimum=1 + // + // Supplementary GIDs must fit within int32. + // - https://releases.k8s.io/v1.18.0/pkg/apis/core/validation/validation.go#L3659-L3663 + // - https://releases.k8s.io/v1.22.0/pkg/apis/core/validation/validation.go#L3923-L3927 + // +kubebuilder:validation:items:Maximum=2147483647 SupplementalGroups []int64 `json:"supplementalGroups,omitempty"` // Users to create inside PostgreSQL and the databases they should access. @@ -451,7 +450,20 @@ type PostgresInstanceSetSpec struct { // Defines a PersistentVolumeClaim for PostgreSQL data. // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes + // --- // +kubebuilder:validation:Required + // + // NOTE(validation): Every PVC must have at least one accessMode. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.accessModes`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2098-L2100 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2292-L2294 + // +kubebuilder:validation:XValidation:rule=`has(self.accessModes) && size(self.accessModes) > 0`,message=`missing accessModes` + // + // NOTE(validation): Every PVC must have a positive storage request. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.resources.requests.storage`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2126-L2133 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2318-L2325 + // +kubebuilder:validation:XValidation:rule=`has(self.resources) && has(self.resources.requests) && has(self.resources.requests.storage)`,message=`missing storage request` DataVolumeClaimSpec corev1.PersistentVolumeClaimSpec `json:"dataVolumeClaimSpec"` // Priority class name for the PostgreSQL pod. Changing this value causes @@ -492,7 +504,20 @@ type PostgresInstanceSetSpec struct { // Defines a separate PersistentVolumeClaim for PostgreSQL's write-ahead log. // More info: https://www.postgresql.org/docs/current/wal.html - // +optional + // --- + // +kubebuilder:validation:Optional + // + // NOTE(validation): Every PVC must have at least one accessMode. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.accessModes`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2098-L2100 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2292-L2294 + // +kubebuilder:validation:XValidation:rule=`has(self.accessModes) && size(self.accessModes) > 0`,message=`missing accessModes` + // + // NOTE(validation): Every PVC must have a positive storage request. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.resources.requests.storage`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2126-L2133 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2318-L2325 + // +kubebuilder:validation:XValidation:rule=`has(self.resources) && has(self.resources.requests) && has(self.resources.requests.storage)`,message=`missing storage request` WALVolumeClaimSpec *corev1.PersistentVolumeClaimSpec `json:"walVolumeClaimSpec,omitempty"` // The list of tablespaces volumes to mount for this postgrescluster @@ -521,7 +546,20 @@ type TablespaceVolume struct { // Defines a PersistentVolumeClaim for a tablespace. // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes + // --- // +kubebuilder:validation:Required + // + // NOTE(validation): Every PVC must have at least one accessMode. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.accessModes`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2098-L2100 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2292-L2294 + // +kubebuilder:validation:XValidation:rule=`has(self.accessModes) && size(self.accessModes) > 0`,message=`missing accessModes` + // + // NOTE(validation): Every PVC must have a positive storage request. NOTE(KEP-4153) + // TODO(k8s-1.28): fieldPath=`.resources.requests.storage`,reason="FieldValueRequired" + // - https://releases.k8s.io/v1.25.0/pkg/apis/core/validation/validation.go#L2126-L2133 + // - https://releases.k8s.io/v1.31.0/pkg/apis/core/validation/validation.go#L2318-L2325 + // +kubebuilder:validation:XValidation:rule=`has(self.resources) && has(self.resources.requests) && has(self.resources.requests.storage)`,message=`missing storage request` DataVolumeClaimSpec corev1.PersistentVolumeClaimSpec `json:"dataVolumeClaimSpec"` } @@ -705,5 +743,6 @@ func NewPostgresCluster() *PostgresCluster { type VolumeSnapshots struct { // Name of the VolumeSnapshotClass that should be used by VolumeSnapshots // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 VolumeSnapshotClassName string `json:"volumeSnapshotClassName"` } diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go index d34316123d..1dc4e3627e 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go @@ -1,17 +1,6 @@ -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go index cc5749e9ec..96cd4da073 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types_test.go @@ -1,17 +1,6 @@ -/* - Copyright 2022 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2022 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/standalone_pgadmin_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/standalone_pgadmin_types.go index 9b64476b64..4fbc90a3b9 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/standalone_pgadmin_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/standalone_pgadmin_types.go @@ -1,16 +1,6 @@ // Copyright 2023 - 2024 Crunchy Data Solutions, Inc. // -// 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. +// SPDX-License-Identifier: Apache-2.0 package v1beta1 diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go index a9aa828a4d..fa32069d0f 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go @@ -1,19 +1,8 @@ //go:build !ignore_autogenerated -/* - Copyright 2021 - 2024 Crunchy Data Solutions, Inc. - 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. -*/ +// Copyright 2021 - 2024 Crunchy Data Solutions, Inc. +// +// SPDX-License-Identifier: Apache-2.0 // Code generated by controller-gen. DO NOT EDIT. diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/01--valid-upgrade.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/01--valid-upgrade.yaml deleted file mode 100644 index fa3985231d..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/01--valid-upgrade.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -# This upgrade is valid, but has no pgcluster to work on and should get that condition -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -spec: - # postgres version that is no longer available - fromPostgresVersion: 10 - toPostgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} - postgresClusterName: major-upgrade-empty-image diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/01-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/01-assert.yaml deleted file mode 100644 index b7d0f936fb..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/01-assert.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - reason: "PGClusterNotFound" diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/10--cluster.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/10--cluster.yaml deleted file mode 100644 index c85a9b8dae..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/10--cluster.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -# Create the cluster we will do an actual upgrade on, but set the postgres version -# to '10' to force a missing image scenario -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - # postgres version that is no longer available - postgresVersion: 10 - patroni: - dynamicConfiguration: - postgresql: - parameters: - shared_preload_libraries: pgaudit, set_user, pg_stat_statements, pgnodemx, pg_cron - instances: - - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } - backups: - pgbackrest: - repos: - - name: repo1 - volume: - volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/10-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/10-assert.yaml deleted file mode 100644 index 72e9ff6387..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/10-assert.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -# The cluster is not running due to the missing image, not due to a proper -# shutdown status. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - reason: "PGClusterNotShutdown" diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/11--shutdown-cluster.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/11--shutdown-cluster.yaml deleted file mode 100644 index 316f3a5472..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/11--shutdown-cluster.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Shutdown the cluster -- but without the annotation. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - shutdown: true diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/11-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/11-assert.yaml deleted file mode 100644 index 5bd9d447cb..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/11-assert.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -# Since the cluster is missing the annotation, we get this condition -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - reason: "PGClusterPrimaryNotIdentified" diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/12--start-and-update-version.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/12--start-and-update-version.yaml deleted file mode 100644 index fcdf4f62e3..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/12--start-and-update-version.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# Update the postgres version and restart the cluster. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - shutdown: false - postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} ---- -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -spec: - # update postgres version - fromPostgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/12-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/12-assert.yaml deleted file mode 100644 index 14c33cccfe..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/12-assert.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -# Wait for the instances to be ready and the replica backup to complete -# by waiting for the status to signal pods ready and pgbackrest stanza created -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} -status: - instances: - - name: '00' - replicas: 1 - readyReplicas: 1 - updatedReplicas: 1 - pgbackrest: - repos: - - name: repo1 - replicaCreateBackupComplete: true - stanzaCreated: true ---- -# Even when the cluster exists, the pgupgrade is not progressing because the cluster is not shutdown -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - reason: "PGClusterNotShutdown" diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/13--shutdown-cluster.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/13--shutdown-cluster.yaml deleted file mode 100644 index 316f3a5472..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/13--shutdown-cluster.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Shutdown the cluster -- but without the annotation. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - shutdown: true diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/13-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/13-assert.yaml deleted file mode 100644 index 78e51e566a..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/13-assert.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -# Since the cluster is missing the annotation, we get this condition -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - reason: "PGClusterMissingRequiredAnnotation" diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/14--annotate-cluster.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/14--annotate-cluster.yaml deleted file mode 100644 index 2fa2c949a9..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/14--annotate-cluster.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Annotate the cluster for an upgrade. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image - annotations: - postgres-operator.crunchydata.com/allow-upgrade: empty-image-upgrade diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/14-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/14-assert.yaml deleted file mode 100644 index bd828180f4..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/14-assert.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -# Now that the postgres cluster is shut down and annotated, the pgupgrade -# can finish reconciling. We know the reconciliation is complete when -# the pgupgrade status is succeeded and the postgres cluster status -# has the updated version. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PGUpgrade -metadata: - name: empty-image-upgrade -status: - conditions: - - type: "Progressing" - status: "False" - - type: "Succeeded" - status: "True" ---- -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -status: - postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/15--start-cluster.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/15--start-cluster.yaml deleted file mode 100644 index e5f270fb2f..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/15--start-cluster.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -# Once the pgupgrade is finished, update the version and set shutdown to false -# in the postgres cluster -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -spec: - postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} - shutdown: false diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/15-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/15-assert.yaml deleted file mode 100644 index dfcbd4c819..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/15-assert.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -# Wait for the instances to be ready with the target Postgres version. -apiVersion: postgres-operator.crunchydata.com/v1beta1 -kind: PostgresCluster -metadata: - name: major-upgrade-empty-image -status: - postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} - instances: - - name: '00' - replicas: 1 - readyReplicas: 1 - updatedReplicas: 1 - pgbackrest: - repos: - - name: repo1 - replicaCreateBackupComplete: true - stanzaCreated: true diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/16-check-pgbackrest.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/16-check-pgbackrest.yaml deleted file mode 100644 index 969e7f0ac3..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/16-check-pgbackrest.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kuttl.dev/v1beta1 -kind: TestStep -commands: -# Check that the pgbackrest setup has successfully completed -- script: | - kubectl -n "${NAMESPACE}" exec "statefulset.apps/major-upgrade-empty-image-repo-host" -c pgbackrest -- pgbackrest check --stanza=db diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/17--check-version.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/17--check-version.yaml deleted file mode 100644 index 5315c1d14f..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/17--check-version.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -# Check the version reported by PostgreSQL -apiVersion: batch/v1 -kind: Job -metadata: - name: major-upgrade-empty-image-after - labels: { postgres-operator-test: kuttl } -spec: - backoffLimit: 6 - template: - metadata: - labels: { postgres-operator-test: kuttl } - spec: - restartPolicy: Never - containers: - - name: psql - image: ${KUTTL_PSQL_IMAGE} - env: - - name: PGURI - valueFrom: { secretKeyRef: { name: major-upgrade-empty-image-pguser-major-upgrade-empty-image, key: uri } } - - # Do not wait indefinitely. - - { name: PGCONNECT_TIMEOUT, value: '5' } - - # Note: the `$$$$` is reduced to `$$` by Kubernetes. - # - https://kubernetes.io/docs/tasks/inject-data-application/ - command: - - psql - - $(PGURI) - - --quiet - - --echo-errors - - --set=ON_ERROR_STOP=1 - - --command - - | - DO $$$$ - BEGIN - ASSERT current_setting('server_version_num') LIKE '${KUTTL_PG_UPGRADE_TO_VERSION}%', - format('got %L', current_setting('server_version_num')); - END $$$$; diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/17-assert.yaml b/testing/kuttl/e2e-other/major-upgrade-missing-image/17-assert.yaml deleted file mode 100644 index 56289c35c1..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/17-assert.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: major-upgrade-empty-image-after -status: - succeeded: 1 diff --git a/testing/kuttl/e2e-other/major-upgrade-missing-image/README.md b/testing/kuttl/e2e-other/major-upgrade-missing-image/README.md deleted file mode 100644 index 341cc854f7..0000000000 --- a/testing/kuttl/e2e-other/major-upgrade-missing-image/README.md +++ /dev/null @@ -1,36 +0,0 @@ -## Major upgrade missing image tests - -This is a variation derived from our major upgrade KUTTL tests designed to -test scenarios where required container images are not defined in either the -PostgresCluster spec or via the RELATED_IMAGES environment variables. - -### Basic PGUpgrade controller and CRD instance validation - -* 01--valid-upgrade: create a valid PGUpgrade instance -* 01-assert: check that the PGUpgrade instance exists and has the expected status - -### Verify new statuses for missing required container images - -* 10--cluster: create the cluster with an unavailable image (i.e. Postgres 10) -* 10-assert: check that the PGUpgrade instance has the expected reason: "PGClusterNotShutdown" -* 11-shutdown-cluster: set the spec.shutdown value to 'true' as required for upgrade -* 11-assert: check that the new reason is set, "PGClusterPrimaryNotIdentified" - -### Update to an available Postgres version, start and upgrade PostgresCluster - -* 12--start-and-update-version: update the Postgres version on both CRD instances and set 'shutdown' to false -* 12-assert: verify that the cluster is running and the PGUpgrade instance now has the new status info with reason: "PGClusterNotShutdown" -* 13--shutdown-cluster: set spec.shutdown to 'true' -* 13-assert: check that the PGUpgrade instance has the expected reason: "PGClusterMissingRequiredAnnotation" -* 14--annotate-cluster: set the required annotation -* 14-assert: verify that the upgrade succeeded and the new Postgres version shows in the cluster's status -* 15--start-cluster: set the new Postgres version and spec.shutdown to 'false' - -### Verify upgraded PostgresCluster - -* 15-assert: verify that the cluster is running -* 16-check-pgbackrest: check that the pgbackrest setup has successfully completed -* 17--check-version: check the version reported by PostgreSQL -* 17-assert: assert the Job from the previous step succeeded - - diff --git a/testing/kuttl/e2e/major-upgrade-missing-image/01--valid-upgrade.yaml b/testing/kuttl/e2e/major-upgrade-missing-image/01--valid-upgrade.yaml index fa3985231d..741efead41 100644 --- a/testing/kuttl/e2e/major-upgrade-missing-image/01--valid-upgrade.yaml +++ b/testing/kuttl/e2e/major-upgrade-missing-image/01--valid-upgrade.yaml @@ -6,6 +6,6 @@ metadata: name: empty-image-upgrade spec: # postgres version that is no longer available - fromPostgresVersion: 10 + fromPostgresVersion: 11 toPostgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} postgresClusterName: major-upgrade-empty-image diff --git a/testing/kuttl/e2e/major-upgrade-missing-image/10--cluster.yaml b/testing/kuttl/e2e/major-upgrade-missing-image/10--cluster.yaml index c85a9b8dae..f5ef8c029e 100644 --- a/testing/kuttl/e2e/major-upgrade-missing-image/10--cluster.yaml +++ b/testing/kuttl/e2e/major-upgrade-missing-image/10--cluster.yaml @@ -7,7 +7,7 @@ metadata: name: major-upgrade-empty-image spec: # postgres version that is no longer available - postgresVersion: 10 + postgresVersion: 11 patroni: dynamicConfiguration: postgresql: diff --git a/testing/kuttl/e2e/major-upgrade-missing-image/README.md b/testing/kuttl/e2e/major-upgrade-missing-image/README.md index 341cc854f7..1053da29ed 100644 --- a/testing/kuttl/e2e/major-upgrade-missing-image/README.md +++ b/testing/kuttl/e2e/major-upgrade-missing-image/README.md @@ -11,7 +11,7 @@ PostgresCluster spec or via the RELATED_IMAGES environment variables. ### Verify new statuses for missing required container images -* 10--cluster: create the cluster with an unavailable image (i.e. Postgres 10) +* 10--cluster: create the cluster with an unavailable image (i.e. Postgres 11) * 10-assert: check that the PGUpgrade instance has the expected reason: "PGClusterNotShutdown" * 11-shutdown-cluster: set the spec.shutdown value to 'true' as required for upgrade * 11-assert: check that the new reason is set, "PGClusterPrimaryNotIdentified" diff --git a/testing/kuttl/e2e/standalone-pgadmin/00-assert.yaml b/testing/kuttl/e2e/standalone-pgadmin/00-assert.yaml new file mode 100644 index 0000000000..5b95b46964 --- /dev/null +++ b/testing/kuttl/e2e/standalone-pgadmin/00-assert.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: command + command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/pgadmin=pgadmin +- namespace: $NAMESPACE + selector: postgres-operator.crunchydata.com/pgadmin=pgadmin diff --git a/trivy.yaml b/trivy.yaml new file mode 100644 index 0000000000..b2ef32d785 --- /dev/null +++ b/trivy.yaml @@ -0,0 +1,14 @@ +# https://aquasecurity.github.io/trivy/latest/docs/references/configuration/config-file/ +--- +# Specify an exact list of recognized and acceptable licenses. +# [A GitHub workflow](/.github/workflows/trivy.yaml) rejects pull requests that +# import licenses not in this list. +# +# https://aquasecurity.github.io/trivy/latest/docs/scanner/license/ +license: + ignored: + - Apache-2.0 + - BSD-2-Clause + - BSD-3-Clause + - ISC + - MIT