diff --git a/Makefile b/Makefile index 6d73251613..24ce2f8279 100644 --- a/Makefile +++ b/Makefile @@ -407,6 +407,9 @@ after-release-versions: -e "s#^IMAGE_PGBOUNCER18=.*#IMAGE_PGBOUNCER18=$(IMAGE_TAG_BASE):main-pgbouncer18#" \ -e "s#^IMAGE_POSTGIS18=.*#IMAGE_POSTGIS18=$(IMAGE_TAG_BASE):main-ppg18-postgres-gis#" \ -e "s#^IMAGE_BACKREST18=.*#IMAGE_BACKREST18=$(IMAGE_TAG_BASE):main-pgbackrest18#" \ + -e "s#^IMAGE_POSTGRESQL19=.*#IMAGE_POSTGRESQL19=$(IMAGE_TAG_BASE):main-ppg19-postgres#" \ + -e "s#^IMAGE_PGBOUNCER19=.*#IMAGE_PGBOUNCER19=$(IMAGE_TAG_BASE):main-pgbouncer19#" \ + -e "s#^IMAGE_BACKREST19=.*#IMAGE_BACKREST19=$(IMAGE_TAG_BASE):main-pgbackrest19#" \ -e "s#^IMAGE_UPGRADE=.*#IMAGE_UPGRADE=$(IMAGE_TAG_BASE):main-upgrade#" \ -e "s#^IMAGE_PMM_CLIENT=.*#IMAGE_PMM_CLIENT=perconalab/pmm-client:3-dev-latest#" \ -e "s#^IMAGE_PMM_SERVER=.*#IMAGE_PMM_SERVER=perconalab/pmm-server:3-dev-latest#" \ diff --git a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml index 29982ac365..5dd4441c8a 100644 --- a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml +++ b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml @@ -13218,7 +13218,7 @@ spec: minimum: 1024 type: integer postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: diff --git a/build/crd/percona/generated/pgv2.percona.com_perconapgupgrades.yaml b/build/crd/percona/generated/pgv2.percona.com_perconapgupgrades.yaml index fec3f9f8b0..06423859c9 100644 --- a/build/crd/percona/generated/pgv2.percona.com_perconapgupgrades.yaml +++ b/build/crd/percona/generated/pgv2.percona.com_perconapgupgrades.yaml @@ -466,7 +466,7 @@ spec: type: object type: object fromPostgresVersion: - maximum: 17 + maximum: 18 minimum: 12 type: integer image: @@ -1264,7 +1264,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: diff --git a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml index e4631db6ad..b88239d7e9 100644 --- a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml +++ b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml @@ -13632,7 +13632,7 @@ spec: minimum: 1024 type: integer postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: @@ -17456,7 +17456,7 @@ spec: type: object type: object fromPostgresVersion: - maximum: 17 + maximum: 18 minimum: 12 type: integer image: @@ -18254,7 +18254,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: diff --git a/config/crd/bases/upstream.pgv2.percona.com_pgupgrades.yaml b/config/crd/bases/upstream.pgv2.percona.com_pgupgrades.yaml index 5cba005651..96a4c83799 100644 --- a/config/crd/bases/upstream.pgv2.percona.com_pgupgrades.yaml +++ b/config/crd/bases/upstream.pgv2.percona.com_pgupgrades.yaml @@ -1263,7 +1263,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: diff --git a/config/crd/bases/upstream.pgv2.percona.com_postgresclusters.yaml b/config/crd/bases/upstream.pgv2.percona.com_postgresclusters.yaml index 92a234c078..ee1ed1ffe7 100644 --- a/config/crd/bases/upstream.pgv2.percona.com_postgresclusters.yaml +++ b/config/crd/bases/upstream.pgv2.percona.com_postgresclusters.yaml @@ -11144,7 +11144,7 @@ spec: postGISVersion: type: string postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 19dbe090d8..7f4e96afdc 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -13833,7 +13833,7 @@ spec: minimum: 1024 type: integer postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: @@ -17661,7 +17661,7 @@ spec: type: object type: object fromPostgresVersion: - maximum: 17 + maximum: 18 minimum: 12 type: integer image: @@ -18459,7 +18459,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -20810,7 +20810,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -32054,7 +32054,7 @@ spec: postGISVersion: type: string postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: diff --git a/deploy/crd.yaml b/deploy/crd.yaml index aac5a9534a..1e96ce05e3 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -13833,7 +13833,7 @@ spec: minimum: 1024 type: integer postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: @@ -17661,7 +17661,7 @@ spec: type: object type: object fromPostgresVersion: - maximum: 17 + maximum: 18 minimum: 12 type: integer image: @@ -18459,7 +18459,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -20810,7 +20810,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -32054,7 +32054,7 @@ spec: postGISVersion: type: string postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index e881798213..f365b80fbd 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -13833,7 +13833,7 @@ spec: minimum: 1024 type: integer postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: @@ -17661,7 +17661,7 @@ spec: type: object type: object fromPostgresVersion: - maximum: 17 + maximum: 18 minimum: 12 type: integer image: @@ -18459,7 +18459,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -20810,7 +20810,7 @@ spec: toPostgresImage: type: string toPostgresVersion: - maximum: 18 + maximum: 19 minimum: 13 type: integer tolerations: @@ -32054,7 +32054,7 @@ spec: postGISVersion: type: string postgresVersion: - maximum: 18 + maximum: 19 minimum: 12 type: integer proxy: diff --git a/e2e-tests/functions b/e2e-tests/functions index abf2aaa4c9..0449459033 100644 --- a/e2e-tests/functions +++ b/e2e-tests/functions @@ -1399,6 +1399,7 @@ function get_container_image() { pgbouncer) key="IMAGE_PGBOUNCER${pgVersion}" ;; pgbackrest) key="IMAGE_BACKREST${pgVersion}" ;; postgis) key="IMAGE_POSTGIS${pgVersion}" ;; + upgrade) key="IMAGE_UPGRADE${pgVersion}" ;; *) key="IMAGE_POSTGRESQL${pgVersion}" ;; esac get_release_image "$key" @@ -1413,8 +1414,35 @@ function get_container_image() { operatorVersion=main fi + # Community images are built from upstream PGDG packages and published under + # their own tags. pgBouncer is version agnostic there, so a single image + # serves every PostgreSQL version. PostgreSQL 19 is the exception: it is in + # beta and its images carry the version in the tag, because they are built + # separately (PGDG testing packages, pgBackRest 2.59, PG 19 upgrade binaries). + if [[ ${PG_DISTRIBUTION} == "community" ]]; then + case $component in + pgbouncer) + echo "${IMAGE_BASE}:${operatorVersion}-pgbouncer-community" + ;; + pgbackrest | upgrade) + if [[ ${pgVersion} -ge 19 ]]; then + echo "${IMAGE_BASE}:${operatorVersion}-${component}${pgVersion}" + else + echo "${IMAGE_BASE}:${operatorVersion}-${component}-community" + fi + ;; + *) + echo "${IMAGE_BASE}:${operatorVersion}-postgres${pgVersion}-community" + ;; + esac + return + fi + if [[ $component == 'pgbouncer' || $component == 'pgbackrest' ]]; then echo "${IMAGE_BASE}:${operatorVersion}-${component}${pgVersion}" + elif [[ $component == 'upgrade' ]]; then + # a single upgrade image carries every supported version + echo "${IMAGE_BASE}:${operatorVersion}-upgrade" elif [[ $component == 'postgis' ]]; then # the docker build job publishes postgis images as ...-ppg-postgres-gis echo "${IMAGE_BASE}:${operatorVersion}-ppg${pgVersion}-postgres-gis" diff --git a/e2e-tests/release_versions b/e2e-tests/release_versions index 13b0316d6c..99173ea4d7 100644 --- a/e2e-tests/release_versions +++ b/e2e-tests/release_versions @@ -25,6 +25,11 @@ IMAGE_PGBOUNCER18=perconalab/percona-postgresql-operator:main-pgbouncer18 IMAGE_POSTGIS18=perconalab/percona-postgresql-operator:main-ppg18-postgres-gis IMAGE_BACKREST18=perconalab/percona-postgresql-operator:main-pgbackrest18 +IMAGE_POSTGRESQL19=perconalab/percona-postgresql-operator:main-ppg19-postgres +IMAGE_PGBOUNCER19=perconalab/percona-postgresql-operator:main-pgbouncer19 +IMAGE_BACKREST19=perconalab/percona-postgresql-operator:main-pgbackrest19 +IMAGE_UPGRADE19=perconalab/percona-postgresql-operator:main-upgrade19 + IMAGE_UPGRADE=perconalab/percona-postgresql-operator:main-upgrade IMAGE_LOGCOLLECTOR=perconalab/fluentbit:main-logcollector diff --git a/e2e-tests/run-pr.csv b/e2e-tests/run-pr.csv index 91d87b8de7..dc131df69a 100644 --- a/e2e-tests/run-pr.csv +++ b/e2e-tests/run-pr.csv @@ -18,6 +18,7 @@ major-upgrade-14-to-15 major-upgrade-15-to-16 major-upgrade-16-to-17 major-upgrade-17-to-18 +major-upgrade-18-to-19 ldap ldap-tls logcollection diff --git a/e2e-tests/run-release.csv b/e2e-tests/run-release.csv index 0a3a2f09d4..00c00c393a 100644 --- a/e2e-tests/run-release.csv +++ b/e2e-tests/run-release.csv @@ -19,6 +19,7 @@ major-upgrade-14-to-15 major-upgrade-15-to-16 major-upgrade-16-to-17 major-upgrade-17-to-18 +major-upgrade-18-to-19 major-upgrade-14-to-15-postgis major-upgrade-15-to-16-postgis major-upgrade-16-to-17-postgis diff --git a/e2e-tests/tests/major-upgrade-18-to-19/00-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/00-assert.yaml new file mode 100644 index 0000000000..ae5a062d84 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/00-assert.yaml @@ -0,0 +1,24 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 120 +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: perconapgclusters.pgv2.percona.com +spec: + group: pgv2.percona.com + names: + kind: PerconaPGCluster + listKind: PerconaPGClusterList + plural: perconapgclusters + singular: perconapgcluster + scope: Namespaced +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +metadata: + name: check-operator-deploy-status +timeout: 120 +commands: + - script: kubectl assert exist-enhanced deployment percona-postgresql-operator -n ${OPERATOR_NS:-$NAMESPACE} --field-selector status.readyReplicas=1 diff --git a/e2e-tests/tests/major-upgrade-18-to-19/00-deploy-operator.yaml b/e2e-tests/tests/major-upgrade-18-to-19/00-deploy-operator.yaml new file mode 100644 index 0000000000..5d21c58f9d --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/00-deploy-operator.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + init_temp_dir # do this only in the first TestStep + + deploy_operator + deploy_client + deploy_s3_secrets diff --git a/e2e-tests/tests/major-upgrade-18-to-19/01-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/01-assert.yaml new file mode 100644 index 0000000000..5859f3dbf4 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/01-assert.yaml @@ -0,0 +1,135 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 120 +--- +kind: StatefulSet +apiVersion: apps/v1 +metadata: + name: major-upgrade-18-to-19-repo-host + labels: + postgres-operator.crunchydata.com/cluster: major-upgrade-18-to-19 + postgres-operator.crunchydata.com/data: pgbackrest + postgres-operator.crunchydata.com/pgbackrest: '' + postgres-operator.crunchydata.com/pgbackrest-dedicated: '' + ownerReferences: + - apiVersion: upstream.pgv2.percona.com/v1beta1 + kind: PostgresCluster + name: major-upgrade-18-to-19 + controller: true + blockOwnerDeletion: true +status: + observedGeneration: 1 + replicas: 1 + readyReplicas: 1 + currentReplicas: 1 + updatedReplicas: 1 + collisionCount: 0 +--- +kind: StatefulSet +apiVersion: apps/v1 +metadata: + labels: + postgres-operator.crunchydata.com/cluster: major-upgrade-18-to-19 + postgres-operator.crunchydata.com/data: postgres + postgres-operator.crunchydata.com/instance-set: instance1 + ownerReferences: + - apiVersion: upstream.pgv2.percona.com/v1beta1 + kind: PostgresCluster + name: major-upgrade-18-to-19 + controller: true + blockOwnerDeletion: true +status: + observedGeneration: 1 + replicas: 1 + readyReplicas: 1 + currentReplicas: 1 + updatedReplicas: 1 + collisionCount: 0 +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: major-upgrade-18-to-19-pgbouncer + labels: + postgres-operator.crunchydata.com/cluster: major-upgrade-18-to-19 + postgres-operator.crunchydata.com/role: pgbouncer + annotations: + deployment.kubernetes.io/revision: '1' + ownerReferences: + - apiVersion: upstream.pgv2.percona.com/v1beta1 + kind: PostgresCluster + name: major-upgrade-18-to-19 + controller: true + blockOwnerDeletion: true +status: + observedGeneration: 1 + replicas: 3 + updatedReplicas: 3 + readyReplicas: 3 +--- +kind: Job +apiVersion: batch/v1 +metadata: + labels: + postgres-operator.crunchydata.com/cluster: major-upgrade-18-to-19 + postgres-operator.crunchydata.com/pgbackrest: '' + postgres-operator.crunchydata.com/pgbackrest-backup: replica-create + postgres-operator.crunchydata.com/pgbackrest-repo: repo1 + ownerReferences: + - apiVersion: pgv2.percona.com/v2 + kind: PerconaPGBackup + controller: true + blockOwnerDeletion: true +status: + succeeded: 1 +--- +apiVersion: upstream.pgv2.percona.com/v1beta1 +kind: PostgresCluster +metadata: + name: major-upgrade-18-to-19 + ownerReferences: + - apiVersion: pgv2.percona.com/v2 + kind: PerconaPGCluster + name: major-upgrade-18-to-19 + controller: true + blockOwnerDeletion: true + finalizers: + - postgres-operator.crunchydata.com/finalizer +status: + instances: + - name: instance1 + readyReplicas: 3 + replicas: 3 + updatedReplicas: 3 + observedGeneration: 1 + pgbackrest: + repoHost: + apiVersion: apps/v1 + kind: StatefulSet + ready: true + repos: + - bound: true + name: repo1 + replicaCreateBackupComplete: true + stanzaCreated: true + proxy: + pgBouncer: + readyReplicas: 3 + replicas: 3 +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: major-upgrade-18-to-19 +status: + pgbouncer: + ready: 3 + size: 3 + postgres: + instances: + - name: instance1 + ready: 3 + size: 3 + ready: 3 + size: 3 + state: ready diff --git a/e2e-tests/tests/major-upgrade-18-to-19/01-create-cluster.yaml b/e2e-tests/tests/major-upgrade-18-to-19/01-create-cluster.yaml new file mode 100644 index 0000000000..f38269d59d --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/01-create-cluster.yaml @@ -0,0 +1,30 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +timeout: 10 +commands: + - script: |- + set -o errexit + set -o xtrace + + # PostgreSQL 19 is a beta tech preview: it exists only as a community + # image built from PGDG packages, there are no ppg-19 packages. Both + # sides of the upgrade must come from the same build, so this test pins + # the community distribution instead of following the run flavor. + # Drop this once PostgreSQL 19 goes GA and ppg-19 images are published. + export PG_DISTRIBUTION=community + + source ../../functions + + postgres_image=$(get_container_image "postgres" 18) + pgbouncer_image=$(get_container_image "pgbouncer" 18) + pgbackrest_image=$(get_container_image "pgbackrest" 18) + + get_cr \ + | yq eval " + .spec.postgresVersion = 18 | + .spec.image = \"${postgres_image}\" | + .spec.instances[0].dataVolumeClaimSpec.resources.requests.storage = \"3Gi\" | + .spec.proxy.pgBouncer.image = \"${pgbouncer_image}\" | + .spec.backups.pgbackrest.image = \"${pgbackrest_image}\" | + .spec.patroni.removeDataDirectoryOnDivergedTimelines = true" \ + | kubectl -n "${NAMESPACE}" apply -f - diff --git a/e2e-tests/tests/major-upgrade-18-to-19/02-write-data.yaml b/e2e-tests/tests/major-upgrade-18-to-19/02-write-data.yaml new file mode 100644 index 0000000000..61fdad8e60 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/02-write-data.yaml @@ -0,0 +1,16 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + + run_psql_local \ + 'CREATE DATABASE myapp; \c myapp \\\ CREATE TABLE IF NOT EXISTS myApp (id int PRIMARY KEY);' \ + "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)" + + run_psql_local \ + '\c myapp \\\ INSERT INTO myApp (id) VALUES (100500)' \ + "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)" diff --git a/e2e-tests/tests/major-upgrade-18-to-19/03-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/03-assert.yaml new file mode 100644 index 0000000000..6848a5b79a --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/03-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 30 +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: 03-read-from-primary +data: + data: ' 100500' diff --git a/e2e-tests/tests/major-upgrade-18-to-19/03-read-from-primary.yaml b/e2e-tests/tests/major-upgrade-18-to-19/03-read-from-primary.yaml new file mode 100644 index 0000000000..a9e3e5dcb8 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/03-read-from-primary.yaml @@ -0,0 +1,11 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + data=$(run_psql_local '\c myapp \\\ SELECT * from myApp;' "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)") + + kubectl create configmap -n "${NAMESPACE}" 03-read-from-primary --from-literal=data="${data}" diff --git a/e2e-tests/tests/major-upgrade-18-to-19/04-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/04-assert.yaml new file mode 100644 index 0000000000..5cf571f6e1 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/04-assert.yaml @@ -0,0 +1,61 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 360 +commands: +- script: |- + kubectl -n ${NAMESPACE} get cm \ + -l app.kubernetes.io/instance=major-upgrade-18-to-19 \ + -l app.kubernetes.io/component=pg -o yaml + kubectl -n ${NAMESPACE} get pg,pod,job + sleep 5 +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: major-upgrade-18-to-19 +spec: + postgresVersion: 19 +status: + pgbouncer: + ready: 3 + size: 3 + postgres: + instances: + - name: instance1 + ready: 3 + size: 3 + ready: 3 + size: 3 + state: ready +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGUpgrade +metadata: + name: 18-to-19 +status: + conditions: + - type: Progressing + reason: PGUpgradeCompleted + status: "False" + observedGeneration: 1 + - type: Succeeded + reason: PGUpgradeSucceeded + status: "True" + observedGeneration: 1 + observedGeneration: 1 +--- +kind: Job +apiVersion: batch/v1 +metadata: + labels: + postgres-operator.crunchydata.com/cluster: major-upgrade-18-to-19 + postgres-operator.crunchydata.com/pgbackrest: '' + postgres-operator.crunchydata.com/pgbackrest-backup: replica-create + postgres-operator.crunchydata.com/pgbackrest-repo: repo1 + ownerReferences: + - apiVersion: pgv2.percona.com/v2 + kind: PerconaPGBackup + controller: true + blockOwnerDeletion: true +status: + succeeded: 1 diff --git a/e2e-tests/tests/major-upgrade-18-to-19/04-upgrade.yaml b/e2e-tests/tests/major-upgrade-18-to-19/04-upgrade.yaml new file mode 100644 index 0000000000..7317ba607c --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/04-upgrade.yaml @@ -0,0 +1,26 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + # see 01-create-cluster.yaml: the whole test runs on community images + export PG_DISTRIBUTION=community + + source ../../functions + + kubectl apply -n ${NAMESPACE} -f - <<-EOF + apiVersion: pgv2.percona.com/v2 + kind: PerconaPGUpgrade + metadata: + name: 18-to-19 + spec: + postgresClusterName: major-upgrade-18-to-19 + image: $(get_container_image "upgrade" 19) + fromPostgresVersion: 18 + toPostgresVersion: 19 + toPostgresImage: $(get_container_image "postgres" 19) + toPgBouncerImage: $(get_container_image "pgbouncer" 19) + toPgBackRestImage: $(get_container_image "pgbackrest" 19) + EOF diff --git a/e2e-tests/tests/major-upgrade-18-to-19/05-post-upgrade.yaml b/e2e-tests/tests/major-upgrade-18-to-19/05-post-upgrade.yaml new file mode 100644 index 0000000000..e633f87033 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/05-post-upgrade.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + + primary=$(get_pod_by_role major-upgrade-18-to-19 primary name) + kubectl -n ${NAMESPACE} exec ${primary} -- vacuumdb --all --analyze-in-stages --missing-stats-only + kubectl -n ${NAMESPACE} exec ${primary} -- vacuumdb --all --analyze-only + kubectl -n ${NAMESPACE} exec ${primary} -- /pgdata/delete_old_cluster.sh diff --git a/e2e-tests/tests/major-upgrade-18-to-19/06-write-data.yaml b/e2e-tests/tests/major-upgrade-18-to-19/06-write-data.yaml new file mode 100644 index 0000000000..6c4416b132 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/06-write-data.yaml @@ -0,0 +1,12 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + + run_psql_local \ + '\c myapp \\\ INSERT INTO myApp (id) VALUES (100501)' \ + "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)" diff --git a/e2e-tests/tests/major-upgrade-18-to-19/07-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/07-assert.yaml new file mode 100644 index 0000000000..838291809d --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/07-assert.yaml @@ -0,0 +1,31 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 660 +--- +kind: Job +apiVersion: batch/v1 +metadata: + annotations: + postgres-operator.crunchydata.com/pgbackrest-backup: backup-after-18-to-19 + labels: + postgres-operator.crunchydata.com/pgbackrest-backup: manual + postgres-operator.crunchydata.com/pgbackrest-repo: repo1 + ownerReferences: + - apiVersion: pgv2.percona.com/v2 + kind: PerconaPGBackup + controller: true + blockOwnerDeletion: true +status: + succeeded: 1 +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGBackup +metadata: + name: backup-after-18-to-19 +spec: + pgCluster: major-upgrade-18-to-19 + repoName: repo1 + options: + - --type=full +status: + state: Succeeded diff --git a/e2e-tests/tests/major-upgrade-18-to-19/07-run-backup.yaml b/e2e-tests/tests/major-upgrade-18-to-19/07-run-backup.yaml new file mode 100644 index 0000000000..b53fe1bea3 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/07-run-backup.yaml @@ -0,0 +1,9 @@ +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGBackup +metadata: + name: backup-after-18-to-19 +spec: + pgCluster: major-upgrade-18-to-19 + repoName: repo1 + options: + - --type=full diff --git a/e2e-tests/tests/major-upgrade-18-to-19/09-write-data.yaml b/e2e-tests/tests/major-upgrade-18-to-19/09-write-data.yaml new file mode 100644 index 0000000000..6ae908639b --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/09-write-data.yaml @@ -0,0 +1,12 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + + run_psql_local \ + '\c myapp \\\ INSERT INTO myApp (id) VALUES (100502)' \ + "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)" diff --git a/e2e-tests/tests/major-upgrade-18-to-19/10-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/10-assert.yaml new file mode 100644 index 0000000000..a5ec0d3cc1 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/10-assert.yaml @@ -0,0 +1,55 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 1500 +commands: + - script: |- + set -o errexit + + kubectl -n ${NAMESPACE} get pod + + for pod in $(kubectl -n ${NAMESPACE} get pods -l postgres-operator.crunchydata.com/data=postgres --no-headers | awk '{print $1}'); do + phase=$(kubectl -n ${NAMESPACE} get pod/${pod} -o jsonpath={".status.phase"}) + if [[ "${phase}" != "Running" ]]; then + echo "Waiting for ${pod} to start running" + continue + fi + echo "PostgreSQL logs from ${pod}:" + echo "find /pgdata/pg19/log -type f -iname 'postgresql*.log' -exec tail -n 30 {} \;" \ + | kubectl -n ${NAMESPACE} exec -it ${pod} -- bash 2>/dev/null + done + + sleep 30 +collectors: + - type: pod + selector: "postgres-operator.crunchydata.com/data=postgres" + tail: 30 + - type: pod + selector: "postgres-operator.crunchydata.com/pgbackrest-restore=''" + tail: 30 +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGRestore +metadata: + name: restore-after-18-to-19 +spec: + pgCluster: major-upgrade-18-to-19 + repoName: repo1 +status: + state: Succeeded +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: major-upgrade-18-to-19 +status: + pgbouncer: + ready: 3 + size: 3 + postgres: + instances: + - name: instance1 + ready: 3 + size: 3 + ready: 3 + size: 3 + state: ready diff --git a/e2e-tests/tests/major-upgrade-18-to-19/10-run-restore.yaml b/e2e-tests/tests/major-upgrade-18-to-19/10-run-restore.yaml new file mode 100644 index 0000000000..c3109980a2 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/10-run-restore.yaml @@ -0,0 +1,7 @@ +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGRestore +metadata: + name: restore-after-18-to-19 +spec: + pgCluster: major-upgrade-18-to-19 + repoName: repo1 diff --git a/e2e-tests/tests/major-upgrade-18-to-19/11-assert.yaml b/e2e-tests/tests/major-upgrade-18-to-19/11-assert.yaml new file mode 100644 index 0000000000..f26c6cb0db --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/11-assert.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 30 +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: 11-read-from-primary +data: + data: |2- + 100500 + 100501 + 100502 diff --git a/e2e-tests/tests/major-upgrade-18-to-19/11-read-from-primary.yaml b/e2e-tests/tests/major-upgrade-18-to-19/11-read-from-primary.yaml new file mode 100644 index 0000000000..9378e3a1e7 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/11-read-from-primary.yaml @@ -0,0 +1,12 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +timeout: 30 +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + data=$(run_psql_local '\c myapp \\\ SELECT * from myApp;' "postgres:$(get_psql_user_pass major-upgrade-18-to-19-pguser-postgres)@$(get_psql_user_host major-upgrade-18-to-19-pguser-postgres)") + + kubectl create configmap -n "${NAMESPACE}" 11-read-from-primary --from-literal=data="${data}" diff --git a/e2e-tests/tests/major-upgrade-18-to-19/99-remove-cluster-gracefully.yaml b/e2e-tests/tests/major-upgrade-18-to-19/99-remove-cluster-gracefully.yaml new file mode 100644 index 0000000000..78792efdea --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/99-remove-cluster-gracefully.yaml @@ -0,0 +1,22 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: pgv2.percona.com/v2 + kind: PerconaPGCluster + metadata: + name: major-upgrade-18-to-19 +- apiVersion: upstream.pgv2.percona.com/v1beta1 + kind: PostgresCluster + metadata: + name: major-upgrade-18-to-19 +commands: + - script: |- + set -o errexit + set -o xtrace + + source ../../functions + + remove_all_finalizers + check_operator_panic + destroy_operator + timeout: 60 diff --git a/e2e-tests/tests/major-upgrade-18-to-19/conf/major-upgrade-18-to-19.yaml b/e2e-tests/tests/major-upgrade-18-to-19/conf/major-upgrade-18-to-19.yaml new file mode 100644 index 0000000000..6499908841 --- /dev/null +++ b/e2e-tests/tests/major-upgrade-18-to-19/conf/major-upgrade-18-to-19.yaml @@ -0,0 +1,14 @@ +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: major-upgrade-18-to-19 +spec: + extensions: + image: + imagePullPolicy: Always + storage: + type: s3 + bucket: pg-extensions + region: eu-central-1 + secret: + name: aws-s3-secret diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go index e20feb493c..e681eaea62 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go @@ -109,7 +109,7 @@ type PerconaPGClusterSpec struct { // The major version of PostgreSQL installed in the PostgreSQL image // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=12 - // +kubebuilder:validation:Maximum=18 + // +kubebuilder:validation:Maximum=19 // +operator-sdk:csv:customresourcedefinitions:type=spec PostgresVersion int `json:"postgresVersion"` @@ -494,6 +494,23 @@ func (cr *PerconaPGCluster) Validate() error { ptr.Deref(cr.Spec.Extensions.BuiltIn.PGStatStatements, false) { return errors.New("pg_stat_monitor and pg_stat_statements cannot both be enabled") } + // Extension packages are not built for PostgreSQL 19 (beta) yet; loading them + // via shared_preload_libraries would make postgres fail to start. + // pgAudit is the exception: the PG 19 community image compiles it from source. + // Remove this check once PostgreSQL 19 goes GA and the extensions are available. + if cr.Spec.PostgresVersion >= 19 { + for _, ext := range []struct { + name string + enabled *bool + }{ + {"pg_cron", cr.Spec.Extensions.PGCron.Enabled}, + {"set_user", cr.Spec.Extensions.SetUser.Enabled}, + } { + if ptr.Deref(ext.enabled, false) { + return errors.Errorf("spec.extensions.%s.enabled cannot be set for PostgreSQL %d: extension packages are not built for beta releases", ext.name, cr.Spec.PostgresVersion) + } + } + } if err := cr.ValidateDynamicConfiguration(); err != nil { return err } diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgupgrade_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgupgrade_types.go index f8ee81aa38..3d2348eae6 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgupgrade_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgupgrade_types.go @@ -59,13 +59,13 @@ type PerconaPGUpgradeSpec struct { // The major version of PostgreSQL before the upgrade. // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=12 - // +kubebuilder:validation:Maximum=17 + // +kubebuilder:validation:Maximum=18 FromPostgresVersion int `json:"fromPostgresVersion"` // The major version of PostgreSQL to be upgraded to. // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=13 - // +kubebuilder:validation:Maximum=18 + // +kubebuilder:validation:Maximum=19 ToPostgresVersion int `json:"toPostgresVersion"` // The image to use for PostgreSQL containers after upgrade. diff --git a/pkg/apis/upstream.pgv2.percona.com/v1beta1/pgupgrade_types.go b/pkg/apis/upstream.pgv2.percona.com/v1beta1/pgupgrade_types.go index 49e7796706..1f4ea2760d 100644 --- a/pkg/apis/upstream.pgv2.percona.com/v1beta1/pgupgrade_types.go +++ b/pkg/apis/upstream.pgv2.percona.com/v1beta1/pgupgrade_types.go @@ -59,7 +59,7 @@ type PGUpgradeSpec struct { // The major version of PostgreSQL to be upgraded to. // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=13 - // +kubebuilder:validation:Maximum=18 + // +kubebuilder:validation:Maximum=19 ToPostgresVersion int `json:"toPostgresVersion"` // The image name to use for PostgreSQL containers after upgrade. diff --git a/pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_types.go b/pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_types.go index 15c38db34a..3361915c4c 100644 --- a/pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_types.go +++ b/pkg/apis/upstream.pgv2.percona.com/v1beta1/postgrescluster_types.go @@ -134,7 +134,7 @@ type PostgresClusterSpec struct { // The major version of PostgreSQL installed in the PostgreSQL image // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=12 - // +kubebuilder:validation:Maximum=18 + // +kubebuilder:validation:Maximum=19 // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1 PostgresVersion int `json:"postgresVersion"`