├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── support---question-and-answer.md ├── actions │ ├── k3d │ │ └── action.yaml │ └── trivy │ │ └── action.yaml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── codeql-analysis.yaml │ ├── govulncheck.yaml │ ├── lint.yaml │ ├── test.yaml │ └── trivy.yaml ├── .gitignore ├── .golangci.bck.yaml ├── .golangci.next.yaml ├── .golangci.yaml ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── bin ├── .gitignore └── license_aggregator.sh ├── build └── postgres-operator │ └── Dockerfile ├── cmd └── postgres-operator │ ├── main.go │ ├── main_test.go │ ├── open_telemetry.go │ └── version.go ├── conf └── .gitignore ├── config ├── README.md ├── crd │ ├── bases │ │ ├── postgres-operator.crunchydata.com_crunchybridgeclusters.yaml │ │ ├── postgres-operator.crunchydata.com_pgadmins.yaml │ │ ├── postgres-operator.crunchydata.com_pgupgrades.yaml │ │ └── postgres-operator.crunchydata.com_postgresclusters.yaml │ └── kustomization.yaml ├── default │ └── kustomization.yaml ├── dev │ ├── kustomization.yaml │ └── manager-dev.yaml ├── manager │ ├── kustomization.yaml │ └── manager.yaml ├── namespace │ ├── kustomization.yaml │ └── namespace.yaml └── rbac │ ├── kustomization.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml ├── docs └── static │ └── logos │ ├── TRADEMARKS.md │ ├── pgo.png │ └── pgo.svg ├── examples ├── pgadmin │ ├── kustomization.yaml │ └── pgadmin.yaml └── postgrescluster │ ├── kustomization.yaml │ └── postgrescluster.yaml ├── go.mod ├── go.sum ├── hack ├── .gitignore ├── api-template.tmpl ├── boilerplate.go.txt ├── create-kubeconfig.sh ├── go-get.sh ├── tools │ └── .gitignore └── update-pgmonitor-installer.sh ├── img └── CrunchyDataPrimaryIcon.png ├── internal ├── bridge │ ├── client.go │ ├── client_test.go │ ├── crunchybridgecluster │ │ ├── apply.go │ │ ├── crunchybridgecluster_controller.go │ │ ├── crunchybridgecluster_controller_test.go │ │ ├── delete.go │ │ ├── delete_test.go │ │ ├── helpers_test.go │ │ ├── mock_bridge_api.go │ │ ├── postgres.go │ │ ├── postgres_test.go │ │ ├── watches.go │ │ └── watches_test.go │ ├── installation.go │ ├── installation_test.go │ ├── naming.go │ ├── quantity.go │ └── quantity_test.go ├── collector │ ├── config.go │ ├── config_test.go │ ├── eq_pg16_fast_metrics.yaml │ ├── generate.go │ ├── generated │ │ ├── eq_pg16_fast_metrics.json │ │ ├── gte_pg17_fast_metrics.json │ │ ├── lt_pg16_fast_metrics.json │ │ ├── lt_pg17_fast_metrics.json │ │ ├── pgbackrest_logs_transforms.json │ │ ├── pgbouncer_metrics_queries.json │ │ ├── postgres_5m_metrics.json │ │ ├── postgres_5m_per_db_metrics.json │ │ ├── postgres_5s_metrics.json │ │ └── postgres_logs_transforms.json │ ├── gte_pg17_fast_metrics.yaml │ ├── helpers_test.go │ ├── instance.go │ ├── logrotate.conf │ ├── lt_pg16_fast_metrics.yaml │ ├── lt_pg17_fast_metrics.yaml │ ├── naming.go │ ├── patroni.go │ ├── patroni_test.go │ ├── pgadmin.go │ ├── pgadmin_test.go │ ├── pgbackrest.go │ ├── pgbackrest_logs_transforms.yaml │ ├── pgbackrest_test.go │ ├── pgbouncer.go │ ├── pgbouncer_metrics_queries.yaml │ ├── pgbouncer_test.go │ ├── postgres.go │ ├── postgres_5m_metrics.yaml │ ├── postgres_5m_per_db_metrics.yaml │ ├── postgres_5s_metrics.yaml │ ├── postgres_logs_transforms.yaml │ ├── postgres_metrics.go │ ├── postgres_metrics_test.go │ ├── postgres_test.go │ └── util.go ├── config │ ├── config.go │ └── config_test.go ├── controller │ ├── pgupgrade │ │ ├── apply.go │ │ ├── jobs.go │ │ ├── jobs_test.go │ │ ├── labels.go │ │ ├── pgupgrade_controller.go │ │ ├── registration.go │ │ ├── registration_test.go │ │ ├── utils.go │ │ ├── world.go │ │ └── world_test.go │ ├── postgrescluster │ │ ├── apply.go │ │ ├── apply_test.go │ │ ├── cluster.go │ │ ├── cluster_test.go │ │ ├── controller.go │ │ ├── controller_ref_manager.go │ │ ├── controller_ref_manager_test.go │ │ ├── controller_test.go │ │ ├── delete.go │ │ ├── helpers_test.go │ │ ├── instance.go │ │ ├── instance.md │ │ ├── instance_rollout_test.go │ │ ├── instance_test.go │ │ ├── metrics_setup.sql │ │ ├── patroni.go │ │ ├── patroni_test.go │ │ ├── pgadmin.go │ │ ├── pgadmin_test.go │ │ ├── pgbackrest.go │ │ ├── pgbackrest_test.go │ │ ├── pgbouncer.go │ │ ├── pgbouncer_test.go │ │ ├── pgmonitor.go │ │ ├── pgmonitor_test.go │ │ ├── pki.go │ │ ├── pki_test.go │ │ ├── pod_disruption_budget.go │ │ ├── pod_disruption_budget_test.go │ │ ├── postgres.go │ │ ├── postgres_test.go │ │ ├── rbac.go │ │ ├── snapshots.go │ │ ├── snapshots_test.go │ │ ├── suite_test.go │ │ ├── topology.go │ │ ├── topology_test.go │ │ ├── util.go │ │ ├── util_test.go │ │ ├── volumes.go │ │ ├── volumes_test.go │ │ ├── watches.go │ │ └── watches_test.go │ ├── runtime │ │ ├── client.go │ │ ├── conversion.go │ │ ├── conversion_test.go │ │ ├── pod_client.go │ │ ├── reconcile.go │ │ ├── reconcile_test.go │ │ ├── runtime.go │ │ ├── ticker.go │ │ └── ticker_test.go │ └── standalone_pgadmin │ │ ├── apply.go │ │ ├── config.go │ │ ├── configmap.go │ │ ├── configmap_test.go │ │ ├── controller.go │ │ ├── controller_test.go │ │ ├── helpers_test.go │ │ ├── pod.go │ │ ├── pod_test.go │ │ ├── related.go │ │ ├── related_test.go │ │ ├── service.go │ │ ├── service_test.go │ │ ├── statefulset.go │ │ ├── statefulset_test.go │ │ ├── users.go │ │ ├── users_test.go │ │ ├── volume.go │ │ └── volume_test.go ├── feature │ ├── features.go │ └── features_test.go ├── initialize │ ├── doc.go │ ├── metadata.go │ ├── metadata_test.go │ ├── primitives.go │ ├── primitives_test.go │ ├── security.go │ └── security_test.go ├── kubeapi │ ├── patch.go │ └── patch_test.go ├── kubernetes │ ├── apis.go │ ├── apis_test.go │ ├── discovery.go │ └── discovery_test.go ├── logging │ ├── logr.go │ ├── logr_test.go │ ├── logrus.go │ └── logrus_test.go ├── naming │ ├── annotations.go │ ├── annotations_test.go │ ├── controllers.go │ ├── dns.go │ ├── dns_test.go │ ├── doc.go │ ├── labels.go │ ├── labels_test.go │ ├── limitations.md │ ├── names.go │ ├── names_test.go │ ├── selectors.go │ └── selectors_test.go ├── patroni │ ├── api.go │ ├── api_test.go │ ├── certificates.go │ ├── certificates.md │ ├── certificates_test.go │ ├── config.go │ ├── config.md │ ├── config_test.go │ ├── doc.go │ ├── postgres.go │ ├── postgres_test.go │ ├── rbac.go │ ├── rbac_test.go │ ├── reconcile.go │ └── reconcile_test.go ├── pgadmin │ ├── config.go │ ├── config_test.go │ ├── reconcile.go │ ├── reconcile_test.go │ ├── users.go │ └── users_test.go ├── pgaudit │ ├── postgres.go │ └── postgres_test.go ├── pgbackrest │ ├── certificates.go │ ├── certificates.md │ ├── certificates_test.go │ ├── config.go │ ├── config.md │ ├── config_test.go │ ├── iana.go │ ├── options.go │ ├── options_test.go │ ├── pgbackrest.go │ ├── pgbackrest_test.go │ ├── postgres.go │ ├── postgres_test.go │ ├── rbac.go │ ├── rbac_test.go │ ├── reconcile.go │ ├── reconcile_test.go │ ├── restore.md │ ├── tls-server.md │ ├── util.go │ └── util_test.go ├── pgbouncer │ ├── certificates.go │ ├── certificates_test.go │ ├── config.go │ ├── config.md │ ├── config_test.go │ ├── postgres.go │ ├── postgres_test.go │ ├── reconcile.go │ └── reconcile_test.go ├── pgmonitor │ ├── exporter.go │ ├── exporter_test.go │ ├── postgres.go │ ├── postgres_test.go │ ├── util.go │ └── util_test.go ├── pki │ ├── common.go │ ├── doc.go │ ├── encoding.go │ ├── encoding_test.go │ ├── pki.go │ └── pki_test.go ├── postgis │ ├── postgis.go │ └── postgis_test.go ├── postgres │ ├── config.go │ ├── config_test.go │ ├── databases.go │ ├── databases_test.go │ ├── doc.go │ ├── exec.go │ ├── exec_test.go │ ├── hba.go │ ├── hba_test.go │ ├── huge_pages.go │ ├── huge_pages_test.go │ ├── iana.go │ ├── parameters.go │ ├── parameters_test.go │ ├── password │ │ ├── doc.go │ │ ├── md5.go │ │ ├── md5_test.go │ │ ├── password.go │ │ ├── password_test.go │ │ ├── scram.go │ │ └── scram_test.go │ ├── reconcile.go │ ├── reconcile_test.go │ ├── sql.go │ ├── sql_test.go │ ├── users.go │ ├── users_test.go │ ├── versions.go │ ├── versions_test.go │ └── wal.md ├── registration │ ├── interface.go │ ├── runner.go │ ├── runner_test.go │ └── testing.go ├── shell │ ├── paths.go │ ├── paths_test.go │ ├── quote.go │ └── quote_test.go ├── testing │ ├── cmp │ │ └── cmp.go │ ├── events │ │ └── recorder.go │ ├── require │ │ ├── encoding.go │ │ ├── encoding_test.go │ │ ├── errors.go │ │ ├── exec.go │ │ ├── kubernetes.go │ │ └── parallel.go │ ├── token_invalid │ ├── token_rsa_key.pub │ ├── token_valid │ └── validation │ │ ├── pgadmin_test.go │ │ └── postgrescluster_test.go ├── tracing │ ├── errors.go │ ├── errors_test.go │ ├── tracing.go │ └── tracing_test.go ├── upgradecheck │ ├── header.go │ ├── header_test.go │ ├── helpers_test.go │ ├── http.go │ └── http_test.go └── util │ ├── secrets.go │ └── secrets_test.go ├── licenses ├── .gitignore └── LICENSE.txt ├── pkg └── apis │ └── postgres-operator.crunchydata.com │ └── v1beta1 │ ├── config_types.go │ ├── config_types_test.go │ ├── crunchy_bridgecluster_types.go │ ├── groupversion_info.go │ ├── instrumentation_types.go │ ├── patroni_types.go │ ├── pgadmin_types.go │ ├── pgbackrest_types.go │ ├── pgbouncer_types.go │ ├── pgmonitor_types.go │ ├── pgupgrade_types.go │ ├── postgres_types.go │ ├── postgrescluster_types.go │ ├── postgrescluster_types_test.go │ ├── shared_types.go │ ├── shared_types_test.go │ ├── standalone_pgadmin_types.go │ └── zz_generated.deepcopy.go ├── testing ├── kuttl │ ├── README.md │ ├── e2e │ │ ├── cluster-pause │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--cluster-paused.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--cluster-resume.yaml │ │ │ ├── 02-assert.yaml │ │ │ └── files │ │ │ │ ├── 00-cluster-created.yaml │ │ │ │ ├── 00-create-cluster.yaml │ │ │ │ ├── 01-cluster-paused.yaml │ │ │ │ ├── 01-pause-cluster.yaml │ │ │ │ ├── 02-cluster-resumed.yaml │ │ │ │ └── 02-resume-cluster.yaml │ │ ├── cluster-start │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--connect.yaml │ │ │ ├── 01-assert.yaml │ │ │ └── files │ │ │ │ ├── 00-cluster-created.yaml │ │ │ │ ├── 00-create-cluster.yaml │ │ │ │ ├── 01-connect-psql.yaml │ │ │ │ └── 01-psql-connected.yaml │ │ ├── delete-namespace │ │ │ ├── 00-assert.yaml │ │ │ ├── 00-create-cluster.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 01-delete-namespace.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── 00-create-cluster.yaml │ │ │ │ ├── 00-create-namespace.yaml │ │ │ │ ├── 00-created.yaml │ │ │ │ └── 01-errors.yaml │ │ ├── delete │ │ │ ├── 00-assert.yaml │ │ │ ├── 00-create-cluster.yaml │ │ │ ├── 01-delete-cluster.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 10-create-cluster-with-replicas.yaml │ │ │ ├── 11-delete-cluster-with-replicas.yaml │ │ │ ├── 20-assert.yaml │ │ │ ├── 20-create-broken-cluster.yaml │ │ │ ├── 21-delete-broken-cluster.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── 00-cluster-created.yaml │ │ │ │ ├── 00-create-cluster.yaml │ │ │ │ ├── 01-cluster-deleted.yaml │ │ │ │ ├── 10-cluster-with-replicas-created.yaml │ │ │ │ ├── 10-create-cluster-with-replicas.yaml │ │ │ │ ├── 11-cluster-with-replicas-deleted.yaml │ │ │ │ ├── 20-broken-cluster-not-created.yaml │ │ │ │ ├── 20-create-broken-cluster.yaml │ │ │ │ └── 21-broken-cluster-deleted.yaml │ │ ├── exporter-custom-queries │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--change-custom-queries.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── exporter-custom-queries-cluster-checks.yaml │ │ │ │ ├── exporter-custom-queries-cluster.yaml │ │ │ │ ├── exporter-custom-queries-configmap-update-checks.yaml │ │ │ │ ├── exporter-custom-queries-configmap-update.yaml │ │ │ │ └── exporter-custom-queries-configmap.yaml │ │ ├── exporter-no-tls │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ └── files │ │ │ │ ├── exporter-no-tls-cluster-checks.yaml │ │ │ │ └── exporter-no-tls-cluster.yaml │ │ ├── exporter-password-change │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--change-password.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── check-restarted-pod.yaml │ │ │ │ ├── initial-postgrescluster-checks.yaml │ │ │ │ ├── initial-postgrescluster.yaml │ │ │ │ ├── update-monitoring-password-checks.yaml │ │ │ │ └── update-monitoring-password.yaml │ │ ├── exporter-tls │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ └── files │ │ │ │ ├── exporter-tls-certs.yaml │ │ │ │ ├── exporter-tls-cluster-checks.yaml │ │ │ │ └── exporter-tls-cluster.yaml │ │ ├── major-upgrade-missing-image │ │ │ ├── 01--valid-upgrade.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 10--cluster.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 11--shutdown-cluster.yaml │ │ │ ├── 11-assert.yaml │ │ │ ├── 12--start-and-update-version.yaml │ │ │ ├── 12-assert.yaml │ │ │ ├── 13--shutdown-cluster.yaml │ │ │ ├── 13-assert.yaml │ │ │ ├── 14--annotate-cluster.yaml │ │ │ ├── 14-assert.yaml │ │ │ ├── 15--start-cluster.yaml │ │ │ ├── 15-assert.yaml │ │ │ ├── 16-check-pgbackrest.yaml │ │ │ ├── 17--check-version.yaml │ │ │ ├── 17-assert.yaml │ │ │ └── README.md │ │ ├── major-upgrade │ │ │ ├── 02--valid-upgrade.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 10--already-updated-cluster.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 11-delete-cluster.yaml │ │ │ ├── 30--cluster.yaml │ │ │ ├── 30-assert.yaml │ │ │ ├── 31--create-data.yaml │ │ │ ├── 31-assert.yaml │ │ │ ├── 32--shutdown-cluster.yaml │ │ │ ├── 32-assert.yaml │ │ │ ├── 33--annotate-cluster.yaml │ │ │ ├── 33-assert.yaml │ │ │ ├── 34--restart-cluster.yaml │ │ │ ├── 34-assert.yaml │ │ │ ├── 35-check-pgbackrest-and-replica.yaml │ │ │ ├── 36--check-data-and-version.yaml │ │ │ └── 36-assert.yaml │ │ ├── optional-backups │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01-errors.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--cluster.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── 06-assert.yaml │ │ │ ├── 10--cluster.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 11-assert.yaml │ │ │ ├── 20--cluster.yaml │ │ │ ├── 20-assert.yaml │ │ │ ├── 21-assert.yaml │ │ │ ├── 22--cluster.yaml │ │ │ ├── 23-assert.yaml │ │ │ ├── 24-errors.yaml │ │ │ ├── 25-assert.yaml │ │ │ └── README.md │ │ ├── otel-logging-and-metrics │ │ │ ├── 00--cluster.yaml │ │ │ ├── 01--add-instrumentation-to-postgrescluster.yaml │ │ │ ├── 02-assert-repo-host-does-not-logs.yaml │ │ │ ├── 03--backup.yaml │ │ │ ├── 04-assert-repo-host-contains-logs.yaml │ │ │ ├── 05-assert-pgbouncer.yaml │ │ │ ├── 06-assert-instance.yaml │ │ │ ├── 07--add-instrumentation-to-pgadmin.yaml │ │ │ ├── 08-assert-pgadmin.yaml │ │ │ ├── 09--add-custom-queries.yaml │ │ │ ├── 10-assert-custom-queries.yaml │ │ │ ├── 11--add-per-db-metrics-to-postgrescluster.yaml │ │ │ ├── 12-assert-per-db-queries.yaml │ │ │ ├── 13--add-second-per-db-metrics-to-postgrescluster.yaml │ │ │ ├── 14-assert-per-db-queries-for-multiple-targets.yaml │ │ │ ├── 15--remove-per-db-metrics-from-postgrescluster.yaml │ │ │ ├── 16-assert-per-db-query-removed.yaml │ │ │ ├── 17--add-custom-queries-per-db.yaml │ │ │ ├── 18-assert-custom-queries-per-db.yaml │ │ │ ├── 19--add-logs-exporter.yaml │ │ │ ├── 20-assert-logs-exported.yaml │ │ │ ├── 21--cluster-no-backups.yaml │ │ │ ├── 22-assert-instance.yaml │ │ │ ├── 23--cluster-add-backups.yaml │ │ │ ├── 24--remove-backups.yaml │ │ │ ├── 25--annotate-cluster.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── 00--create-cluster.yaml │ │ │ │ ├── 00-cluster-created.yaml │ │ │ │ ├── 01--add-instrumentation.yaml │ │ │ │ ├── 01-instrumentation-added.yaml │ │ │ │ ├── 03--annotate-cluster.yaml │ │ │ │ ├── 03-backup-completed.yaml │ │ │ │ ├── 07--add-instrumentation.yaml │ │ │ │ ├── 07-instrumentation-added.yaml │ │ │ │ ├── 09--add-custom-queries.yaml │ │ │ │ ├── 09-custom-queries-added.yaml │ │ │ │ ├── 11--add-per-db-metrics.yaml │ │ │ │ ├── 13--add-per-db-metrics.yaml │ │ │ │ ├── 15--remove-per-db-metrics.yaml │ │ │ │ ├── 17--add-custom-queries-per-db.yaml │ │ │ │ ├── 17-custom-queries-per-db-added.yaml │ │ │ │ ├── 19--add-logs-exporter.yaml │ │ │ │ ├── 19-logs-exporter-added.yaml │ │ │ │ ├── 21--create-cluster.yaml │ │ │ │ ├── 21-cluster-created.yaml │ │ │ │ ├── 23--add-backups.yaml │ │ │ │ ├── 23-backups-added.yaml │ │ │ │ └── 25-backups-removed.yaml │ │ ├── password-change │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--psql-connect-uri.yaml │ │ │ ├── 01--psql-connect.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--secret.yaml │ │ │ ├── 02-errors.yaml │ │ │ ├── 03--psql-connect-uri.yaml │ │ │ ├── 03--psql-connect.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--secret.yaml │ │ │ ├── 04-errors.yaml │ │ │ ├── 05--psql-connect-uri.yaml │ │ │ ├── 05--psql-connect.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── 06--cluster.yaml │ │ │ ├── 06-assert.yaml │ │ │ ├── 07--psql-connect-uri.yaml │ │ │ ├── 07--psql-connect.yaml │ │ │ ├── 07-assert.yaml │ │ │ ├── 08--secret.yaml │ │ │ ├── 08-errors.yaml │ │ │ ├── 09--psql-connect-uri.yaml │ │ │ ├── 09--psql-connect.yaml │ │ │ ├── 09-assert.yaml │ │ │ ├── 10--secret.yaml │ │ │ ├── 10-errors.yaml │ │ │ ├── 11--psql-connect-uri.yaml │ │ │ ├── 11--psql-connect.yaml │ │ │ ├── 11-assert.yaml │ │ │ └── README.md │ │ ├── pgbackrest-backup-standby │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--check-backup-logs.yaml │ │ │ ├── 02--cluster.yaml │ │ │ ├── 02-assert.yaml │ │ │ └── README.md │ │ ├── pgbackrest-init │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01-pgbackrest-connect.yaml │ │ │ ├── 02--cluster.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 03-pgbackrest-connect.yaml │ │ │ ├── 04--cluster.yaml │ │ │ ├── 04-assert.yaml │ │ │ ├── 05-pgbackrest-connect.yaml │ │ │ ├── 06--check-spool-path.yaml │ │ │ └── README.md │ │ ├── pgbackrest-restore │ │ │ ├── 01--create-cluster.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--create-data.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 03--backup.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--clone-cluster.yaml │ │ │ ├── 04-assert.yaml │ │ │ ├── 05--check-data.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── 06--delete-clone.yaml │ │ │ ├── 07--annotate.yaml │ │ │ ├── 07--update-cluster.yaml │ │ │ ├── 08--wait-restart.yaml │ │ │ ├── 09--add-data.yaml │ │ │ ├── 09-assert.yaml │ │ │ ├── 10--wait-archived.yaml │ │ │ ├── 11--clone-cluster.yaml │ │ │ ├── 11-assert.yaml │ │ │ ├── 12--check-data.yaml │ │ │ ├── 12-assert.yaml │ │ │ ├── 13--delete-clone.yaml │ │ │ ├── 14--lose-data.yaml │ │ │ ├── 15--in-place-pitr.yaml │ │ │ ├── 15-assert.yaml │ │ │ ├── 16--check-data.yaml │ │ │ ├── 16-assert.yaml │ │ │ └── 17--check-replication.yaml │ │ ├── pgbouncer │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--psql-connect.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 10--read-certificate.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 11--open-connection.yaml │ │ │ ├── 11-assert.yaml │ │ │ ├── 12--rotate-certificate.yaml │ │ │ ├── 13--read-certificate.yaml │ │ │ ├── 13-assert.yaml │ │ │ ├── 14--compare-certificate.yaml │ │ │ ├── 15--check-connection.yaml │ │ │ ├── 16--reconnect.yaml │ │ │ └── 16-assert.yaml │ │ ├── replica-read │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--psql-replica-read.yaml │ │ │ └── 01-assert.yaml │ │ ├── root-cert-ownership │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--check-owners.yaml │ │ │ ├── 02--delete-owner1.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 02-errors.yaml │ │ │ ├── 03--check-owners.yaml │ │ │ ├── 04--delete-owner2.yaml │ │ │ ├── 04-errors.yaml │ │ │ ├── 05--check-secret.yaml │ │ │ └── README.md │ │ ├── scaledown │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--update-cluster.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--delete-cluster.yaml │ │ │ ├── 10--create-cluster.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 11-annotate.yaml │ │ │ ├── 12--update-cluster.yaml │ │ │ ├── 12-assert.yaml │ │ │ ├── 13--delete-cluster.yaml │ │ │ ├── 20--create-cluster.yaml │ │ │ ├── 20-assert.yaml │ │ │ ├── 21--update-cluster.yaml │ │ │ ├── 21-assert.yaml │ │ │ └── readme.MD │ │ ├── security-context │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--security-context.yaml │ │ │ └── 10--kyverno.yaml │ │ ├── standalone-pgadmin-db-uri │ │ │ ├── 00--create-cluster.yaml │ │ │ ├── 01--user-schema.yaml │ │ │ ├── 02--create-pgadmin.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--update-pgadmin.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── 00-cluster-check.yaml │ │ │ │ ├── 00-cluster.yaml │ │ │ │ ├── 02-pgadmin-check.yaml │ │ │ │ ├── 02-pgadmin.yaml │ │ │ │ ├── 04-pgadmin-check.yaml │ │ │ │ └── 04-pgadmin.yaml │ │ ├── standalone-pgadmin-service │ │ │ ├── 00--pgadmin.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--update-service.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--remove-service.yaml │ │ │ ├── 02-errors.yaml │ │ │ ├── 10--manual-service.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 20--owned-service.yaml │ │ │ ├── 20-assert.yaml │ │ │ ├── 21--service-takeover-fails.yaml │ │ │ └── 21-assert.yaml │ │ ├── standalone-pgadmin-user-management │ │ │ ├── 00--create-pgadmin.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--edit-pgadmin-users.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--change-pgadmin-user-passwords.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── 06--delete-pgadmin-users.yaml │ │ │ ├── 07-assert.yaml │ │ │ ├── README.md │ │ │ └── files │ │ │ │ ├── 00-pgadmin-check.yaml │ │ │ │ ├── 00-pgadmin.yaml │ │ │ │ ├── 02-pgadmin-check.yaml │ │ │ │ ├── 02-pgadmin.yaml │ │ │ │ ├── 04-pgadmin-check.yaml │ │ │ │ ├── 04-pgadmin.yaml │ │ │ │ ├── 06-pgadmin-check.yaml │ │ │ │ └── 06-pgadmin.yaml │ │ ├── streaming-standby │ │ │ ├── 00--secrets.yaml │ │ │ ├── 01--primary-cluster.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--create-data.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 03--standby-cluster.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--check-data.yaml │ │ │ ├── 04-assert.yaml │ │ │ └── README.md │ │ ├── switchover │ │ │ ├── 01--cluster.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02-annotate.yaml │ │ │ └── 03-assert.yaml │ │ ├── tablespace-enabled │ │ │ ├── 00--cluster.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--psql-connect.yaml │ │ │ ├── 01-assert.yaml │ │ │ └── README.md │ │ └── wal-pvc-pgupgrade │ │ │ ├── 00--create-resources.yaml │ │ │ ├── 00-assert.yaml │ │ │ ├── 01--create-data.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 02--shutdown-cluster.yaml │ │ │ ├── 02-assert.yaml │ │ │ ├── 03--annotate-cluster.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 04--restart-cluster.yaml │ │ │ ├── 04-assert.yaml │ │ │ ├── 05-check-pgbackrest-and-replica.yaml │ │ │ ├── 06--check-data-and-version.yaml │ │ │ ├── 06--check-spool-path.yaml │ │ │ └── 06-assert.yaml │ ├── kuttl-test.yaml │ └── scripts │ │ └── pgbackrest-initialization.sh └── policies │ └── kyverno │ ├── kustomization.yaml │ └── service_links.yaml └── trivy.yaml /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | # 3 | # https://neovim.io/doc/user/editorconfig.html 4 | # https://github.com/editorconfig/editorconfig-emacs 5 | # https://plugins.jetbrains.com/plugin/7294-editorconfig 6 | # https://marketplace.visualstudio.com/items/EditorConfig.EditorConfig 7 | 8 | [*] 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.{go,sh}] 14 | indent_size = tab 15 | indent_style = tab 16 | 17 | [*.{md,yml,yaml}] 18 | indent_size = 2 19 | indent_style = space 20 | 21 | [Makefile] 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # https://docs.gitlab.com/user/project/merge_requests/changes#collapse-generated-files 2 | # https://github.com/github-linguist/linguist/blob/-/docs/overrides.md#generated-code 3 | # https://git-scm.com/docs/gitattributes#_defining_macro_attributes 4 | [attr]generated gitlab-generated linguist-generated 5 | 6 | /internal/collector/generated/*.json generated 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 - 2025 Crunchy Data Solutions, Inc. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # documentation: https://docs.github.com/code-security/dependabot/dependabot-version-updates 6 | # schema documentation: https://docs.github.com/code-security/dependabot/working-with-dependabot/dependabot-options-reference 7 | # yaml-language-server: $schema=https://json.schemastore.org/dependabot-2.0.json 8 | --- 9 | version: 2 10 | updates: 11 | - package-ecosystem: github-actions 12 | directories: 13 | - '/' 14 | - '.github/actions/*' 15 | schedule: 16 | interval: weekly 17 | day: tuesday 18 | groups: 19 | all-github-actions: 20 | patterns: ['*'] 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Checklist:** 2 | 3 | 4 | - [ ] Have you added an explanation of what your changes do and why you'd like them to be included? 5 | - [ ] Have you updated or added documentation for the change, as applicable? 6 | - [ ] Have you tested your changes on all related environments with successful results, as applicable? 7 | - [ ] Have you added automated tests? 8 | 9 | 10 | 11 | **Type of Changes:** 12 | 13 | 14 | - [ ] New feature 15 | - [ ] Bug fix 16 | - [ ] Documentation 17 | - [ ] Testing enhancement 18 | - [ ] Other 19 | 20 | 21 | **What is the current behavior (link to any open issues here)?** 22 | 23 | 24 | 25 | **What is the new behavior (if this is a feature change)?** 26 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 27 | 28 | 29 | 30 | **Other Information**: 31 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yaml: -------------------------------------------------------------------------------- 1 | # https://codeql.github.com 2 | name: CodeQL 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | schedule: 10 | - cron: '10 18 * * 2' 11 | 12 | env: 13 | # Use the Go toolchain installed by setup-go 14 | # https://github.com/actions/setup-go/issues/457 15 | GOTOOLCHAIN: local 16 | 17 | jobs: 18 | analyze: 19 | if: ${{ github.repository == 'CrunchyData/postgres-operator' }} 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | 25 | runs-on: ubuntu-24.04 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: actions/setup-go@v5 29 | with: { go-version: stable } 30 | 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v3 33 | with: { languages: go } 34 | 35 | - name: Autobuild 36 | # This action calls `make` which runs our "help" target. 37 | uses: github/codeql-action/autobuild@v3 38 | 39 | - name: Perform CodeQL Analysis 40 | uses: github/codeql-action/analyze@v3 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /vendor/ 3 | /testing/kuttl/e2e-generated*/ 4 | gke_gcloud_auth_plugin_cache 5 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | /apiserver 2 | /pgo 3 | /pgo-mac 4 | /pgo.exe 5 | /postgres-operator 6 | -------------------------------------------------------------------------------- /build/postgres-operator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/ubi-minimal 2 | 3 | COPY licenses /licenses 4 | 5 | COPY bin/postgres-operator /usr/local/bin 6 | 7 | RUN mkdir -p /opt/crunchy/conf 8 | 9 | COPY hack/tools/queries /opt/crunchy/conf 10 | 11 | RUN chgrp -R 0 /opt/crunchy/conf && chmod -R g=u opt/crunchy/conf 12 | 13 | USER 2 14 | 15 | CMD ["postgres-operator"] 16 | -------------------------------------------------------------------------------- /cmd/postgres-operator/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path/filepath" 11 | "runtime" 12 | ) 13 | 14 | var userAgent string 15 | var versionString string 16 | 17 | func initVersion() { 18 | command := "unknown" 19 | if len(os.Args) > 0 && len(os.Args[0]) > 0 { 20 | command = filepath.Base(os.Args[0]) 21 | } 22 | if len(versionString) > 0 { 23 | command += "/" + versionString 24 | } 25 | userAgent = fmt.Sprintf("%s (%s/%s)", command, runtime.GOOS, runtime.GOARCH) 26 | } 27 | -------------------------------------------------------------------------------- /conf/.gitignore: -------------------------------------------------------------------------------- 1 | *.repo 2 | *.public 3 | *.private 4 | *KEY* 5 | -------------------------------------------------------------------------------- /config/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | ## Targets 9 | 10 | - The `default` target installs the operator in the `postgres-operator` 11 | namespace and configures it to manage resources in all namespaces. 12 | 13 | 17 | 18 | 19 | ## Bases 20 | 21 | - The `crd` base creates `CustomResourceDefinition`s that are managed by the 22 | operator. 23 | 24 | - The `manager` base creates the `Deployment` that runs the operator. Do not 25 | run this as a target. 26 | 27 | - The `rbac` base creates a `ClusterRole` that allows the operator to 28 | manage resources in all current and future namespaces. 29 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | kind: Kustomization 2 | 3 | resources: 4 | - bases/postgres-operator.crunchydata.com_crunchybridgeclusters.yaml 5 | - bases/postgres-operator.crunchydata.com_postgresclusters.yaml 6 | - bases/postgres-operator.crunchydata.com_pgupgrades.yaml 7 | - bases/postgres-operator.crunchydata.com_pgadmins.yaml 8 | 9 | patches: 10 | - target: 11 | kind: CustomResourceDefinition 12 | patch: |- 13 | - op: add 14 | path: /metadata/labels 15 | value: 16 | app.kubernetes.io/name: pgo 17 | app.kubernetes.io/version: latest 18 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: postgres-operator 5 | 6 | labels: 7 | - includeSelectors: true 8 | pairs: 9 | # Note: this label differs from the label set in postgres-operator-examples 10 | postgres-operator.crunchydata.com/control-plane: postgres-operator 11 | 12 | resources: 13 | - ../crd 14 | - ../rbac 15 | - ../manager 16 | 17 | images: 18 | - name: postgres-operator 19 | newName: registry.developers.crunchydata.com/crunchydata/postgres-operator 20 | newTag: latest 21 | -------------------------------------------------------------------------------- /config/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../default 6 | 7 | patches: 8 | - path: manager-dev.yaml 9 | -------------------------------------------------------------------------------- /config/dev/manager-dev.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: pgo 5 | spec: 6 | replicas: 0 7 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - manager.yaml 6 | -------------------------------------------------------------------------------- /config/namespace/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - namespace.yaml 6 | -------------------------------------------------------------------------------- /config/namespace/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: postgres-operator 5 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - service_account.yaml 6 | - role.yaml 7 | - role_binding.yaml 8 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: postgres-operator 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: postgres-operator 10 | subjects: 11 | - kind: ServiceAccount 12 | name: pgo 13 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: pgo 6 | -------------------------------------------------------------------------------- /docs/static/logos/pgo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrunchyData/postgres-operator/8f4e9767227cca1eff5f59f2c5d21eaeb028cb92/docs/static/logos/pgo.png -------------------------------------------------------------------------------- /examples/pgadmin/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: postgres-operator 5 | 6 | resources: 7 | - pgadmin.yaml 8 | -------------------------------------------------------------------------------- /examples/pgadmin/pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: rhino 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | serverGroups: 13 | - name: supply 14 | # An empty selector selects all postgresclusters in the Namespace 15 | postgresClusterSelector: {} 16 | - name: demand 17 | postgresClusterSelector: 18 | matchLabels: 19 | postgres-operator.crunchydata.com/cluster: hippo 20 | -------------------------------------------------------------------------------- /examples/postgrescluster/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: postgres-operator 5 | 6 | resources: 7 | - postgrescluster.yaml 8 | -------------------------------------------------------------------------------- /examples/postgrescluster/postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: hippo 5 | spec: 6 | postgresVersion: 16 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | backups: 16 | pgbackrest: 17 | repos: 18 | - name: repo1 19 | volume: 20 | volumeClaimSpec: 21 | accessModes: 22 | - "ReadWriteOnce" 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | - name: repo2 27 | volume: 28 | volumeClaimSpec: 29 | accessModes: 30 | - "ReadWriteOnce" 31 | resources: 32 | requests: 33 | storage: 1Gi 34 | proxy: 35 | pgBouncer: {} 36 | -------------------------------------------------------------------------------- /hack/.gitignore: -------------------------------------------------------------------------------- 1 | .kube -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /hack/go-get.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2025 Crunchy Data Solutions, Inc. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | # This runs `$GO get` without changing the "go" directive in the "go.mod" file. 8 | # To change that, pass a "go@go{version}" argument. 9 | # 10 | # https://go.dev/doc/toolchain 11 | # 12 | # Usage: $0 help 13 | # Usage: $0 -u golang.org/x/crypto 14 | # Usage: $0 -u golang.org/x/crypto go@go1.99.0 15 | # 16 | 17 | set -eu 18 | : "${GO:=go}" 19 | 20 | if [[ "$#" -eq 0 ]] || [[ "$1" == 'help' ]] || [[ "$*" == *'--help'* ]] || [[ "$*" == *'--version'* ]] 21 | then 22 | self=$(command -v -- "$0") 23 | content=$(< "${self}") 24 | content="${content%%$'\n\n'*}" 25 | content="#${content#*$'\n#'}" 26 | content="${content//$'$GO'/${GO}}" 27 | exec echo "${content//$'$0'/$0}" 28 | fi 29 | 30 | version=$(${GO} list -m -f 'go@go{{.GoVersion}}') 31 | 32 | for arg in "$@" 33 | do case "${arg}" in go@go*) version="${arg}" ;; *) esac 34 | done 35 | 36 | ${GO} get "$@" "${version}" 'toolchain@none' 37 | ${GO} mod tidy 38 | -------------------------------------------------------------------------------- /hack/tools/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /img/CrunchyDataPrimaryIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrunchyData/postgres-operator/8f4e9767227cca1eff5f59f2c5d21eaeb028cb92/img/CrunchyDataPrimaryIcon.png -------------------------------------------------------------------------------- /internal/bridge/naming.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package bridge 6 | 7 | const ( 8 | KeyBridgeLocalTime = "bridge-local-time" 9 | KeyBridgeToken = "bridge-token" 10 | ) 11 | -------------------------------------------------------------------------------- /internal/collector/helpers_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package collector 6 | 7 | import ( 8 | "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" 9 | ) 10 | 11 | func testInstrumentationSpec() *v1beta1.InstrumentationSpec { 12 | spec := v1beta1.InstrumentationSpec{ 13 | Config: &v1beta1.InstrumentationConfigSpec{ 14 | Exporters: map[string]any{ 15 | "googlecloud": map[string]any{ 16 | "log": map[string]any{ 17 | "default_log_name": "opentelemetry.io/collector-exported-log", 18 | }, 19 | "project": "google-project-name", 20 | }, 21 | }, 22 | }, 23 | Logs: &v1beta1.InstrumentationLogsSpec{ 24 | Exporters: []string{"googlecloud"}, 25 | }, 26 | } 27 | 28 | return spec.DeepCopy() 29 | } 30 | -------------------------------------------------------------------------------- /internal/collector/logrotate.conf: -------------------------------------------------------------------------------- 1 | %s { 2 | rotate %d 3 | missingok 4 | sharedscripts 5 | notifempty 6 | nocompress 7 | %s 8 | postrotate 9 | %s 10 | endscript 11 | } 12 | -------------------------------------------------------------------------------- /internal/controller/postgrescluster/topology.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package postgrescluster 6 | 7 | import ( 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | ) 11 | 12 | // defaultTopologySpreadConstraints returns constraints that prefer to schedule 13 | // pods on different nodes and in different zones. 14 | func defaultTopologySpreadConstraints(selector metav1.LabelSelector) []corev1.TopologySpreadConstraint { 15 | return []corev1.TopologySpreadConstraint{ 16 | { 17 | TopologyKey: corev1.LabelHostname, 18 | WhenUnsatisfiable: corev1.ScheduleAnyway, 19 | LabelSelector: &selector, MaxSkew: 1, 20 | }, 21 | { 22 | TopologyKey: corev1.LabelTopologyZone, 23 | WhenUnsatisfiable: corev1.ScheduleAnyway, 24 | LabelSelector: &selector, MaxSkew: 1, 25 | }, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /internal/controller/standalone_pgadmin/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package standalone_pgadmin 6 | 7 | // Include configs here used by multiple files 8 | const ( 9 | // ConfigMap keys used also in mounting volume to pod 10 | settingsConfigMapKey = "pgadmin-settings.json" 11 | settingsClusterMapKey = "pgadmin-shared-clusters.json" 12 | gunicornConfigKey = "gunicorn-config.json" 13 | 14 | // Port address used to define pod and service 15 | pgAdminPort = 5050 16 | 17 | // Directory for pgAdmin in container 18 | pgAdminDir = "/usr/local/lib/python3.11/site-packages/pgadmin4" 19 | ) 20 | -------------------------------------------------------------------------------- /internal/initialize/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package initialize provides functions to initialize some common fields and types. 6 | package initialize 7 | -------------------------------------------------------------------------------- /internal/initialize/metadata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package initialize 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // Annotations initializes the Annotations of object when they are nil. 12 | func Annotations(object metav1.Object) { 13 | if object != nil && object.GetAnnotations() == nil { 14 | object.SetAnnotations(make(map[string]string)) 15 | } 16 | } 17 | 18 | // Labels initializes the Labels of object when they are nil. 19 | func Labels(object metav1.Object) { 20 | if object != nil && object.GetLabels() == nil { 21 | object.SetLabels(make(map[string]string)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /internal/naming/controllers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package naming 6 | 7 | const ( 8 | ControllerBridge = "bridge-controller" 9 | ControllerPGAdmin = "pgadmin-controller" 10 | ) 11 | -------------------------------------------------------------------------------- /internal/naming/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package naming provides functions and constants for the postgres-operator 6 | // naming and labeling scheme. 7 | package naming 8 | -------------------------------------------------------------------------------- /internal/patroni/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package patroni provides clients, utilities and resources for configuring and 6 | // interacting with Patroni inside of a PostgreSQL cluster 7 | package patroni 8 | -------------------------------------------------------------------------------- /internal/pgbackrest/iana.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package pgbackrest 6 | 7 | // The protocol used by pgBackRest is registered with the Internet Assigned 8 | // Numbers Authority (IANA). 9 | // - https://www.iana.org/assignments/service-names-port-numbers 10 | const ( 11 | // IANAPortNumber is the port assigned to pgBackRest at the IANA. 12 | IANAPortNumber = 8432 13 | 14 | // IANAServiceName is the name of the pgBackRest protocol at the IANA. 15 | IANAServiceName = "pgbackrest" 16 | ) 17 | -------------------------------------------------------------------------------- /internal/pgbackrest/rbac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package pgbackrest 6 | 7 | import ( 8 | corev1 "k8s.io/api/core/v1" 9 | rbacv1 "k8s.io/api/rbac/v1" 10 | 11 | "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" 12 | ) 13 | 14 | // +kubebuilder:rbac:groups="",resources="pods",verbs={list} 15 | // +kubebuilder:rbac:groups="",resources="pods/exec",verbs={create} 16 | 17 | // Permissions returns the RBAC rules pgBackRest needs for a cluster. 18 | func Permissions(cluster *v1beta1.PostgresCluster) []rbacv1.PolicyRule { 19 | 20 | rules := make([]rbacv1.PolicyRule, 0, 2) 21 | 22 | rules = append(rules, rbacv1.PolicyRule{ 23 | APIGroups: []string{corev1.SchemeGroupVersion.Group}, 24 | Resources: []string{"pods"}, 25 | Verbs: []string{"list"}, 26 | }) 27 | 28 | rules = append(rules, rbacv1.PolicyRule{ 29 | APIGroups: []string{corev1.SchemeGroupVersion.Group}, 30 | Resources: []string{"pods/exec"}, 31 | Verbs: []string{"create"}, 32 | }) 33 | 34 | return rules 35 | } 36 | -------------------------------------------------------------------------------- /internal/pki/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package pki provides types and functions to support the public key 6 | // infrastructure of the Postgres Operator. It enforces a two layer system 7 | // of certificate authorities and certificates. 8 | // 9 | // NewRootCertificateAuthority() creates a new root CA. 10 | // GenerateLeafCertificate() creates a new leaf certificate. 11 | // 12 | // Certificate and PrivateKey are primitives that can be marshaled. 13 | package pki 14 | -------------------------------------------------------------------------------- /internal/postgres/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package postgres is a collection of resources that interact with PostgreSQL 6 | // or provide functionality that makes it easier for other resources to interact 7 | // with PostgreSQL. 8 | package postgres 9 | -------------------------------------------------------------------------------- /internal/postgres/iana.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package postgres 6 | 7 | // The protocol used by PostgreSQL is registered with the Internet Assigned 8 | // Numbers Authority (IANA). 9 | // - https://www.iana.org/assignments/service-names-port-numbers 10 | const ( 11 | // IANAPortNumber is the port assigned to PostgreSQL at the IANA. 12 | IANAPortNumber = 5432 13 | 14 | // IANAServiceName is the name of the PostgreSQL protocol at the IANA. 15 | IANAServiceName = "postgresql" 16 | ) 17 | -------------------------------------------------------------------------------- /internal/postgres/password/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // package password lets one create the appropriate password hashes and 6 | // verifiers that are used for adding the information into PostgreSQL 7 | package password 8 | -------------------------------------------------------------------------------- /internal/postgres/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package postgres 6 | 7 | import "strings" 8 | 9 | // escapeLiteral is called by QuoteLiteral to add backslashes before special 10 | // characters of the "escape" string syntax. Double quote marks to escape them 11 | // regardless of the "backslash_quote" parameter. 12 | var escapeLiteral = strings.NewReplacer(`'`, `''`, `\`, `\\`).Replace 13 | 14 | // QuoteLiteral escapes v so it can be safely used as a literal (or constant) 15 | // in an SQL statement. 16 | func QuoteLiteral(v string) string { 17 | // Use the "escape" syntax to ensure that backslashes behave consistently regardless 18 | // of the "standard_conforming_strings" parameter. Include a space before so 19 | // the "E" cannot change the meaning of an adjacent SQL keyword or identifier. 20 | // - https://www.postgresql.org/docs/current/sql-syntax-lexical.html 21 | return ` E'` + escapeLiteral(v) + `'` 22 | } 23 | -------------------------------------------------------------------------------- /internal/postgres/sql_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package postgres 6 | 7 | import ( 8 | "testing" 9 | 10 | "gotest.tools/v3/assert" 11 | ) 12 | 13 | func TestQuoteLiteral(t *testing.T) { 14 | assert.Equal(t, QuoteLiteral(``), ` E''`) 15 | assert.Equal(t, QuoteLiteral(`ab"cd\ef'gh`), ` E'ab"cd\\ef''gh'`) 16 | } 17 | -------------------------------------------------------------------------------- /internal/postgres/versions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package postgres 6 | 7 | import "time" 8 | 9 | // https://www.postgresql.org/support/versioning 10 | var finalReleaseDates = map[int]time.Time{ 11 | 10: time.Date(2022, time.November+1, 10, 0, 0, 0, 0, time.UTC), 12 | 11: time.Date(2023, time.November+1, +9, 0, 0, 0, 0, time.UTC), 13 | 12: time.Date(2024, time.November+1, 14, 0, 0, 0, 0, time.UTC), 14 | 13: time.Date(2025, time.November+1, 13, 0, 0, 0, 0, time.UTC), 15 | 14: time.Date(2026, time.November+1, 12, 0, 0, 0, 0, time.UTC), 16 | 15: time.Date(2027, time.November+1, 11, 0, 0, 0, 0, time.UTC), 17 | 16: time.Date(2028, time.November+1, +9, 0, 0, 0, 0, time.UTC), 18 | 17: time.Date(2029, time.November+1, +8, 0, 0, 0, 0, time.UTC), 19 | } 20 | 21 | // ReleaseIsFinal returns whether or not t is definitively past the final 22 | // scheduled release of a Postgres version. 23 | func ReleaseIsFinal(majorVersion int, t time.Time) bool { 24 | known, ok := finalReleaseDates[majorVersion] 25 | return ok && t.After(known) 26 | } 27 | -------------------------------------------------------------------------------- /internal/registration/testing.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package registration 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/client-go/tools/record" 10 | "sigs.k8s.io/controller-runtime/pkg/client" 11 | ) 12 | 13 | // NOTE: This type can go away following https://go.dev/issue/47487. 14 | 15 | type RegistrationFunc func(record.EventRecorder, client.Object, *[]metav1.Condition) bool 16 | 17 | func (fn RegistrationFunc) Required(rec record.EventRecorder, obj client.Object, conds *[]metav1.Condition) bool { 18 | return fn(rec, obj, conds) 19 | } 20 | 21 | var _ Registration = RegistrationFunc(nil) 22 | -------------------------------------------------------------------------------- /internal/shell/quote_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package shell 6 | 7 | import ( 8 | "testing" 9 | 10 | "gotest.tools/v3/assert" 11 | ) 12 | 13 | func TestQuoteWord(t *testing.T) { 14 | assert.Equal(t, QuoteWord(""), `''`, 15 | "expected empty and single-quoted") 16 | 17 | assert.Equal(t, QuoteWord("abc"), `'abc'`, 18 | "expected single-quoted") 19 | 20 | assert.Equal(t, QuoteWord(`a" b"c`), `'a" b"c'`, 21 | "expected easy double-quotes") 22 | 23 | assert.Equal(t, QuoteWord(`a' b'c`), 24 | `'a'`+`"'"`+`' b'`+`"'"`+`'c'`, 25 | "expected close-quote-open twice") 26 | 27 | assert.Equal(t, QuoteWord(`a''b`), 28 | `'a'`+`"''"`+`'b'`, 29 | "expected close-quotes-open once") 30 | 31 | assert.Equal(t, QuoteWord(`x''''y`), 32 | `'x'`+`"''"`+`''`+`"''"`+`'y'`, 33 | "expected close-quotes-open twice") 34 | } 35 | -------------------------------------------------------------------------------- /internal/testing/require/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package require 6 | 7 | import ( 8 | "errors" 9 | "testing" 10 | 11 | "gotest.tools/v3/assert" 12 | apierrors "k8s.io/apimachinery/pkg/api/errors" 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | ) 15 | 16 | // StatusError returns the [metav1.Status] within err's tree. 17 | // It calls t.Fatal when err is nil or there is no status. 18 | func StatusError(t testing.TB, err error) metav1.Status { 19 | status, ok := err.(apierrors.APIStatus) 20 | 21 | assert.Assert(t, ok || errors.As(err, &status), 22 | "%T does not implement %T", err, status) 23 | 24 | return status.Status() 25 | } 26 | 27 | // Value returns v or panics when err is not nil. 28 | func Value[T any](v T, err error) T { 29 | if err != nil { 30 | panic(err) 31 | } 32 | return v 33 | } 34 | -------------------------------------------------------------------------------- /internal/testing/require/parallel.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package require 6 | 7 | import ( 8 | "sync" 9 | "testing" 10 | ) 11 | 12 | var capacity sync.Mutex 13 | 14 | // ParallelCapacity calls t.Parallel then waits for needed capacity. There is 15 | // no wait when needed is zero. 16 | func ParallelCapacity(t *testing.T, needed int) { 17 | t.Helper() 18 | t.Parallel() 19 | 20 | if needed > 0 { 21 | // Assume capacity of one; allow only one caller at a time. 22 | // TODO: actually track how much capacity is available. 23 | capacity.Lock() 24 | t.Cleanup(capacity.Unlock) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /internal/testing/token_invalid: -------------------------------------------------------------------------------- 1 | eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUEsiLCJzdWIiOiJwb2ludC5vZi5jb250YWN0QGNvbXBhbnkuY29tIiwiaXNzIjoiQ3J1bmNoeSBEYXRhIiwiZXhwIjoxNzI3NDUxOTM1LCJuYmYiOjE1MTYyMzkwMjIsImlhdCI6MTUxNjIzOTAyMn0.I2RBGvpHV4GKoWD5TaM89ToEFBhNdSYovyNlYp-PbEmSTTGLc_Wa3cKujahSYtlfwlZ6gSPKVE5U4IPAv7kzO8C74zoX-9_5GpHxGyBBDLL2XLglRmuTO_W5bheuFzrCq9A7HIi-kjKTk_DRvep1dhdooHqFzZQiAxxDa_U-zCkUAByo1cWd-Z2k51VZp1TUzAYSId6rDclIBc7QSi2HrMsdh3IeXZQs4dPhjemf09l6vVIT94sdqj774t6kTawUJhTdGVrZ_ad8ar3YxCpWGZzB3oSo62K7QEGWp9KCqTebP-LAF8glkpwi8H4HWiUcXo4bfANXPXe9Z0Oziau69Q+ 2 | -------------------------------------------------------------------------------- /internal/testing/token_rsa_key.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo 3 | 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u 4 | +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh 5 | kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ 6 | 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg 7 | cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc 8 | mwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /internal/testing/token_valid: -------------------------------------------------------------------------------- 1 | eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUEsiLCJzdWIiOiJwb2ludC5vZi5jb250YWN0QGNvbXBhbnkuY29tIiwiaXNzIjoiQ3J1bmNoeSBEYXRhIiwiZXhwIjoxNzI3NDUxOTM1LCJuYmYiOjE1MTYyMzkwMjIsImlhdCI6MTUxNjIzOTAyMn0.I2RBGvpHV4GKoWD5TaM89ToEFBhNdSYovyNlYp-PbEmSTTGLc_Wa3cKujahSYtlfwlZ6gSPKVE5U4IPAv7kzO8C74zoX-9_5GpHxGyBBDLL2XLglRmuTO_W5bheuFzrCq9A7HIi-kjKTk_DRvep1dhdooHqFzZQiAxxDa_U-zCkUAByo1cWd-Z2k51VZp1TUzAYSId6rDclIBc7QSi2HrMsdh3IeXZQs4dPhjemf09l6vVIT94sdqj774t6kTawUJhTdGVrZ_ad8ar3YxCpWGZzB3oSo62K7QEGWp9KCqTebP-LAF8glkpwi8H4HWiUcXo4bfANXPXe9Z0Oziau69Q 2 | -------------------------------------------------------------------------------- /internal/tracing/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package tracing 6 | 7 | import ( 8 | semconv "go.opentelemetry.io/otel/semconv/v1.27.0" 9 | "go.opentelemetry.io/otel/trace" 10 | ) 11 | 12 | // Check returns true when err is nil. Otherwise, it adds err as an exception 13 | // event on s and returns false. If you intend to return err, consider using 14 | // [Escape] instead. 15 | // 16 | // See: https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans 17 | func Check(s Span, err error) bool { 18 | if err == nil { 19 | return true 20 | } 21 | if s.IsRecording() { 22 | s.RecordError(err) 23 | } 24 | return false 25 | } 26 | 27 | // Escape adds non-nil err as an escaped exception event on s and returns err. 28 | // See: https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans 29 | func Escape(s Span, err error) error { 30 | if err != nil && s.IsRecording() { 31 | s.RecordError(err, trace.WithAttributes(semconv.ExceptionEscaped(true))) 32 | } 33 | return err 34 | } 35 | -------------------------------------------------------------------------------- /licenses/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /pkg/apis/postgres-operator.crunchydata.com/v1beta1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 - 2025 Crunchy Data Solutions, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package v1beta1 contains API Schema definitions for the postgres-operator v1beta1 API group 6 | // +kubebuilder:object:generate=true 7 | // +groupName=postgres-operator.crunchydata.com 8 | package v1beta1 9 | 10 | import ( 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "sigs.k8s.io/controller-runtime/pkg/scheme" 13 | ) 14 | 15 | var ( 16 | // GroupVersion is group version used to register these objects 17 | GroupVersion = schema.GroupVersion{Group: "postgres-operator.crunchydata.com", Version: "v1beta1"} 18 | 19 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 20 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 21 | 22 | // AddToScheme adds the types in this group-version to the given scheme. 23 | AddToScheme = SchemeBuilder.AddToScheme 24 | ) 25 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-create-cluster.yaml 5 | assert: 6 | - files/00-cluster-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=cluster-pause 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=cluster-pause 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/01--cluster-paused.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/01-pause-cluster.yaml 5 | assert: 6 | - files/01-cluster-paused.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=cluster-pause 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=cluster-pause 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/02--cluster-resume.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/02-resume-cluster.yaml 5 | assert: 6 | - files/02-cluster-resumed.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=cluster-pause 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=cluster-pause 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/00-cluster-created.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/01-cluster-paused.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | status: 6 | conditions: 7 | - message: No spec changes will be applied and no other statuses will be updated. 8 | reason: Paused 9 | status: "False" 10 | type: Progressing 11 | instances: 12 | - name: instance1 13 | readyReplicas: 1 14 | replicas: 1 15 | updatedReplicas: 1 16 | --- 17 | apiVersion: v1 18 | kind: Service 19 | metadata: 20 | name: cluster-pause-ha 21 | spec: 22 | type: ClusterIP 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/01-pause-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | spec: 6 | # We change the service, but this won't result in a change until we resume 7 | service: 8 | type: LoadBalancer 9 | paused: true 10 | instances: 11 | - name: instance1 12 | dataVolumeClaimSpec: 13 | accessModes: 14 | - "ReadWriteOnce" 15 | resources: 16 | requests: 17 | storage: 1Gi 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/02-cluster-resumed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: cluster-pause-ha 16 | spec: 17 | type: LoadBalancer 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-pause/files/02-resume-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-pause 5 | spec: 6 | paused: false 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-create-cluster.yaml 5 | assert: 6 | - files/00-cluster-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=cluster-start 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=cluster-start 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/01--connect.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/01-connect-psql.yaml 5 | assert: 6 | - files/01-psql-connected.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=cluster-start 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=cluster-start 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/files/00-cluster-created.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-start 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: cluster-start-primary 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/files/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: cluster-start 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/cluster-start/files/01-psql-connected.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect 5 | status: 6 | succeeded: 1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n ${KUTTL_TEST_DELETE_NAMESPACE} describe pods --selector postgres-operator.crunchydata.com/cluster=delete-namespace 6 | - namespace: ${KUTTL_TEST_DELETE_NAMESPACE} 7 | selector: postgres-operator.crunchydata.com/cluster=delete-namespace 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-create-namespace.yaml 5 | - files/00-create-cluster.yaml 6 | assert: 7 | - files/00-created.yaml 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n ${KUTTL_TEST_DELETE_NAMESPACE} describe pods --selector postgres-operator.crunchydata.com/cluster=delete-namespace 6 | - namespace: ${KUTTL_TEST_DELETE_NAMESPACE} 7 | selector: postgres-operator.crunchydata.com/cluster=delete-namespace 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/01-delete-namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove the namespace. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: v1 7 | kind: Namespace 8 | name: ${KUTTL_TEST_DELETE_NAMESPACE} 9 | error: 10 | - files/01-errors.yaml 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/README.md: -------------------------------------------------------------------------------- 1 | ### Delete namespace test 2 | 3 | * Create a namespace 4 | * Start a regular cluster in that namespace 5 | * Delete the namespace 6 | * Check that nothing remains. 7 | 8 | Note: KUTTL provides a `$NAMESPACE` var that can be used in scripts/commands, 9 | but which cannot be used in object definition yamls (like `01--cluster.yaml`). 10 | Therefore, we use a given, non-random namespace that is defined in the makefile 11 | and generated with `generate-kuttl`. 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/files/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete-namespace 6 | namespace: ${KUTTL_TEST_DELETE_NAMESPACE} 7 | spec: 8 | postgresVersion: ${KUTTL_PG_VERSION} 9 | instances: 10 | - name: instance1 11 | replicas: 1 12 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 13 | backups: 14 | pgbackrest: 15 | repos: 16 | - name: repo1 17 | volume: 18 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/files/00-create-namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: ${KUTTL_TEST_DELETE_NAMESPACE} 6 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete-namespace/files/00-created.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete-namespace 6 | namespace: ${KUTTL_TEST_DELETE_NAMESPACE} 7 | status: 8 | instances: 9 | - name: instance1 10 | readyReplicas: 1 11 | replicas: 1 12 | updatedReplicas: 1 13 | --- 14 | apiVersion: batch/v1 15 | kind: Job 16 | metadata: 17 | namespace: ${KUTTL_TEST_DELETE_NAMESPACE} 18 | labels: 19 | postgres-operator.crunchydata.com/cluster: delete-namespace 20 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 21 | status: 22 | succeeded: 1 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=delete 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=delete 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-create-cluster.yaml 5 | assert: 6 | - files/00-cluster-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/01-delete-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | delete: 4 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | name: delete 7 | error: 8 | - files/01-cluster-deleted.yaml 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/10-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=delete-with-replica 6 | - namespace: $NAMESPACE 7 | selector: postgres-operator.crunchydata.com/cluster=delete-with-replica 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/10-create-cluster-with-replicas.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/10-create-cluster-with-replicas.yaml 5 | assert: 6 | - files/10-cluster-with-replicas-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/11-delete-cluster-with-replicas.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove the cluster. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | name: delete-with-replica 9 | error: 10 | - files/11-cluster-with-replicas-deleted.yaml 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/20-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | collectors: 4 | - type: command 5 | command: kubectl -n $NAMESPACE describe pods --selector postgres-operator.crunchydata.com/cluster=delete-not-running 6 | # This shouldn't be running, so skip logs; if there's an error, we'll be able to see it in the describe 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/20-create-broken-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/20-create-broken-cluster.yaml 5 | error: 6 | - files/20-broken-cluster-not-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/21-delete-broken-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove the cluster. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | name: delete-not-running 9 | error: 10 | - files/21-broken-cluster-deleted.yaml 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/README.md: -------------------------------------------------------------------------------- 1 | ### Delete test 2 | 3 | #### Regular cluster delete (00-01) 4 | 5 | * Start a regular cluster 6 | * Delete it 7 | * Check that nothing remains. 8 | 9 | #### Delete cluster with replica (10-11) 10 | 11 | * Start a regular cluster with 2 replicas 12 | * Delete it 13 | * Check that nothing remains 14 | 15 | #### Delete a cluster that never started (20-21) 16 | 17 | * Start a cluster with a bad image 18 | * Delete it 19 | * Check that nothing remains 20 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/00-cluster-created.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete 6 | status: 7 | instances: 8 | - name: instance1 9 | readyReplicas: 1 10 | replicas: 1 11 | updatedReplicas: 1 12 | --- 13 | apiVersion: batch/v1 14 | kind: Job 15 | metadata: 16 | labels: 17 | postgres-operator.crunchydata.com/cluster: delete 18 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 19 | status: 20 | succeeded: 1 21 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/00-create-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | replicas: 1 11 | dataVolumeClaimSpec: 12 | accessModes: 13 | - "ReadWriteOnce" 14 | resources: 15 | requests: 16 | storage: 1Gi 17 | backups: 18 | pgbackrest: 19 | repos: 20 | - name: repo1 21 | volume: 22 | volumeClaimSpec: 23 | accessModes: 24 | - "ReadWriteOnce" 25 | resources: 26 | requests: 27 | storage: 1Gi 28 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/01-cluster-deleted.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete 6 | --- 7 | apiVersion: apps/v1 8 | kind: StatefulSet 9 | metadata: 10 | labels: 11 | postgres-operator.crunchydata.com/cluster: delete 12 | --- 13 | # Patroni DCS objects are not owned by the PostgresCluster. 14 | apiVersion: v1 15 | kind: Endpoints 16 | metadata: 17 | labels: 18 | postgres-operator.crunchydata.com/cluster: delete 19 | --- 20 | apiVersion: v1 21 | kind: Pod 22 | metadata: 23 | labels: 24 | postgres-operator.crunchydata.com/cluster: delete 25 | --- 26 | apiVersion: v1 27 | kind: Service 28 | metadata: 29 | labels: 30 | postgres-operator.crunchydata.com/cluster: delete 31 | --- 32 | apiVersion: v1 33 | kind: Secret 34 | metadata: 35 | labels: 36 | postgres-operator.crunchydata.com/cluster: delete 37 | --- 38 | apiVersion: v1 39 | kind: ConfigMap 40 | metadata: 41 | labels: 42 | postgres-operator.crunchydata.com/cluster: delete 43 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/10-cluster-with-replicas-created.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: delete-with-replica 6 | status: 7 | instances: 8 | - name: instance1 9 | readyReplicas: 2 10 | replicas: 2 11 | updatedReplicas: 2 12 | --- 13 | # Patroni labels and readiness happen separately. 14 | # The next step expects to find pods by their role label; wait for them here. 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | labels: 19 | postgres-operator.crunchydata.com/cluster: delete-with-replica 20 | postgres-operator.crunchydata.com/role: master 21 | --- 22 | apiVersion: v1 23 | kind: Pod 24 | metadata: 25 | labels: 26 | postgres-operator.crunchydata.com/cluster: delete-with-replica 27 | postgres-operator.crunchydata.com/role: replica 28 | --- 29 | apiVersion: batch/v1 30 | kind: Job 31 | metadata: 32 | labels: 33 | postgres-operator.crunchydata.com/cluster: delete-with-replica 34 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 35 | status: 36 | succeeded: 1 37 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/10-create-cluster-with-replicas.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: delete-with-replica 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | patroni: 8 | switchover: 9 | enabled: true 10 | instances: 11 | - name: instance1 12 | replicas: 2 13 | dataVolumeClaimSpec: 14 | accessModes: 15 | - "ReadWriteOnce" 16 | resources: 17 | requests: 18 | storage: 1Gi 19 | backups: 20 | pgbackrest: 21 | repos: 22 | - name: repo1 23 | volume: 24 | volumeClaimSpec: 25 | accessModes: 26 | - "ReadWriteOnce" 27 | resources: 28 | requests: 29 | storage: 1Gi 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/20-broken-cluster-not-created.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: delete-not-running 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/delete/files/20-create-broken-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: delete-not-running 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | image: "example.com/does-not-exist" 8 | instances: 9 | - name: instance1 10 | replicas: 1 11 | dataVolumeClaimSpec: 12 | accessModes: 13 | - "ReadWriteOnce" 14 | resources: 15 | requests: 16 | storage: 1Gi 17 | backups: 18 | pgbackrest: 19 | repos: 20 | - name: repo1 21 | volume: 22 | volumeClaimSpec: 23 | accessModes: 24 | - "ReadWriteOnce" 25 | resources: 26 | requests: 27 | storage: 1Gi 28 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/exporter-custom-queries-configmap.yaml 5 | - files/exporter-custom-queries-cluster.yaml 6 | assert: 7 | - files/exporter-custom-queries-cluster-checks.yaml 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/01--change-custom-queries.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/exporter-custom-queries-configmap-update.yaml 5 | assert: 6 | - files/exporter-custom-queries-configmap-update-checks.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/README.md: -------------------------------------------------------------------------------- 1 | # Exporter 2 | 3 | **Note**: This series of tests depends on PGO being deployed with the `AppendCustomQueries` feature gate OFF. 4 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/files/exporter-custom-queries-cluster-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-custom-queries 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: exporter-custom-queries 17 | postgres-operator.crunchydata.com/crunchy-postgres-exporter: "true" 18 | status: 19 | phase: Running 20 | --- 21 | apiVersion: v1 22 | kind: ConfigMap 23 | metadata: 24 | name: exporter-custom-queries-exporter-queries-config 25 | --- 26 | apiVersion: v1 27 | kind: ConfigMap 28 | metadata: 29 | name: custom-queries-test 30 | data: 31 | queries.yml: "# This is a test." 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/files/exporter-custom-queries-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-custom-queries 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 10 | monitoring: 11 | pgmonitor: 12 | exporter: 13 | configuration: 14 | - configMap: 15 | name: custom-queries-test 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/files/exporter-custom-queries-configmap-update-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: custom-queries-test 5 | data: 6 | queries.yml: "# This is a different test." 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/files/exporter-custom-queries-configmap-update.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: custom-queries-test 5 | data: 6 | queries.yml: "# This is a different test." 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-custom-queries/files/exporter-custom-queries-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: custom-queries-test 5 | data: 6 | queries.yml: "# This is a test." 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-no-tls/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/exporter-no-tls-cluster.yaml 5 | assert: 6 | - files/exporter-no-tls-cluster-checks.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-no-tls/files/exporter-no-tls-cluster-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-no-tls 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: exporter-no-tls 17 | postgres-operator.crunchydata.com/crunchy-postgres-exporter: "true" 18 | status: 19 | phase: Running 20 | --- 21 | apiVersion: v1 22 | kind: ConfigMap 23 | metadata: 24 | name: exporter-no-tls-exporter-queries-config 25 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-no-tls/files/exporter-no-tls-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-no-tls 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 10 | monitoring: 11 | pgmonitor: 12 | exporter: {} 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/initial-postgrescluster.yaml 5 | assert: 6 | - files/initial-postgrescluster-checks.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/02--change-password.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/update-monitoring-password.yaml 5 | assert: 6 | - files/update-monitoring-password-checks.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/files/check-restarted-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | postgres-operator.crunchydata.com/cluster: exporter-password-change 6 | postgres-operator.crunchydata.com/crunchy-postgres-exporter: "true" 7 | status: 8 | phase: Running 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/files/initial-postgrescluster-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-password-change 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: exporter-password-change 17 | postgres-operator.crunchydata.com/crunchy-postgres-exporter: "true" 18 | status: 19 | phase: Running 20 | --- 21 | apiVersion: v1 22 | kind: Secret 23 | metadata: 24 | name: exporter-password-change-monitoring 25 | labels: 26 | postgres-operator.crunchydata.com/cluster: exporter-password-change 27 | postgres-operator.crunchydata.com/role: monitoring 28 | ownerReferences: 29 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 30 | blockOwnerDeletion: true 31 | controller: true 32 | kind: PostgresCluster 33 | name: exporter-password-change 34 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/files/initial-postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-password-change 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 10 | monitoring: 11 | pgmonitor: 12 | exporter: {} 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/files/update-monitoring-password-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: exporter-password-change-monitoring 5 | labels: 6 | postgres-operator.crunchydata.com/cluster: exporter-password-change 7 | postgres-operator.crunchydata.com/role: monitoring 8 | ownerReferences: 9 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 10 | blockOwnerDeletion: true 11 | controller: true 12 | kind: PostgresCluster 13 | name: exporter-password-change 14 | data: 15 | # ensure the password is encoded to 'password' 16 | password: cGFzc3dvcmQ= 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-password-change/files/update-monitoring-password.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: exporter-password-change-monitoring 5 | labels: 6 | postgres-operator.crunchydata.com/cluster: exporter-password-change 7 | postgres-operator.crunchydata.com/role: monitoring 8 | stringData: 9 | password: password 10 | data: 11 | # Ensure data field is deleted so that password/verifier will be regenerated 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-tls/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/exporter-tls-certs.yaml 5 | - files/exporter-tls-cluster.yaml 6 | assert: 7 | - files/exporter-tls-cluster-checks.yaml 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-tls/files/exporter-tls-cluster-checks.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-tls 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: exporter-tls 17 | postgres-operator.crunchydata.com/crunchy-postgres-exporter: "true" 18 | status: 19 | phase: Running 20 | --- 21 | apiVersion: v1 22 | kind: ConfigMap 23 | metadata: 24 | name: exporter-tls-exporter-queries-config 25 | --- 26 | apiVersion: v1 27 | kind: ConfigMap 28 | metadata: 29 | name: exporter-tls-exporter-web-config 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/exporter-tls/files/exporter-tls-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: exporter-tls 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 10 | monitoring: 11 | pgmonitor: 12 | exporter: 13 | customTLSSecret: 14 | name: cluster-cert 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/01--valid-upgrade.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This upgrade is valid, but has no pgcluster to work on and should get that condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: empty-image-upgrade 7 | spec: 8 | # postgres version that is no longer available 9 | fromPostgresVersion: 11 10 | toPostgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 11 | postgresClusterName: major-upgrade-empty-image 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/01-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PGUpgrade 4 | metadata: 5 | name: empty-image-upgrade 6 | status: 7 | conditions: 8 | - type: "Progressing" 9 | status: "False" 10 | reason: "PGClusterNotFound" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/10--cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create the cluster we will do an actual upgrade on, but set the postgres version 3 | # to '10' to force a missing image scenario 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: major-upgrade-empty-image 8 | spec: 9 | # postgres version that is no longer available 10 | postgresVersion: 11 11 | config: 12 | parameters: 13 | shared_preload_libraries: pgaudit, set_user, pg_stat_statements, pgnodemx, pg_cron 14 | instances: 15 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 16 | backups: 17 | pgbackrest: 18 | repos: 19 | - name: repo1 20 | volume: 21 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/10-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # The cluster is not running due to the missing image, not due to a proper 3 | # shutdown status. 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PGUpgrade 6 | metadata: 7 | name: empty-image-upgrade 8 | status: 9 | conditions: 10 | - type: "Progressing" 11 | status: "False" 12 | reason: "PGClusterNotShutdown" 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/11--shutdown-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Shutdown the cluster -- but without the annotation. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade-empty-image 7 | spec: 8 | shutdown: true 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/11-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Since the cluster is missing the annotation, we get this condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: empty-image-upgrade 7 | status: 8 | conditions: 9 | - type: "Progressing" 10 | status: "False" 11 | reason: "PGClusterPrimaryNotIdentified" 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/12--start-and-update-version.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Update the postgres version and restart the cluster. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade-empty-image 7 | spec: 8 | shutdown: false 9 | postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 10 | --- 11 | apiVersion: postgres-operator.crunchydata.com/v1beta1 12 | kind: PGUpgrade 13 | metadata: 14 | name: empty-image-upgrade 15 | spec: 16 | # update postgres version 17 | fromPostgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/12-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready and the replica backup to complete 3 | # by waiting for the status to signal pods ready and pgbackrest stanza created 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: major-upgrade-empty-image 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 10 | status: 11 | instances: 12 | - name: '00' 13 | replicas: 1 14 | readyReplicas: 1 15 | updatedReplicas: 1 16 | pgbackrest: 17 | repos: 18 | - name: repo1 19 | replicaCreateBackupComplete: true 20 | stanzaCreated: true 21 | --- 22 | # Even when the cluster exists, the pgupgrade is not progressing because the cluster is not shutdown 23 | apiVersion: postgres-operator.crunchydata.com/v1beta1 24 | kind: PGUpgrade 25 | metadata: 26 | name: empty-image-upgrade 27 | status: 28 | conditions: 29 | - type: "Progressing" 30 | status: "False" 31 | reason: "PGClusterNotShutdown" 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/13--shutdown-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Shutdown the cluster -- but without the annotation. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade-empty-image 7 | spec: 8 | shutdown: true 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/13-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Since the cluster is missing the annotation, we get this condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: empty-image-upgrade 7 | status: 8 | conditions: 9 | - type: "Progressing" 10 | status: "False" 11 | reason: "PGClusterMissingRequiredAnnotation" 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/14--annotate-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Annotate the cluster for an upgrade. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade-empty-image 7 | annotations: 8 | postgres-operator.crunchydata.com/allow-upgrade: empty-image-upgrade 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/14-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Now that the postgres cluster is shut down and annotated, the pgupgrade 3 | # can finish reconciling. We know the reconciliation is complete when 4 | # the pgupgrade status is succeeded and the postgres cluster status 5 | # has the updated version. 6 | apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PGUpgrade 8 | metadata: 9 | name: empty-image-upgrade 10 | status: 11 | conditions: 12 | - type: "Progressing" 13 | status: "False" 14 | - type: "Succeeded" 15 | status: "True" 16 | --- 17 | apiVersion: postgres-operator.crunchydata.com/v1beta1 18 | kind: PostgresCluster 19 | metadata: 20 | name: major-upgrade-empty-image 21 | status: 22 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/15--start-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Once the pgupgrade is finished, update the version and set shutdown to false 3 | # in the postgres cluster 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: major-upgrade-empty-image 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 10 | shutdown: false 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/15-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready with the target Postgres version. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade-empty-image 7 | status: 8 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 9 | instances: 10 | - name: '00' 11 | replicas: 1 12 | readyReplicas: 1 13 | updatedReplicas: 1 14 | pgbackrest: 15 | repos: 16 | - name: repo1 17 | replicaCreateBackupComplete: true 18 | stanzaCreated: true 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/16-check-pgbackrest.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # Check that the pgbackrest setup has successfully completed 5 | - script: | 6 | kubectl -n "${NAMESPACE}" exec "statefulset.apps/major-upgrade-empty-image-repo-host" -c pgbackrest -- pgbackrest check --stanza=db 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade-missing-image/17-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: major-upgrade-empty-image-after 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/02--valid-upgrade.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This upgrade is valid, but has no pgcluster to work on and should get that condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: major-upgrade-do-it 7 | spec: 8 | fromPostgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 9 | toPostgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 10 | postgresClusterName: major-upgrade 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/02-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PGUpgrade 4 | metadata: 5 | name: major-upgrade-do-it 6 | status: 7 | conditions: 8 | - type: "Progressing" 9 | status: "False" 10 | reason: "PGClusterNotFound" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/10--already-updated-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create a cluster that is already at the correct version 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade 7 | spec: 8 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 9 | instances: 10 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 11 | backups: 12 | pgbackrest: 13 | repos: 14 | - name: repo1 15 | volume: 16 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/10-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # pgupgrade should exit since the cluster is already at the requested version 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: major-upgrade-do-it 7 | status: 8 | conditions: 9 | - type: "Progressing" 10 | status: "False" 11 | reason: "PGUpgradeResolved" 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/11-delete-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Delete the existing cluster. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | name: major-upgrade 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/30--cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create the cluster we will do an actual upgrade on 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade 7 | spec: 8 | postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 9 | config: 10 | parameters: 11 | shared_preload_libraries: pgaudit, set_user, pg_stat_statements, pgnodemx, pg_cron 12 | instances: 13 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 14 | replicas: 3 15 | backups: 16 | pgbackrest: 17 | repos: 18 | - name: repo1 19 | volume: 20 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 21 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/30-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready and the replica backup to complete 3 | # by waiting for the status to signal pods ready and pgbackrest stanza created 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: major-upgrade 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 10 | status: 11 | instances: 12 | - name: '00' 13 | replicas: 3 14 | readyReplicas: 3 15 | updatedReplicas: 3 16 | pgbackrest: 17 | repos: 18 | - name: repo1 19 | replicaCreateBackupComplete: true 20 | stanzaCreated: true 21 | --- 22 | # Even when the cluster exists, the pgupgrade is not progressing because the cluster is not shutdown 23 | apiVersion: postgres-operator.crunchydata.com/v1beta1 24 | kind: PGUpgrade 25 | metadata: 26 | name: major-upgrade-do-it 27 | status: 28 | conditions: 29 | - type: "Progressing" 30 | status: "False" 31 | reason: "PGClusterNotShutdown" 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/31-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: major-upgrade-before 6 | status: 7 | succeeded: 1 8 | --- 9 | apiVersion: batch/v1 10 | kind: Job 11 | metadata: 12 | name: major-upgrade-before-replica 13 | status: 14 | succeeded: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/32--shutdown-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Shutdown the cluster -- but without the annotation. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade 7 | spec: 8 | shutdown: true 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/32-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Since the cluster is missing the annotation, we get this condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: major-upgrade-do-it 7 | status: 8 | conditions: 9 | - type: "Progressing" 10 | status: "False" 11 | reason: "PGClusterMissingRequiredAnnotation" 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/33--annotate-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Annotate the cluster for an upgrade. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade 7 | annotations: 8 | postgres-operator.crunchydata.com/allow-upgrade: major-upgrade-do-it 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/33-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Now that the postgres cluster is shut down and annotated, the pgupgrade 3 | # can finish reconciling. We know the reconciling is complete when 4 | # the pgupgrade status is succeeded and the postgres cluster status 5 | # has the updated version. 6 | apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PGUpgrade 8 | metadata: 9 | name: major-upgrade-do-it 10 | status: 11 | conditions: 12 | - type: "Progressing" 13 | status: "False" 14 | - type: "Succeeded" 15 | status: "True" 16 | --- 17 | apiVersion: postgres-operator.crunchydata.com/v1beta1 18 | kind: PostgresCluster 19 | metadata: 20 | name: major-upgrade 21 | status: 22 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/34--restart-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Once the pgupgrade is finished, update the version and set shutdown to false 3 | # in the postgres cluster 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: major-upgrade 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 10 | shutdown: false 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/34-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready with the target Postgres version. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: major-upgrade 7 | status: 8 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 9 | instances: 10 | - name: '00' 11 | replicas: 3 12 | readyReplicas: 3 13 | updatedReplicas: 3 14 | pgbackrest: 15 | repos: 16 | - name: repo1 17 | replicaCreateBackupComplete: true 18 | stanzaCreated: true 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/35-check-pgbackrest-and-replica.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # Check that the pgbackrest setup has successfully completed 5 | - script: | 6 | kubectl -n "${NAMESPACE}" exec "statefulset.apps/major-upgrade-repo-host" -c pgbackrest -- pgbackrest check --stanza=db 7 | # Check that the replica data dir has been successfully cleaned 8 | - script: | 9 | # Check that the old pg folders do not exist on the replica 10 | REPLICA=$(kubectl get pod -l=postgres-operator.crunchydata.com/role=replica -n "${NAMESPACE}" -o=jsonpath='{ .items[0].metadata.name }') 11 | kubectl -n "${NAMESPACE}" exec "${REPLICA}" -c database -- [ ! -d "pgdata/pg${KUTTL_PG_UPGRADE_FROM_VERSION}" ] 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/major-upgrade/36-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: major-upgrade-after 6 | status: 7 | succeeded: 1 8 | --- 9 | apiVersion: batch/v1 10 | kind: Job 11 | metadata: 12 | name: major-upgrade-after-replica 13 | status: 14 | succeeded: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: created-without-backups 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/01-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: created-without-backups-repo1 5 | --- 6 | apiVersion: apps/v1 7 | kind: StatefulSet 8 | metadata: 9 | name: created-without-backups-repo-host 10 | --- 11 | apiVersion: v1 12 | kind: ConfigMap 13 | metadata: 14 | name: created-without-backups-pgbackrest-config 15 | --- 16 | apiVersion: v1 17 | kind: ServiceAccount 18 | metadata: 19 | name: created-without-backups-pgbackrest 20 | --- 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | kind: RoleBinding 23 | metadata: 24 | name: created-without-backups-pgbackrest 25 | --- 26 | apiVersion: rbac.authorization.k8s.io/v1 27 | kind: Role 28 | metadata: 29 | name: created-without-backups-pgbackrest 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backups) 7 | 8 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 9 | -- psql -qb --set ON_ERROR_STOP=1 --file=- <<'SQL' 10 | DO $$ 11 | BEGIN 12 | ASSERT current_setting('archive_command') LIKE 'true', 13 | format('expected "true", got %L', current_setting('archive_command')); 14 | END $$ 15 | SQL 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/03-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backups) 7 | 8 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 9 | -- psql -qb --set ON_ERROR_STOP=1 \ 10 | -c "CREATE TABLE important (data) AS VALUES ('treasure');" 11 | 12 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 13 | -- psql -qb --set ON_ERROR_STOP=1 \ 14 | -c "CHECKPOINT;" 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/04--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: created-without-backups 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 2 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/05-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | postgres-operator.crunchydata.com/cluster: created-without-backups 6 | postgres-operator.crunchydata.com/data: postgres 7 | postgres-operator.crunchydata.com/instance-set: instance1 8 | postgres-operator.crunchydata.com/role: replica 9 | status: 10 | containerStatuses: 11 | - ready: true 12 | - ready: true 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/06-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backups \ 7 | -l postgres-operator.crunchydata.com/role=replica) 8 | 9 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 10 | -- psql -qb --set ON_ERROR_STOP=1 --file=- <<'SQL' 11 | DO $$ 12 | DECLARE 13 | everything jsonb; 14 | BEGIN 15 | SELECT jsonb_agg(important) INTO everything FROM important; 16 | ASSERT everything = '[{"data":"treasure"}]', format('got %L', everything); 17 | END $$ 18 | SQL 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/10--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: created-without-backups 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | repos: 19 | - name: repo1 20 | volume: 21 | volumeClaimSpec: 22 | accessModes: 23 | - "ReadWriteOnce" 24 | resources: 25 | requests: 26 | storage: 1Gi 27 | 28 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/11-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backup \ 7 | -l postgres-operator.crunchydata.com/instance-set=instance1 \ 8 | -l postgres-operator.crunchydata.com/patroni=created-without-backups-ha \ 9 | -l postgres-operator.crunchydata.com/role=master) 10 | 11 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 12 | -- psql -qb --set ON_ERROR_STOP=1 --file=- <<'SQL' 13 | DO $$ 14 | BEGIN 15 | ASSERT current_setting('archive_command') LIKE 'pgbackrest --stanza=db archive-push "%p"', 16 | format('expected "pgbackrest --stanza=db archive-push \"%p\"", got %L', current_setting('archive_command')); 17 | END $$ 18 | SQL 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/20--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - command: |- 5 | kubectl patch postgrescluster created-without-backups --type 'merge' -p '{"spec":{"backups": null}}' 6 | namespaced: true 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/21-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backup \ 7 | -l postgres-operator.crunchydata.com/instance-set=instance1 \ 8 | -l postgres-operator.crunchydata.com/patroni=created-without-backups-ha \ 9 | -l postgres-operator.crunchydata.com/role=master) 10 | 11 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 12 | -- psql -qb --set ON_ERROR_STOP=1 --file=- <<'SQL' 13 | DO $$ 14 | BEGIN 15 | ASSERT current_setting('archive_command') LIKE 'pgbackrest --stanza=db archive-push "%p"', 16 | format('expected "pgbackrest --stanza=db archive-push \"%p\"", got %L', current_setting('archive_command')); 17 | END $$ 18 | SQL 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/22--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - command: kubectl annotate postgrescluster created-without-backups postgres-operator.crunchydata.com/authorizeBackupRemoval="true" 5 | namespaced: true 6 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/23-assert.yaml: -------------------------------------------------------------------------------- 1 | # It should be possible to turn backups back on. 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: created-without-backups 6 | status: 7 | instances: 8 | - name: instance1 9 | pgbackrest: {} 10 | --- 11 | apiVersion: v1 12 | kind: PersistentVolumeClaim 13 | metadata: 14 | labels: 15 | postgres-operator.crunchydata.com/cluster: created-without-backups 16 | postgres-operator.crunchydata.com/data: postgres 17 | postgres-operator.crunchydata.com/instance-set: instance1 18 | postgres-operator.crunchydata.com/role: pgdata 19 | --- 20 | apiVersion: apps/v1 21 | kind: StatefulSet 22 | metadata: 23 | labels: 24 | postgres-operator.crunchydata.com/cluster: created-without-backups 25 | postgres-operator.crunchydata.com/data: postgres 26 | postgres-operator.crunchydata.com/instance-set: instance1 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/24-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: created-without-backups-repo1 5 | --- 6 | apiVersion: apps/v1 7 | kind: StatefulSet 8 | metadata: 9 | name: created-without-backups-repo-host 10 | --- 11 | apiVersion: v1 12 | kind: ConfigMap 13 | metadata: 14 | name: created-without-backups-pgbackrest-config 15 | --- 16 | apiVersion: v1 17 | kind: ServiceAccount 18 | metadata: 19 | name: created-without-backups-pgbackrest 20 | --- 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | kind: RoleBinding 23 | metadata: 24 | name: created-without-backups-pgbackrest 25 | --- 26 | apiVersion: rbac.authorization.k8s.io/v1 27 | kind: Role 28 | metadata: 29 | name: created-without-backups-pgbackrest 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/25-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 6 | -l postgres-operator.crunchydata.com/cluster=created-without-backups) 7 | 8 | kubectl exec --stdin "${pod}" --namespace "${NAMESPACE}" -c database \ 9 | -- psql -qb --set ON_ERROR_STOP=1 --file=- <<'SQL' 10 | DO $$ 11 | BEGIN 12 | ASSERT current_setting('archive_command') LIKE 'true', 13 | format('expected "true", got %L', current_setting('archive_command')); 14 | END $$ 15 | SQL 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/optional-backups/README.md: -------------------------------------------------------------------------------- 1 | ## Optional backups 2 | 3 | ### Steps 4 | 5 | 00-02. Create cluster without backups, check that expected K8s objects do/don't exist, e.g., repo-host sts doesn't exist; check that the archive command is `true` 6 | 7 | 03-06. Add data and a replica; check that the data successfully replicates to the replica. 8 | 9 | 10-11. Update cluster to add backups, check that expected K8s objects do/don't exist, e.g., repo-host sts exists; check that the archive command is set to the usual 10 | 11 | 20-21. Update cluster to remove backups but without annotation, check that no changes were made, including to the archive command 12 | 13 | 22-25. Annotate cluster to remove existing backups, check that expected K8s objects do/don't exist, e.g., repo-host sts doesn't exist; check that the archive command is `true` 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00--create-cluster.yaml 5 | assert: 6 | - files/00-cluster-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/01--add-instrumentation-to-postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/01--add-instrumentation.yaml 5 | assert: 6 | - files/01-instrumentation-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/03--backup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/03--annotate-cluster.yaml 5 | assert: 6 | - files/03-backup-completed.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/07--add-instrumentation-to-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/07--add-instrumentation.yaml 5 | assert: 6 | - files/07-instrumentation-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/09--add-custom-queries.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/09--add-custom-queries.yaml 5 | assert: 6 | - files/09-custom-queries-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/11--add-per-db-metrics-to-postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/11--add-per-db-metrics.yaml 5 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/13--add-second-per-db-metrics-to-postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/13--add-per-db-metrics.yaml 5 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/15--remove-per-db-metrics-from-postgrescluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/15--remove-per-db-metrics.yaml 5 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/17--add-custom-queries-per-db.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/17--add-custom-queries-per-db.yaml 5 | assert: 6 | - files/17-custom-queries-per-db-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/19--add-logs-exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/19--add-logs-exporter.yaml 5 | assert: 6 | - files/19-logs-exporter-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/21--cluster-no-backups.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/21--create-cluster.yaml 5 | assert: 6 | - files/21-cluster-created.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/23--cluster-add-backups.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/23--add-backups.yaml 5 | assert: 6 | - files/23-backups-added.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/24--remove-backups.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - command: |- 5 | kubectl patch postgrescluster otel-cluster-no-backups --type 'merge' -p '{"spec":{"backups": null}}' 6 | namespaced: true 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/25--annotate-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - command: kubectl annotate postgrescluster otel-cluster-no-backups postgres-operator.crunchydata.com/authorizeBackupRemoval="true" 5 | namespaced: true 6 | assert: 7 | - files/25-backups-removed.yaml 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/01--add-instrumentation.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | manual: 19 | repoName: repo1 20 | options: 21 | - --type=diff 22 | repos: 23 | - name: repo1 24 | volume: 25 | volumeClaimSpec: 26 | accessModes: 27 | - "ReadWriteOnce" 28 | resources: 29 | requests: 30 | storage: 1Gi 31 | config: 32 | parameters: 33 | log_min_messages: INFO 34 | proxy: 35 | pgBouncer: {} 36 | instrumentation: {} 37 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/03--annotate-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Annotate the cluster to trigger a backup. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: otel-cluster 7 | annotations: 8 | postgres-operator.crunchydata.com/pgbackrest-backup: do-it 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/03-backup-completed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | labels: 5 | postgres-operator.crunchydata.com/cluster: otel-cluster 6 | postgres-operator.crunchydata.com/pgbackrest-backup: manual 7 | status: 8 | succeeded: 1 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/07--add-instrumentation.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PGAdmin 4 | metadata: 5 | name: otel-pgadmin 6 | spec: 7 | users: 8 | - username: otel@example.com 9 | role: Administrator 10 | passwordRef: 11 | name: pgadmin-password-secret 12 | key: otel-password 13 | dataVolumeClaimSpec: 14 | accessModes: 15 | - "ReadWriteOnce" 16 | resources: 17 | requests: 18 | storage: 1Gi 19 | serverGroups: 20 | - name: supply 21 | # An empty selector selects all postgresclusters in the Namespace 22 | postgresClusterSelector: {} 23 | config: 24 | settings: 25 | AUTHENTICATION_SOURCES: ['internal'] 26 | instrumentation: {} 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/11--add-per-db-metrics.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster 6 | spec: 7 | users: 8 | - name: ash 9 | databases: 10 | - pikachu 11 | - name: brock 12 | databases: 13 | - onix 14 | instrumentation: 15 | metrics: 16 | perDBMetricTargets: 17 | - pikachu 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/13--add-per-db-metrics.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster 6 | spec: 7 | instrumentation: 8 | metrics: 9 | perDBMetricTargets: 10 | - pikachu 11 | - onix 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/15--remove-per-db-metrics.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster 6 | spec: 7 | instrumentation: 8 | metrics: 9 | customQueries: 10 | remove: 11 | - ccp_connection_stats_active 12 | - ccp_database_size_bytes 13 | - ccp_table_size_bytes 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/21--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster-no-backups 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | instrumentation: {} 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/21-cluster-created.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: otel-cluster-no-backups 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/data: postgres 17 | postgres-operator.crunchydata.com/role: master 18 | postgres-operator.crunchydata.com/cluster: otel-cluster-no-backups 19 | postgres-operator.crunchydata.com/crunchy-otel-collector: "true" 20 | status: 21 | containerStatuses: 22 | - name: collector 23 | ready: true 24 | started: true 25 | - name: database 26 | ready: true 27 | started: true 28 | - name: replication-cert-copy 29 | ready: true 30 | started: true 31 | phase: Running 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: otel-cluster-no-backups-primary 37 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/23--add-backups.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: otel-cluster-no-backups 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | manual: 19 | repoName: repo1 20 | options: 21 | - --type=diff 22 | repos: 23 | - name: repo1 24 | volume: 25 | volumeClaimSpec: 26 | accessModes: 27 | - "ReadWriteOnce" 28 | resources: 29 | requests: 30 | storage: 1Gi 31 | instrumentation: {} 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/otel-logging-and-metrics/files/25-backups-removed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: otel-cluster-no-backups 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/data: postgres 17 | postgres-operator.crunchydata.com/role: master 18 | postgres-operator.crunchydata.com/cluster: otel-cluster-no-backups 19 | postgres-operator.crunchydata.com/crunchy-otel-collector: "true" 20 | status: 21 | containerStatuses: 22 | - name: collector 23 | ready: true 24 | started: true 25 | - name: database 26 | ready: true 27 | started: true 28 | - name: replication-cert-copy 29 | ready: true 30 | started: true 31 | phase: Running 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: otel-cluster-no-backups-primary 37 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: password-change 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: password-change 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: password-change-primary 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/01--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | - name: PGURI 20 | valueFrom: { secretKeyRef: { name: password-change-pguser-password-change, key: uri } } 21 | 22 | # Do not wait indefinitely. 23 | - { name: PGCONNECT_TIMEOUT, value: '5' } 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/02--secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-password-change 5 | data: 6 | # Hardcoding the password as "datalake" 7 | password: ZGF0YWxha2U= 8 | verifier: "" 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/02-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-password-change 5 | data: 6 | # `02-secret.yaml` changes the password and removes the verifier field, 7 | # so when PGO reconciles the secret, it should fill in the empty verifier field; 8 | # if it does not fill in the verifier field by a certain time this step will error 9 | # and KUTTL will mark the test as failed. 10 | verifier: "" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/03--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri2 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | # The ./02-errors.yaml checks that the secret is not in the state that we set it to 20 | # in the ./02-secret.yaml file, i.e., the secret has been reconciled by PGO, 21 | # so the uri field of the secret should be updated with the new password by this time 22 | - name: PGURI 23 | valueFrom: { secretKeyRef: { name: password-change-pguser-password-change, key: uri } } 24 | 25 | # Do not wait indefinitely. 26 | - { name: PGCONNECT_TIMEOUT, value: '5' } 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/03-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect2 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri2 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/04--secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: password-change-pguser-password-change 6 | # Updating the password with the stringData field and an md5-based verifier 7 | stringData: 8 | password: infopond 9 | verifier: "md585eb8fa4f697b2ea949d3aba788e8631" 10 | uri: "" 11 | --- 12 | # Enable authenticating with MD5 passwords 13 | apiVersion: postgres-operator.crunchydata.com/v1beta1 14 | kind: PostgresCluster 15 | metadata: 16 | name: password-change 17 | spec: 18 | authentication: 19 | rules: 20 | - connection: hostssl 21 | method: md5 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/04-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-password-change 5 | data: 6 | # `04-secret.yaml` changes the password and removes the verifier field, 7 | # so when PGO reconciles the secret, it should fill in the empty verifier field; 8 | # if it does not fill in the verifier field by a certain time this step will error 9 | # and KUTTL will mark the test as failed. 10 | uri: "" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/05--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri3 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | # The ./04-errors.yaml checks that the secret is not in the state that we set it to 20 | # in the ./04-secret.yaml file, i.e., the secret has been reconciled by PGO, 21 | # so the uri field of the secret should be updated with the new password by this time 22 | - name: PGURI 23 | valueFrom: { secretKeyRef: { name: password-change-pguser-password-change, key: uri } } 24 | 25 | # Do not wait indefinitely. 26 | - { name: PGCONNECT_TIMEOUT, value: '5' } 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/05-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect3 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri3 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/06--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: password-change 5 | spec: 6 | # Adding a custom user to the spec 7 | users: 8 | - name: rhino 9 | databases: 10 | - rhino 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/06-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: password-change 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: password-change-primary 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/07--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri4 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | - name: PGURI 20 | valueFrom: { secretKeyRef: { name: password-change-pguser-rhino, key: uri } } 21 | 22 | # Do not wait indefinitely. 23 | - { name: PGCONNECT_TIMEOUT, value: '5' } 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/07-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect4 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri4 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/08--secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-rhino 5 | data: 6 | # Hardcoding the password as "datalake" 7 | password: ZGF0YWxha2U= 8 | verifier: "" 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/08-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-rhino 5 | data: 6 | # `08-secret.yaml` changes the password and removes the verifier field, 7 | # so when PGO reconciles the secret, it should fill in the empty verifier field; 8 | # if it does not fill in the verifier field by a certain time this step will error 9 | # and KUTTL will mark the test as failed. 10 | verifier: "" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/09--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri5 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | # The ./08-errors.yaml checks that the secret is not in the state that we set it to 20 | # in the ./08-secret.yaml file, i.e., the secret has been reconciled by PGO, 21 | # so the uri field of the secret should be updated with the new password by this time 22 | - name: PGURI 23 | valueFrom: { secretKeyRef: { name: password-change-pguser-rhino, key: uri } } 24 | 25 | # Do not wait indefinitely. 26 | - { name: PGCONNECT_TIMEOUT, value: '5' } 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/09-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect5 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri5 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/10--secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-rhino 5 | # Updating the password with the stringData field and a scram verifier 6 | stringData: 7 | password: infopond 8 | verifier: "SCRAM-SHA-256$4096:RI03PMRQH2oAFMH6AOQHdA==$D74VOn98ErW3J8CIiFYldUVO+kjsXj+Ju7jhmMURHQo=:c5hC/1V2TYNnoJ6VcaSJCcoGQ2eTcYJBP/pfKFv+k54=" 9 | uri: "" 10 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/10-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: password-change-pguser-rhino 5 | data: 6 | # `10-secret.yaml` changes the password and removes the verifier field, 7 | # so when PGO reconciles the secret, it should fill in the empty verifier field; 8 | # if it does not fill in the verifier field by a certain time this step will error 9 | # and KUTTL will mark the test as failed. 10 | uri: "" 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/11--psql-connect-uri.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect-uri6 5 | spec: 6 | backoffLimit: 6 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: psql 12 | image: ${KUTTL_PSQL_IMAGE} 13 | command: 14 | - psql 15 | - "$(PGURI)" 16 | - -c 17 | - "select version();" 18 | env: 19 | # The ./10-errors.yaml checks that the secret is not in the state that we set it to 20 | # in the ./10-secret.yaml file, i.e., the secret has been reconciled by PGO, 21 | # so the uri field of the secret should be updated with the new password by this time 22 | - name: PGURI 23 | valueFrom: { secretKeyRef: { name: password-change-pguser-rhino, key: uri } } 24 | 25 | # Do not wait indefinitely. 26 | - { name: PGCONNECT_TIMEOUT, value: '5' } 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/password-change/11-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect6 5 | status: 6 | succeeded: 1 7 | --- 8 | apiVersion: batch/v1 9 | kind: Job 10 | metadata: 11 | name: psql-connect-uri6 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: pgbackrest-backup-standby 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | global: 19 | backup-standby: "y" 20 | repos: 21 | - name: repo1 22 | volume: 23 | volumeClaimSpec: 24 | accessModes: 25 | - "ReadWriteOnce" 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: pgbackrest-backup-standby 5 | status: 6 | pgbackrest: 7 | repoHost: 8 | apiVersion: apps/v1 9 | kind: StatefulSet 10 | ready: true 11 | repos: 12 | - bound: true 13 | name: repo1 14 | --- 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | labels: 19 | postgres-operator.crunchydata.com/cluster: pgbackrest-backup-standby 20 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 21 | postgres-operator.crunchydata.com/pgbackrest-repo: repo1 22 | status: 23 | phase: Failed 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/01--check-backup-logs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # First, find at least one backup job pod. 5 | # Then, check the logs for the 'unable to find standby cluster' line. 6 | # If this line isn't found, exit 1. 7 | - script: | 8 | retry() { bash -ceu 'printf "$1\nSleeping...\n" && sleep 5' - "$@"; } 9 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 10 | 11 | pod=$(kubectl get pods -o name -n "${NAMESPACE}" \ 12 | -l postgres-operator.crunchydata.com/cluster=pgbackrest-backup-standby \ 13 | -l postgres-operator.crunchydata.com/pgbackrest-backup=replica-create) 14 | [ "$pod" = "" ] && retry "Pod not found" && exit 1 15 | 16 | logs=$(kubectl logs "${pod}" --namespace "${NAMESPACE}") 17 | { contains "${logs}" 'unable to find standby cluster - cannot proceed'; } || { 18 | echo 'did not find expected standby cluster error ' 19 | exit 1 20 | } 21 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/02--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: pgbackrest-backup-standby 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 2 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | global: 19 | backup-standby: "y" 20 | repos: 21 | - name: repo1 22 | volume: 23 | volumeClaimSpec: 24 | accessModes: 25 | - "ReadWriteOnce" 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: pgbackrest-backup-standby 5 | status: 6 | pgbackrest: 7 | repoHost: 8 | apiVersion: apps/v1 9 | kind: StatefulSet 10 | ready: true 11 | repos: 12 | - bound: true 13 | name: repo1 14 | replicaCreateBackupComplete: true 15 | stanzaCreated: true 16 | --- 17 | apiVersion: batch/v1 18 | kind: Job 19 | metadata: 20 | labels: 21 | postgres-operator.crunchydata.com/cluster: pgbackrest-backup-standby 22 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 23 | postgres-operator.crunchydata.com/pgbackrest-repo: repo1 24 | status: 25 | succeeded: 1 26 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-backup-standby/README.md: -------------------------------------------------------------------------------- 1 | ### pgBackRest backup-standby test 2 | 3 | * 00: Create a cluster with 'backup-standby' set to 'y' but with only one replica. 4 | * 01: Check the backup Job Pod logs for the expected error. 5 | * 02: Update the cluster to have 2 replicas and verify that the cluster can initialize successfully and the backup job can complete. 6 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/01-pgbackrest-connect.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # When the cluster comes up, only the repo in the 0th position has activated with a backup, 5 | # so the pgbackrest status should be "mixed" and there should be only one backup 6 | - script: CLUSTER=init-pgbackrest ../../scripts/pgbackrest-initialization.sh "mixed" 1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/02--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - command: kubectl annotate postgrescluster init-pgbackrest postgres-operator.crunchydata.com/pgbackrest-backup="manual" 5 | namespaced: true 6 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/02-assert.yaml: -------------------------------------------------------------------------------- 1 | # Manual backup job should have pushed to repo2 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/cluster: init-pgbackrest 7 | postgres-operator.crunchydata.com/pgbackrest-backup: manual 8 | postgres-operator.crunchydata.com/pgbackrest-repo: repo2 9 | status: 10 | succeeded: 1 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/03-pgbackrest-connect.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # Now that a manual backup has been pushed to repo2, the pgbackrest status should be "ok" 5 | # and there should be two backups 6 | - script: CLUSTER=init-pgbackrest ../../scripts/pgbackrest-initialization.sh "ok" 2 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/04-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: init-pgbackrest 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 2 9 | replicas: 2 10 | updatedReplicas: 2 11 | pgbackrest: 12 | repoHost: 13 | apiVersion: apps/v1 14 | kind: StatefulSet 15 | ready: true 16 | repos: 17 | # Assert that the status has the two repos, with only the first having the `replicaCreateBackupComplete` field 18 | - bound: true 19 | name: repo1 20 | replicaCreateBackupComplete: true 21 | stanzaCreated: true 22 | - bound: true 23 | name: repo2 24 | stanzaCreated: true 25 | --- 26 | apiVersion: batch/v1 27 | kind: Job 28 | metadata: 29 | labels: 30 | postgres-operator.crunchydata.com/cluster: init-pgbackrest 31 | postgres-operator.crunchydata.com/pgbackrest-backup: replica-create 32 | postgres-operator.crunchydata.com/pgbackrest-repo: repo1 33 | status: 34 | succeeded: 1 35 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/05-pgbackrest-connect.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | # Assumes the cluster only has a single replica 6 | NEW_REPLICA=$( 7 | kubectl get pod --namespace "${NAMESPACE}" \ 8 | --output name --selector ' 9 | postgres-operator.crunchydata.com/cluster=init-pgbackrest, 10 | postgres-operator.crunchydata.com/role=replica' 11 | ) 12 | 13 | LIST=$( 14 | kubectl exec --namespace "${NAMESPACE}" "${NEW_REPLICA}" -- \ 15 | ls /pgdata/pg${KUTTL_PG_VERSION}/ 16 | ) 17 | 18 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 19 | { 20 | !(contains "${LIST}" 'recovery.signal') 21 | } || { 22 | echo >&2 'Signal file(s) found' 23 | echo "${LIST}" 24 | exit 1 25 | } 26 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/06--check-spool-path.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | PRIMARY=$( 6 | kubectl get pod --namespace "${NAMESPACE}" \ 7 | --output name --selector ' 8 | postgres-operator.crunchydata.com/role=master' 9 | ) 10 | 11 | LIST=$( 12 | kubectl exec --namespace "${NAMESPACE}" -c database "${PRIMARY}" -- \ 13 | ls -l /pgdata 14 | ) 15 | 16 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 17 | contains "$LIST" "pgbackrest-spool" || exit 1 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-init/README.md: -------------------------------------------------------------------------------- 1 | ### pgBackRest Init test 2 | 3 | * 00: Create a cluster with two PVC repos and set up for manual backups to go to the second; verify that the PVCs exist and that the backup job completed successfully 4 | * 01: Run pgbackrest-initialization.sh, which checks that the status matches the expected status of `mixed` (because the second repo in the repo list has not yet been pushed to) and that there is only one full backup 5 | * 02: Use `kubectl` to annotate the cluster to initiate a manual backup; verify that the job completed successfully 6 | * 03: Rerun pgbackrest-initialization.sh, now expecting the status to be `ok` since both repos have been pushed to and there to be two full backups 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/01--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create a cluster with a single pgBackRest repository and some parameters that 3 | # require attention during PostgreSQL recovery. 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: original 8 | labels: { postgres-operator-test: kuttl } 9 | spec: 10 | postgresVersion: ${KUTTL_PG_VERSION} 11 | config: 12 | parameters: 13 | max_connections: 200 14 | instances: 15 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 16 | replicas: 2 17 | backups: 18 | pgbackrest: 19 | manual: 20 | repoName: repo1 21 | repos: 22 | - name: repo1 23 | volume: 24 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 25 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/01-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the replica backup to complete. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: original 7 | status: 8 | pgbackrest: 9 | repos: 10 | - name: repo1 11 | replicaCreateBackupComplete: true 12 | stanzaCreated: true 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/02--create-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create some data that will be restored. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: original-data 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | backoffLimit: 3 10 | template: 11 | metadata: 12 | labels: { postgres-operator-test: kuttl } 13 | spec: 14 | restartPolicy: Never 15 | containers: 16 | - name: psql 17 | image: ${KUTTL_PSQL_IMAGE} 18 | env: 19 | - name: PGURI 20 | valueFrom: { secretKeyRef: { name: original-pguser-original, key: uri } } 21 | 22 | # Do not wait indefinitely. 23 | - { name: PGCONNECT_TIMEOUT, value: '5' } 24 | 25 | command: 26 | - psql 27 | - $(PGURI) 28 | - --set=ON_ERROR_STOP=1 29 | - --command 30 | - | 31 | CREATE SCHEMA "original"; 32 | CREATE TABLE important (data) AS VALUES ('treasure'); 33 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/02-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: original-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/03--backup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # Annotate the cluster to trigger a backup. 6 | - script: | 7 | kubectl annotate --namespace="${NAMESPACE}" postgrescluster/original \ 8 | 'postgres-operator.crunchydata.com/pgbackrest-backup=one' 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/03-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the backup job to complete. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | annotations: 7 | postgres-operator.crunchydata.com/pgbackrest-backup: one 8 | labels: 9 | postgres-operator.crunchydata.com/cluster: original 10 | postgres-operator.crunchydata.com/pgbackrest-backup: manual 11 | postgres-operator.crunchydata.com/pgbackrest-repo: repo1 12 | status: 13 | succeeded: 1 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/04--clone-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Clone the cluster using a pgBackRest restore. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: clone-one 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | dataSource: 10 | postgresCluster: 11 | clusterName: original 12 | repoName: repo1 13 | 14 | postgresVersion: ${KUTTL_PG_VERSION} 15 | instances: 16 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 17 | backups: 18 | pgbackrest: 19 | repos: 20 | - name: repo1 21 | volume: 22 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/04-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the clone cluster to come online. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: clone-one 7 | status: 8 | instances: 9 | - name: '00' 10 | replicas: 1 11 | readyReplicas: 1 12 | updatedReplicas: 1 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/05-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: clone-one-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/06--delete-clone.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove the cloned cluster. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | name: clone-one 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/07--annotate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Annotate the cluster with the timestamp at which PostgreSQL last started. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | commands: 6 | - script: | 7 | PRIMARY=$( 8 | kubectl get pod --namespace "${NAMESPACE}" \ 9 | --output name --selector ' 10 | postgres-operator.crunchydata.com/cluster=original, 11 | postgres-operator.crunchydata.com/role=master' 12 | ) 13 | START=$( 14 | kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" \ 15 | -- psql -qAt --command 'SELECT pg_postmaster_start_time()' 16 | ) 17 | kubectl annotate --namespace "${NAMESPACE}" postgrescluster/original \ 18 | "testing/start-before=${START}" 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/07--update-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Update the cluster with PostgreSQL parameters that require attention during recovery. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: original 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | postgresVersion: ${KUTTL_PG_VERSION} 10 | config: 11 | parameters: 12 | max_connections: 1000 13 | instances: 14 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 15 | replicas: 2 16 | backups: 17 | pgbackrest: 18 | manual: 19 | repoName: repo1 20 | repos: 21 | - name: repo1 22 | volume: 23 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/09--add-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Add more data to the WAL archive. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: original-more-data 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | backoffLimit: 3 10 | template: 11 | metadata: 12 | labels: { postgres-operator-test: kuttl } 13 | spec: 14 | restartPolicy: Never 15 | containers: 16 | - name: psql 17 | image: ${KUTTL_PSQL_IMAGE} 18 | env: 19 | - name: PGURI 20 | valueFrom: { secretKeyRef: { name: original-pguser-original, key: uri } } 21 | 22 | # Do not wait indefinitely. 23 | - { name: PGCONNECT_TIMEOUT, value: '5' } 24 | 25 | command: 26 | - psql 27 | - $(PGURI) 28 | - --set=ON_ERROR_STOP=1 29 | - --command 30 | - | 31 | INSERT INTO important (data) VALUES ('water'), ('socks'); 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/09-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: original-more-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/10--wait-archived.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | - script: | 6 | PRIMARY=$( 7 | kubectl get pod --namespace "${NAMESPACE}" \ 8 | --output name --selector ' 9 | postgres-operator.crunchydata.com/cluster=original, 10 | postgres-operator.crunchydata.com/role=master' 11 | ) 12 | 13 | # Wait for the data to be sent to the WAL archive. A prior step reset the 14 | # "pg_stat_archiver" counters, so anything more than zero should suffice. 15 | kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" -- psql -c 'SELECT pg_switch_wal()' 16 | while [ 0 = "$( 17 | kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" -- psql -qAt -c 'SELECT archived_count FROM pg_stat_archiver' 18 | )" ]; do sleep 1; done 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/11--clone-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Clone the cluster using a pgBackRest restore. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: clone-two 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | dataSource: 10 | postgresCluster: 11 | clusterName: original 12 | repoName: repo1 13 | 14 | postgresVersion: ${KUTTL_PG_VERSION} 15 | instances: 16 | - dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 17 | backups: 18 | pgbackrest: 19 | repos: 20 | - name: repo1 21 | volume: 22 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/11-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the clone cluster to come online. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: clone-two 7 | status: 8 | instances: 9 | - name: '00' 10 | replicas: 1 11 | readyReplicas: 1 12 | updatedReplicas: 1 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/12-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: clone-two-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/13--delete-clone.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove the cloned cluster. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | delete: 6 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | name: clone-two 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/15-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the restore to complete and the cluster to come online. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: original 7 | status: 8 | instances: 9 | - name: '00' 10 | replicas: 2 11 | readyReplicas: 2 12 | updatedReplicas: 2 13 | pgbackrest: 14 | restore: 15 | id: one 16 | finished: true 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/16-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: original-pitr-primary-data 6 | status: 7 | succeeded: 1 8 | 9 | --- 10 | apiVersion: batch/v1 11 | kind: Job 12 | metadata: 13 | name: original-pitr-replica-data 14 | status: 15 | succeeded: 1 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbackrest-restore/17--check-replication.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Confirm that the replica is streaming from the primary. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | commands: 6 | - script: | 7 | REPLICA=$( 8 | kubectl get pod --namespace "${NAMESPACE}" \ 9 | --output name --selector ' 10 | postgres-operator.crunchydata.com/cluster=original, 11 | postgres-operator.crunchydata.com/role=replica' 12 | ) 13 | 14 | kubectl exec --stdin --namespace "${NAMESPACE}" "${REPLICA}" \ 15 | -- psql -qb original --set ON_ERROR_STOP=1 \ 16 | --file=- <<'SQL' 17 | DO $$ 18 | BEGIN 19 | PERFORM * FROM pg_stat_wal_receiver WHERE status = 'streaming'; 20 | ASSERT FOUND, 'expected streaming replication'; 21 | END $$ 22 | SQL 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: proxied 5 | labels: { postgres-operator-test: kuttl } 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | replicas: 1 11 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 12 | proxy: 13 | pgBouncer: 14 | replicas: 1 15 | config: 16 | # Set the pgBouncer verbosity level to debug to print connection logs 17 | # --https://www.pgbouncer.org/config.html#log-settings 18 | global: 19 | verbose: '1' 20 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: proxied 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: proxied-pgbouncer 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect 5 | status: 6 | succeeded: 1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/10--read-certificate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Print the certificate presented by PgBouncer. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: read-cert-before 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | backoffLimit: 1 10 | template: 11 | metadata: 12 | labels: { postgres-operator-test: kuttl } 13 | spec: 14 | restartPolicy: Never 15 | containers: 16 | - name: openssl 17 | image: ${KUTTL_PSQL_IMAGE} 18 | env: 19 | - name: PGHOST 20 | valueFrom: { secretKeyRef: { name: proxied-pguser-proxied, key: pgbouncer-host } } 21 | - name: PGPORT 22 | valueFrom: { secretKeyRef: { name: proxied-pguser-proxied, key: pgbouncer-port } } 23 | command: 24 | - bash 25 | - -ceu 26 | - | 27 | openssl s_client --connect '$(PGHOST):$(PGPORT)' --starttls postgres < /dev/null 2> /dev/null | 28 | openssl x509 --noout --text 29 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/10-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the job to complete. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: read-cert-before 7 | status: 8 | succeeded: 1 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/11-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the job to start. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: psql-open-connection 7 | status: 8 | active: 1 9 | 10 | --- 11 | # Wait for the pod to start. 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | job-name: psql-open-connection 17 | status: 18 | phase: Running 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/13--read-certificate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Print the certificate presented by PgBouncer. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: read-cert-after 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | backoffLimit: 1 10 | template: 11 | metadata: 12 | labels: { postgres-operator-test: kuttl } 13 | spec: 14 | restartPolicy: Never 15 | containers: 16 | - name: openssl 17 | image: ${KUTTL_PSQL_IMAGE} 18 | env: 19 | - name: PGHOST 20 | valueFrom: { secretKeyRef: { name: proxied-pguser-proxied, key: pgbouncer-host } } 21 | - name: PGPORT 22 | valueFrom: { secretKeyRef: { name: proxied-pguser-proxied, key: pgbouncer-port } } 23 | command: 24 | - bash 25 | - -ceu 26 | - | 27 | openssl s_client --connect '$(PGHOST):$(PGPORT)' --starttls postgres < /dev/null 2> /dev/null | 28 | openssl x509 --noout --text 29 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/13-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the job to complete. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: read-cert-after 7 | status: 8 | succeeded: 1 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/14--compare-certificate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Confirm that PgBouncer is serving a new certificate. 3 | apiVersion: kuttl.dev/v1beta1 4 | kind: TestStep 5 | commands: 6 | - script: | 7 | bash -c '! diff -u \ 8 | <(kubectl logs --namespace "${NAMESPACE}" job.batch/read-cert-before) \ 9 | <(kubectl logs --namespace "${NAMESPACE}" job.batch/read-cert-after) \ 10 | ' || { 11 | echo 'Certificate did not change!' 12 | kubectl logs --namespace "${NAMESPACE}" job.batch/read-cert-after 13 | exit 1 14 | } 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/pgbouncer/16-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the job to complete. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: psql-tls-after 7 | status: 8 | succeeded: 1 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/replica-read/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: replica-read 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | replicas: 2 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/replica-read/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: replica-read 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 2 9 | replicas: 2 10 | updatedReplicas: 2 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: replica-read-replicas 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/replica-read/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-replica-read 5 | status: 6 | succeeded: 1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: owner1 5 | labels: { postgres-operator-test: kuttl } 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | replicas: 1 11 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 12 | --- 13 | apiVersion: postgres-operator.crunchydata.com/v1beta1 14 | kind: PostgresCluster 15 | metadata: 16 | name: owner2 17 | labels: { postgres-operator-test: kuttl } 18 | spec: 19 | postgresVersion: ${KUTTL_PG_VERSION} 20 | instances: 21 | - name: instance1 22 | replicas: 1 23 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: owner1 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: postgres-operator.crunchydata.com/v1beta1 13 | kind: PostgresCluster 14 | metadata: 15 | name: owner2 16 | status: 17 | instances: 18 | - name: instance1 19 | readyReplicas: 1 20 | replicas: 1 21 | updatedReplicas: 1 22 | --- 23 | apiVersion: v1 24 | kind: Secret 25 | metadata: 26 | name: pgo-root-cacert 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/01--check-owners.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # Get a list of the current owners of the root ca cert secret and verify that 6 | # both owners are listed. 7 | - script: | 8 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 9 | while true; do 10 | sleep 1 # this sleep allows time for the owner reference list to be updated 11 | CURRENT_OWNERS=$(kubectl --namespace="${NAMESPACE}" get secret \ 12 | pgo-root-cacert -o jsonpath='{.metadata.ownerReferences[*].name}') 13 | # If owner1 and owner2 are both listed, exit successfully 14 | if contains "${CURRENT_OWNERS}" "owner1" && contains "${CURRENT_OWNERS}" "owner2"; then 15 | exit 0 16 | fi 17 | done 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/02--delete-owner1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | delete: 4 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | name: owner1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: owner2 5 | --- 6 | apiVersion: v1 7 | kind: Secret 8 | metadata: 9 | name: pgo-root-cacert 10 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/02-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: owner1 5 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/03--check-owners.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # Get a list of the current owners of the root ca cert secret and verify that 6 | # owner1 is no longer listed and owner2 is found. 7 | - script: | 8 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 9 | while true; do 10 | sleep 1 # this sleep allows time for the owner reference list to be updated 11 | CURRENT_OWNERS=$(kubectl --namespace="${NAMESPACE}" get secret \ 12 | pgo-root-cacert -o jsonpath='{.metadata.ownerReferences[*].name}') 13 | # If owner1 is removed and owner2 is still listed, exit successfully 14 | if !(contains "${CURRENT_OWNERS}" "owner1") && contains "${CURRENT_OWNERS}" "owner2"; then 15 | exit 0 16 | fi 17 | done 18 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/04--delete-owner2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | delete: 4 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | name: owner2 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/root-cert-ownership/04-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: owner1 5 | --- 6 | apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PostgresCluster 8 | metadata: 9 | name: owner2 10 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | - name: instance2 16 | dataVolumeClaimSpec: 17 | accessModes: 18 | - "ReadWriteOnce" 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | backups: 23 | pgbackrest: 24 | repos: 25 | - name: repo1 26 | volume: 27 | volumeClaimSpec: 28 | accessModes: 29 | - "ReadWriteOnce" 30 | resources: 31 | requests: 32 | storage: 1Gi 33 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | - name: instance2 12 | readyReplicas: 1 13 | replicas: 1 14 | updatedReplicas: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/01--update-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/02--delete-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | delete: 5 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 6 | kind: PostgresCluster 7 | name: scaledown 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/10--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown1 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 2 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | backups: 17 | pgbackrest: 18 | repos: 19 | - name: repo1 20 | volume: 21 | volumeClaimSpec: 22 | accessModes: 23 | - "ReadWriteOnce" 24 | resources: 25 | requests: 26 | storage: 1Gi 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/10-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown1 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 2 9 | replicas: 2 10 | updatedReplicas: 2 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: scaledown1 17 | postgres-operator.crunchydata.com/instance-set: instance1 18 | postgres-operator.crunchydata.com/role: master 19 | status: 20 | phase: Running 21 | --- 22 | apiVersion: v1 23 | kind: Pod 24 | metadata: 25 | labels: 26 | postgres-operator.crunchydata.com/cluster: scaledown1 27 | postgres-operator.crunchydata.com/instance-set: instance1 28 | postgres-operator.crunchydata.com/role: replica 29 | status: 30 | phase: Running 31 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/11-annotate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # Label instance pods with their current role. 6 | - script: | 7 | kubectl label --namespace="${NAMESPACE}" pods \ 8 | --selector='postgres-operator.crunchydata.com/role=master' \ 9 | 'testing/role-before=master' 10 | - script: | 11 | kubectl label --namespace="${NAMESPACE}" pods \ 12 | --selector='postgres-operator.crunchydata.com/role=replica' \ 13 | 'testing/role-before=replica' 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/12--update-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown1 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 1 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/12-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown1 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Pod 14 | metadata: 15 | labels: 16 | postgres-operator.crunchydata.com/cluster: scaledown1 17 | postgres-operator.crunchydata.com/instance-set: instance1 18 | postgres-operator.crunchydata.com/role: master 19 | testing/role-before: master 20 | status: 21 | phase: Running 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/13--delete-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | delete: 5 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 6 | kind: PostgresCluster 7 | name: scaledown1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/20--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown2 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | replicas: 2 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | - name: instance2 17 | dataVolumeClaimSpec: 18 | accessModes: 19 | - "ReadWriteOnce" 20 | resources: 21 | requests: 22 | storage: 1Gi 23 | backups: 24 | pgbackrest: 25 | repos: 26 | - name: repo1 27 | volume: 28 | volumeClaimSpec: 29 | accessModes: 30 | - "ReadWriteOnce" 31 | resources: 32 | requests: 33 | storage: 1Gi 34 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/20-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown2 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 2 9 | replicas: 2 10 | updatedReplicas: 2 11 | - name: instance2 12 | readyReplicas: 1 13 | replicas: 1 14 | updatedReplicas: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/21--update-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown2 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | instances: 8 | - name: instance1 9 | dataVolumeClaimSpec: 10 | accessModes: 11 | - "ReadWriteOnce" 12 | resources: 13 | requests: 14 | storage: 1Gi 15 | - name: instance2 16 | dataVolumeClaimSpec: 17 | accessModes: 18 | - "ReadWriteOnce" 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/scaledown/21-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: scaledown2 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | - name: instance2 12 | readyReplicas: 1 13 | replicas: 1 14 | updatedReplicas: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/security-context/00--cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: security-context 5 | labels: { postgres-operator-test: kuttl } 6 | spec: 7 | postgresVersion: ${KUTTL_PG_VERSION} 8 | instances: 9 | - name: instance1 10 | replicas: 1 11 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 12 | backups: 13 | pgbackrest: 14 | repos: 15 | - name: repo1 16 | volume: 17 | volumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 18 | proxy: 19 | pgBouncer: 20 | replicas: 1 21 | monitoring: 22 | pgmonitor: 23 | exporter: {} 24 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/security-context/10--kyverno.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | - script: | 6 | command -v kustomize || { echo Skipping... ; exit ; } 7 | command -v kyverno || { echo Skipping... ; exit ; } 8 | 9 | set -e 10 | kustomize build ../../../../testing/policies/kyverno > policies.yaml 11 | kyverno apply --cluster --namespace "${NAMESPACE}" policies.yaml 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/00--create-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-cluster.yaml 5 | assert: 6 | - files/00-cluster-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/01--user-schema.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # ensure the user schema is created for pgAdmin to use 6 | - script: | 7 | PRIMARY=$( 8 | kubectl get pod --namespace "${NAMESPACE}" \ 9 | --output name --selector ' 10 | postgres-operator.crunchydata.com/cluster=elephant, 11 | postgres-operator.crunchydata.com/role=master' 12 | ) 13 | kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" \ 14 | -- psql -qAt -d elephant --command 'CREATE SCHEMA elephant AUTHORIZATION elephant' 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/02--create-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/02-pgadmin.yaml 5 | assert: 6 | - files/02-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/03-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | commands: 4 | - script: | 5 | PRIMARY=$( 6 | kubectl get pod --namespace "${NAMESPACE}" \ 7 | --output name --selector ' 8 | postgres-operator.crunchydata.com/cluster=elephant, 9 | postgres-operator.crunchydata.com/role=master' 10 | ) 11 | 12 | NUM_USERS=$( 13 | kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" -- \ 14 | psql -qAt -d elephant --command 'select count(*) from elephant.user' \ 15 | ) 16 | 17 | if [[ ${NUM_USERS} != 1 ]]; then 18 | echo >&2 'Expected 1 user' 19 | echo "got ${NUM_USERS}" 20 | exit 1 21 | fi 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/04--update-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/04-pgadmin.yaml 5 | assert: 6 | - files/04-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/README.md: -------------------------------------------------------------------------------- 1 | # pgAdmin external database tests 2 | 3 | Notes: 4 | - Due to the (random) namespace being part of the host, we cannot check the configmap using the usual assert/file pattern. 5 | - These tests will only work with pgAdmin version v8 and higher 6 | 7 | ## create postgrescluster and add user schema 8 | * 00: 9 | * create a postgrescluster with a label; 10 | * check that the cluster has the label and that the expected user secret is created. 11 | * 01: 12 | * create the user schema for pgAdmin to use 13 | 14 | ## create pgadmin and verify connection to database 15 | * 02: 16 | * create a pgadmin with a selector for the existing cluster's label; 17 | * check the correct existence of the secret, configmap, and pod. 18 | * 03: 19 | * check that pgAdmin only has one user 20 | 21 | ## add a pgadmin user and verify it in the database 22 | * 04: 23 | * update pgadmin with a new user; 24 | * check that the pod is still running as expected. 25 | * 05: 26 | * check that pgAdmin now has two users and that the defined user is present. 27 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/00-cluster-check.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: elephant 5 | labels: 6 | sometest: test1 7 | status: 8 | instances: 9 | - name: instance1 10 | readyReplicas: 1 11 | replicas: 1 12 | updatedReplicas: 1 13 | --- 14 | apiVersion: v1 15 | kind: Secret 16 | metadata: 17 | labels: 18 | postgres-operator.crunchydata.com/cluster: elephant 19 | postgres-operator.crunchydata.com/pguser: elephant 20 | postgres-operator.crunchydata.com/role: pguser 21 | type: Opaque 22 | --- 23 | apiVersion: v1 24 | kind: Pod 25 | metadata: 26 | labels: 27 | postgres-operator.crunchydata.com/cluster: elephant 28 | postgres-operator.crunchydata.com/instance-set: instance1 29 | postgres-operator.crunchydata.com/role: master 30 | status: 31 | phase: Running 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/00-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: elephant 5 | labels: 6 | sometest: test1 7 | spec: 8 | postgresVersion: ${KUTTL_PG_VERSION} 9 | instances: 10 | - name: instance1 11 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/02-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/role: pgadmin 7 | postgres-operator.crunchydata.com/pgadmin: pgadmin1 8 | --- 9 | apiVersion: v1 10 | kind: Pod 11 | metadata: 12 | labels: 13 | postgres-operator.crunchydata.com/data: pgadmin 14 | postgres-operator.crunchydata.com/role: pgadmin 15 | postgres-operator.crunchydata.com/pgadmin: pgadmin1 16 | status: 17 | containerStatuses: 18 | - name: pgadmin 19 | ready: true 20 | started: true 21 | phase: Running 22 | --- 23 | apiVersion: v1 24 | kind: Secret 25 | metadata: 26 | labels: 27 | postgres-operator.crunchydata.com/role: pgadmin 28 | postgres-operator.crunchydata.com/pgadmin: pgadmin1 29 | type: Opaque 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/02-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin1 5 | spec: 6 | config: 7 | configDatabaseURI: 8 | name: elephant-pguser-elephant 9 | key: uri 10 | dataVolumeClaimSpec: 11 | accessModes: 12 | - "ReadWriteOnce" 13 | resources: 14 | requests: 15 | storage: 1Gi 16 | serverGroups: 17 | - name: kuttl-test 18 | postgresClusterSelector: 19 | matchLabels: 20 | sometest: test1 21 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/04-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/data: pgadmin 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: pgadmin1 9 | status: 10 | containerStatuses: 11 | - name: pgadmin 12 | ready: true 13 | started: true 14 | phase: Running 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-db-uri/files/04-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin1 5 | spec: 6 | users: 7 | - username: "john.doe@example.com" 8 | passwordRef: 9 | name: john-doe-password 10 | key: password 11 | config: 12 | configDatabaseURI: 13 | name: elephant-pguser-elephant 14 | key: uri 15 | dataVolumeClaimSpec: 16 | accessModes: 17 | - "ReadWriteOnce" 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | serverGroups: 22 | - name: kuttl-test 23 | postgresClusterSelector: 24 | matchLabels: 25 | sometest: test1 26 | --- 27 | apiVersion: v1 28 | kind: Secret 29 | metadata: 30 | name: john-doe-password 31 | type: Opaque 32 | stringData: 33 | password: password 34 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/00--pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | serviceName: pgadmin-service 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgadmin-service 5 | labels: 6 | postgres-operator.crunchydata.com/role: pgadmin 7 | postgres-operator.crunchydata.com/pgadmin: pgadmin 8 | ownerReferences: 9 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 10 | controller: true 11 | kind: PGAdmin 12 | name: pgadmin 13 | spec: 14 | selector: 15 | postgres-operator.crunchydata.com/pgadmin: pgadmin 16 | ports: 17 | - port: 5050 18 | targetPort: 5050 19 | protocol: TCP 20 | name: pgadmin-port 21 | type: ClusterIP 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/01--update-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | serviceName: pgadmin-service-updated 13 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgadmin-service-updated 5 | labels: 6 | postgres-operator.crunchydata.com/role: pgadmin 7 | postgres-operator.crunchydata.com/pgadmin: pgadmin 8 | spec: 9 | selector: 10 | postgres-operator.crunchydata.com/pgadmin: pgadmin 11 | ports: 12 | - port: 5050 13 | targetPort: 5050 14 | protocol: TCP 15 | name: pgadmin-port 16 | type: ClusterIP 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/02--remove-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/02-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgadmin-service 5 | labels: 6 | postgres-operator.crunchydata.com/role: pgadmin 7 | postgres-operator.crunchydata.com/pgadmin: pgadmin 8 | spec: 9 | selector: 10 | postgres-operator.crunchydata.com/pgadmin: pgadmin 11 | ports: 12 | - port: 5050 13 | targetPort: 5050 14 | protocol: TCP 15 | name: pgadmin-port 16 | type: ClusterIP 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/10--manual-service.yaml: -------------------------------------------------------------------------------- 1 | # Manually create a service that should be taken over by pgAdmin 2 | # The manual service is of type LoadBalancer 3 | # Once taken over, the type should change to ClusterIP 4 | apiVersion: v1 5 | kind: Service 6 | metadata: 7 | name: manual-pgadmin-service 8 | spec: 9 | ports: 10 | - name: pgadmin-port 11 | port: 5050 12 | protocol: TCP 13 | selector: 14 | postgres-operator.crunchydata.com/pgadmin: rhino 15 | type: LoadBalancer 16 | --- 17 | # Create a pgAdmin that points to an existing un-owned service 18 | apiVersion: postgres-operator.crunchydata.com/v1beta1 19 | kind: PGAdmin 20 | metadata: 21 | name: manual-svc-pgadmin 22 | spec: 23 | serviceName: manual-pgadmin-service 24 | dataVolumeClaimSpec: 25 | accessModes: 26 | - "ReadWriteOnce" 27 | resources: 28 | requests: 29 | storage: 1Gi 30 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/10-assert.yaml: -------------------------------------------------------------------------------- 1 | # Check that the manually created service has the correct ownerReference 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: manual-pgadmin-service 6 | labels: 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: manual-svc-pgadmin 9 | ownerReferences: 10 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 11 | controller: true 12 | kind: PGAdmin 13 | name: manual-svc-pgadmin 14 | spec: 15 | selector: 16 | postgres-operator.crunchydata.com/pgadmin: manual-svc-pgadmin 17 | ports: 18 | - port: 5050 19 | targetPort: 5050 20 | protocol: TCP 21 | name: pgadmin-port 22 | type: ClusterIP 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/20--owned-service.yaml: -------------------------------------------------------------------------------- 1 | # Create a pgAdmin that will create and own a service 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PGAdmin 4 | metadata: 5 | name: pgadmin-service-owner 6 | spec: 7 | serviceName: pgadmin-owned-service 8 | dataVolumeClaimSpec: 9 | accessModes: 10 | - "ReadWriteOnce" 11 | resources: 12 | requests: 13 | storage: 1Gi 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/20-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgadmin-owned-service 5 | labels: 6 | postgres-operator.crunchydata.com/role: pgadmin 7 | postgres-operator.crunchydata.com/pgadmin: pgadmin-service-owner 8 | ownerReferences: 9 | - apiVersion: postgres-operator.crunchydata.com/v1beta1 10 | controller: true 11 | kind: PGAdmin 12 | name: pgadmin-service-owner 13 | spec: 14 | selector: 15 | postgres-operator.crunchydata.com/pgadmin: pgadmin-service-owner 16 | ports: 17 | - port: 5050 18 | targetPort: 5050 19 | protocol: TCP 20 | name: pgadmin-port 21 | type: ClusterIP 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-service/21--service-takeover-fails.yaml: -------------------------------------------------------------------------------- 1 | # Create a second pgAdmin that attempts to steal the service 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PGAdmin 4 | metadata: 5 | name: pgadmin-service-thief 6 | spec: 7 | serviceName: pgadmin-owned-service 8 | dataVolumeClaimSpec: 9 | accessModes: 10 | - "ReadWriteOnce" 11 | resources: 12 | requests: 13 | storage: 1Gi 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/00--create-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/00-pgadmin.yaml 5 | assert: 6 | - files/00-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/02--edit-pgadmin-users.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/02-pgadmin.yaml 5 | assert: 6 | - files/02-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/04--change-pgadmin-user-passwords.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/04-pgadmin.yaml 5 | assert: 6 | - files/04-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/06--delete-pgadmin-users.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | apply: 4 | - files/06-pgadmin.yaml 5 | assert: 6 | - files/06-pgadmin-check.yaml 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/README.md: -------------------------------------------------------------------------------- 1 | # pgAdmin User Management tests 2 | 3 | *Note: These tests will only work with pgAdmin version v8 and higher* 4 | 5 | ## Create pgAdmin with users 6 | 7 | * Start pgAdmin with a couple users 8 | * Ensure users exist in pgAdmin with correct settings 9 | * Ensure users exist in the `users.json` file in the pgAdmin secret with the correct settings 10 | 11 | ## Edit pgAdmin users 12 | 13 | * Add a user and edit an existing user 14 | * Ensure users exist in pgAdmin with correct settings 15 | * Ensure users exist in the `users.json` file in the pgAdmin secret with the correct settings 16 | 17 | ## Delete pgAdmin users 18 | 19 | * Remove users from pgAdmin spec 20 | * Ensure users still exist in pgAdmin with correct settings 21 | * Ensure users have been removed from the `users.json` file in the pgAdmin secret 22 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/00-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/data: pgadmin 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: pgadmin 9 | status: 10 | containerStatuses: 11 | - name: pgadmin 12 | ready: true 13 | started: true 14 | phase: Running 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | labels: 20 | postgres-operator.crunchydata.com/role: pgadmin 21 | postgres-operator.crunchydata.com/pgadmin: pgadmin 22 | type: Opaque 23 | --- 24 | apiVersion: v1 25 | kind: Secret 26 | metadata: 27 | name: bob-password-secret 28 | type: Opaque 29 | --- 30 | apiVersion: v1 31 | kind: Secret 32 | metadata: 33 | name: dave-password-secret 34 | type: Opaque 35 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/00-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | serverGroups: [] 13 | users: 14 | - username: bob@example.com 15 | role: Administrator 16 | passwordRef: 17 | name: bob-password-secret 18 | key: password 19 | - username: dave@example.com 20 | passwordRef: 21 | name: dave-password-secret 22 | key: password 23 | --- 24 | apiVersion: v1 25 | kind: Secret 26 | metadata: 27 | name: bob-password-secret 28 | type: Opaque 29 | data: 30 | # Password is "password123", base64 encoded 31 | password: cGFzc3dvcmQxMjM= 32 | --- 33 | apiVersion: v1 34 | kind: Secret 35 | metadata: 36 | name: dave-password-secret 37 | type: Opaque 38 | data: 39 | # Password is "password456", base64 encoded 40 | password: cGFzc3dvcmQ0NTY= 41 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/02-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/data: pgadmin 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: pgadmin 9 | status: 10 | containerStatuses: 11 | - name: pgadmin 12 | ready: true 13 | started: true 14 | phase: Running 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | labels: 20 | postgres-operator.crunchydata.com/role: pgadmin 21 | postgres-operator.crunchydata.com/pgadmin: pgadmin 22 | type: Opaque 23 | --- 24 | apiVersion: v1 25 | kind: Secret 26 | metadata: 27 | name: bob-password-secret 28 | type: Opaque 29 | --- 30 | apiVersion: v1 31 | kind: Secret 32 | metadata: 33 | name: dave-password-secret 34 | type: Opaque 35 | --- 36 | apiVersion: v1 37 | kind: Secret 38 | metadata: 39 | name: jimi-password-secret 40 | type: Opaque 41 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/04-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/data: pgadmin 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: pgadmin 9 | status: 10 | containerStatuses: 11 | - name: pgadmin 12 | ready: true 13 | started: true 14 | phase: Running 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | labels: 20 | postgres-operator.crunchydata.com/role: pgadmin 21 | postgres-operator.crunchydata.com/pgadmin: pgadmin 22 | type: Opaque 23 | --- 24 | apiVersion: v1 25 | kind: Secret 26 | metadata: 27 | name: bob-password-secret 28 | type: Opaque 29 | --- 30 | apiVersion: v1 31 | kind: Secret 32 | metadata: 33 | name: dave-password-secret 34 | type: Opaque 35 | --- 36 | apiVersion: v1 37 | kind: Secret 38 | metadata: 39 | name: jimi-password-secret 40 | type: Opaque 41 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/06-pgadmin-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | postgres-operator.crunchydata.com/data: pgadmin 7 | postgres-operator.crunchydata.com/role: pgadmin 8 | postgres-operator.crunchydata.com/pgadmin: pgadmin 9 | status: 10 | containerStatuses: 11 | - name: pgadmin 12 | ready: true 13 | started: true 14 | phase: Running 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | labels: 20 | postgres-operator.crunchydata.com/role: pgadmin 21 | postgres-operator.crunchydata.com/pgadmin: pgadmin 22 | type: Opaque 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/standalone-pgadmin-user-management/files/06-pgadmin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PGAdmin 3 | metadata: 4 | name: pgadmin 5 | spec: 6 | dataVolumeClaimSpec: 7 | accessModes: 8 | - "ReadWriteOnce" 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | serverGroups: [] 13 | users: [] 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/01--primary-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: primary-cluster 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | customTLSSecret: 8 | name: cluster-cert 9 | customReplicationTLSSecret: 10 | name: replication-cert 11 | instances: 12 | - name: instance1 13 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 14 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/01-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: primary-cluster 6 | status: 7 | instances: 8 | - name: instance1 9 | readyReplicas: 1 10 | replicas: 1 11 | updatedReplicas: 1 12 | --- 13 | apiVersion: v1 14 | kind: Service 15 | metadata: 16 | name: primary-cluster-primary 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/02--create-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create some data that will be replicated. 3 | apiVersion: batch/v1 4 | kind: Job 5 | metadata: 6 | name: primary-cluster-data 7 | labels: { postgres-operator-test: kuttl } 8 | spec: 9 | backoffLimit: 3 10 | template: 11 | metadata: 12 | labels: { postgres-operator-test: kuttl } 13 | spec: 14 | restartPolicy: Never 15 | containers: 16 | - name: psql 17 | image: ${KUTTL_PSQL_IMAGE} 18 | env: 19 | - name: PGURI 20 | valueFrom: { secretKeyRef: { name: primary-cluster-pguser-primary-cluster, key: uri } } 21 | 22 | # Do not wait indefinitely. 23 | - { name: PGCONNECT_TIMEOUT, value: '5' } 24 | 25 | command: 26 | - psql 27 | - $(PGURI) 28 | - --set=ON_ERROR_STOP=1 29 | - --command 30 | - | 31 | CREATE SCHEMA "primary-cluster"; 32 | CREATE TABLE important (data) AS VALUES ('treasure'); 33 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/02-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: primary-cluster-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/03--standby-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: standby-cluster 5 | spec: 6 | postgresVersion: ${KUTTL_PG_VERSION} 7 | standby: 8 | enabled: true 9 | host: primary-cluster-primary 10 | customTLSSecret: 11 | name: cluster-cert 12 | customReplicationTLSSecret: 13 | name: replication-cert 14 | instances: 15 | - name: instance1 16 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/03-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: standby-cluster 6 | status: 7 | instances: 8 | - name: instance1 9 | readyReplicas: 1 10 | replicas: 1 11 | updatedReplicas: 1 12 | --- 13 | apiVersion: v1 14 | kind: Service 15 | metadata: 16 | name: standby-cluster-primary 17 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/04-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: check-standby-data 6 | status: 7 | succeeded: 1 8 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/streaming-standby/README.md: -------------------------------------------------------------------------------- 1 | # Streaming Standby Tests 2 | 3 | The streaming standby test will deploy two clusters, one primary and one standby. 4 | Both clusters are created in the same namespace to allow for easy connections 5 | over the network. 6 | 7 | This test scenario can be run without any specific Kubernetes environment 8 | requirements. More standby tests can be added that will require access to a 9 | cloud storage. 10 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/switchover/01--cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create a cluster with multiple instances and manual switchover enabled. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: switchover 7 | spec: 8 | postgresVersion: ${KUTTL_PG_VERSION} 9 | patroni: 10 | switchover: 11 | enabled: true 12 | instances: 13 | - replicas: 2 14 | dataVolumeClaimSpec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } } 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/switchover/01-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgres-operator.crunchydata.com/v1beta1 3 | kind: PostgresCluster 4 | metadata: 5 | name: switchover 6 | status: 7 | instances: 8 | - name: "00" 9 | replicas: 2 10 | readyReplicas: 2 11 | updatedReplicas: 2 12 | --- 13 | # Patroni labels and readiness happen separately. 14 | # The next step expects to find pods by their role label; wait for them here. 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | labels: 19 | postgres-operator.crunchydata.com/cluster: switchover 20 | postgres-operator.crunchydata.com/role: master 21 | --- 22 | apiVersion: v1 23 | kind: Pod 24 | metadata: 25 | labels: 26 | postgres-operator.crunchydata.com/cluster: switchover 27 | postgres-operator.crunchydata.com/role: replica 28 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/switchover/02-annotate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestStep 4 | commands: 5 | # Label instance pods with their current role. These labels will stick around 6 | # because switchover does not recreate any pods. 7 | - script: | 8 | kubectl label --namespace="${NAMESPACE}" pods \ 9 | --selector='postgres-operator.crunchydata.com/role=master' \ 10 | 'testing/role-before=master' 11 | - script: | 12 | kubectl label --namespace="${NAMESPACE}" pods \ 13 | --selector='postgres-operator.crunchydata.com/role=replica' \ 14 | 'testing/role-before=replica' 15 | 16 | # Annotate the cluster to trigger a switchover. 17 | - script: | 18 | kubectl annotate --namespace="${NAMESPACE}" postgrescluster/switchover \ 19 | "postgres-operator.crunchydata.com/trigger-switchover=$(date)" 20 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/switchover/03-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # After switchover, a former replica should now be the primary. 3 | apiVersion: v1 4 | kind: Pod 5 | metadata: 6 | labels: 7 | postgres-operator.crunchydata.com/cluster: switchover 8 | postgres-operator.crunchydata.com/data: postgres 9 | 10 | postgres-operator.crunchydata.com/role: master 11 | testing/role-before: replica 12 | 13 | --- 14 | # The former primary should now be a replica. 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | labels: 19 | postgres-operator.crunchydata.com/cluster: switchover 20 | postgres-operator.crunchydata.com/data: postgres 21 | 22 | postgres-operator.crunchydata.com/role: replica 23 | testing/role-before: master 24 | 25 | --- 26 | # All instances should be healthy. 27 | apiVersion: postgres-operator.crunchydata.com/v1beta1 28 | kind: PostgresCluster 29 | metadata: 30 | name: switchover 31 | status: 32 | instances: 33 | - name: "00" 34 | replicas: 2 35 | readyReplicas: 2 36 | updatedReplicas: 2 37 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/tablespace-enabled/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: tablespace-enabled 5 | status: 6 | instances: 7 | - name: instance1 8 | readyReplicas: 1 9 | replicas: 1 10 | updatedReplicas: 1 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: tablespace-enabled-primary 16 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/tablespace-enabled/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: psql-connect 5 | status: 6 | succeeded: 1 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/tablespace-enabled/README.md: -------------------------------------------------------------------------------- 1 | # Tablespace Enabled 2 | 3 | **Note**: This series of tests depends on PGO being deployed with the `TablespaceVolume` feature gate enabled. 4 | 5 | 00: Start a cluster with tablespace volumes and a configmap `databaseInitSQL` to create tablespaces with the non-superuser as owner 6 | 01: Connect to the db; check that the tablespaces exist; create tables in the tablespaces; and create a table outside the tablespaces and move it into a tablespace 7 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/00-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready and the replica backup to complete 3 | # by waiting for the status to signal pods ready and pgbackrest stanza created 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: wal-pvc-pgupgrade 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_FROM_VERSION} 10 | status: 11 | instances: 12 | - name: '00' 13 | replicas: 3 14 | readyReplicas: 3 15 | updatedReplicas: 3 16 | pgbackrest: 17 | repos: 18 | - name: repo1 19 | replicaCreateBackupComplete: true 20 | stanzaCreated: true 21 | --- 22 | # Even when the cluster exists, the pgupgrade is not progressing because the cluster is not shutdown 23 | apiVersion: postgres-operator.crunchydata.com/v1beta1 24 | kind: PGUpgrade 25 | metadata: 26 | name: wal-pvc-pgupgrade-do-it 27 | status: 28 | conditions: 29 | - type: "Progressing" 30 | status: "False" 31 | reason: "PGClusterNotShutdown" 32 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/01-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: wal-pvc-pgupgrade-before 6 | status: 7 | succeeded: 1 8 | --- 9 | apiVersion: batch/v1 10 | kind: Job 11 | metadata: 12 | name: wal-pvc-pgupgrade-before-replica 13 | status: 14 | succeeded: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/02--shutdown-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Shutdown the cluster -- but without the annotation. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: wal-pvc-pgupgrade 7 | spec: 8 | shutdown: true 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/02-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Since the cluster is missing the annotation, we get this condition 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PGUpgrade 5 | metadata: 6 | name: wal-pvc-pgupgrade-do-it 7 | status: 8 | conditions: 9 | - type: "Progressing" 10 | status: "False" 11 | reason: "PGClusterMissingRequiredAnnotation" 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/03--annotate-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Annotate the cluster for an upgrade. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: wal-pvc-pgupgrade 7 | annotations: 8 | postgres-operator.crunchydata.com/allow-upgrade: wal-pvc-pgupgrade-do-it 9 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/03-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Now that the postgres cluster is shut down and annotated, the pgupgrade 3 | # can finish reconciling. We know the reconciling is complete when 4 | # the pgupgrade status is succeeded and the postgres cluster status 5 | # has the updated version. 6 | apiVersion: postgres-operator.crunchydata.com/v1beta1 7 | kind: PGUpgrade 8 | metadata: 9 | name: wal-pvc-pgupgrade-do-it 10 | status: 11 | conditions: 12 | - type: "Progressing" 13 | status: "False" 14 | - type: "Succeeded" 15 | status: "True" 16 | --- 17 | apiVersion: postgres-operator.crunchydata.com/v1beta1 18 | kind: PostgresCluster 19 | metadata: 20 | name: wal-pvc-pgupgrade 21 | status: 22 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 23 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/04--restart-cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Once the pgupgrade is finished, update the version and set shutdown to false 3 | # in the postgres cluster 4 | apiVersion: postgres-operator.crunchydata.com/v1beta1 5 | kind: PostgresCluster 6 | metadata: 7 | name: wal-pvc-pgupgrade 8 | spec: 9 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 10 | shutdown: false 11 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/04-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Wait for the instances to be ready with the target Postgres version. 3 | apiVersion: postgres-operator.crunchydata.com/v1beta1 4 | kind: PostgresCluster 5 | metadata: 6 | name: wal-pvc-pgupgrade 7 | status: 8 | postgresVersion: ${KUTTL_PG_UPGRADE_TO_VERSION} 9 | instances: 10 | - name: '00' 11 | replicas: 3 12 | readyReplicas: 3 13 | updatedReplicas: 3 14 | pgbackrest: 15 | repos: 16 | - name: repo1 17 | replicaCreateBackupComplete: true 18 | stanzaCreated: true 19 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/05-check-pgbackrest-and-replica.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # Check that the pgbackrest setup has successfully completed 5 | - script: | 6 | kubectl -n "${NAMESPACE}" exec "statefulset.apps/wal-pvc-pgupgrade-repo-host" -c pgbackrest -- pgbackrest check --stanza=db 7 | # Check that the replica data dir has been successfully cleaned 8 | - script: | 9 | # Check that the old pg folders do not exist on the replica 10 | REPLICA=$(kubectl get pod -l=postgres-operator.crunchydata.com/role=replica -n "${NAMESPACE}" -o=jsonpath='{ .items[0].metadata.name }') 11 | kubectl -n "${NAMESPACE}" exec "${REPLICA}" -c database -- [ ! -d "pgdata/pg${KUTTL_PG_UPGRADE_FROM_VERSION}" ] 12 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/06--check-spool-path.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | PRIMARY=$( 6 | kubectl get pod --namespace "${NAMESPACE}" \ 7 | --output name --selector ' 8 | postgres-operator.crunchydata.com/role=master' 9 | ) 10 | 11 | LIST=$( 12 | kubectl exec --namespace "${NAMESPACE}" -c database "${PRIMARY}" -- \ 13 | ls -l /pgdata 14 | ) 15 | 16 | contains() { bash -ceu '[[ "$1" == *"$2"* ]]' - "$@"; } 17 | 18 | # Confirm that the pgbackrest spool-path has been symlinked to the wal volume. 19 | contains "$LIST" "pgbackrest-spool -> /pgwal/pgbackrest-spool" || exit 1 20 | -------------------------------------------------------------------------------- /testing/kuttl/e2e/wal-pvc-pgupgrade/06-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: wal-pvc-pgupgrade-after 6 | status: 7 | succeeded: 1 8 | --- 9 | apiVersion: batch/v1 10 | kind: Job 11 | metadata: 12 | name: wal-pvc-pgupgrade-after-replica 13 | status: 14 | succeeded: 1 15 | -------------------------------------------------------------------------------- /testing/kuttl/kuttl-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestSuite 3 | testDirs: 4 | - testing/kuttl/e2e-generated/ 5 | timeout: 300 6 | parallel: 2 7 | # by default kuttl will run in a generated namespace to override 8 | # that functionality simply uncomment the line below and replace 9 | # postgres-operator with the desired namespace to run in. 10 | # namespace: postgres-operator 11 | # By default kuttl deletes the resources created during a test. 12 | # For debugging, it may be helpful to uncomment the following line 13 | # in order to inspect the resources. 14 | # skipDelete: true 15 | -------------------------------------------------------------------------------- /testing/kuttl/scripts/pgbackrest-initialization.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | EXPECTED_STATUS=$1 4 | EXPECTED_NUM_BACKUPS=$2 5 | 6 | CLUSTER=${CLUSTER:-default} 7 | 8 | INFO=$(kubectl -n "${NAMESPACE}" exec "statefulset.apps/${CLUSTER}-repo-host" -c pgbackrest -- pgbackrest info) 9 | 10 | # Grab the `status` line from `pgbackrest info`, remove whitespace with `xargs`, 11 | # and trim the string to only include the status in order to 12 | # validate the status matches the expected status. 13 | STATUS=$(grep "status" <<< "$INFO" | xargs | cut -d' ' -f 2) 14 | if [[ "$STATUS" != "$EXPECTED_STATUS" ]]; then 15 | echo "Expected ${EXPECTED_STATUS} but got ${STATUS}" 16 | exit 1 17 | fi 18 | 19 | # Count the lines with `full backup` to validate that the expected number of backups are found. 20 | NUM_BACKUPS=$(grep -c "full backup:" <<< "$INFO") 21 | if [[ "$NUM_BACKUPS" != "$EXPECTED_NUM_BACKUPS" ]]; then 22 | echo "Expected ${EXPECTED_NUM_BACKUPS} but got ${NUM_BACKUPS}" 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /trivy.yaml: -------------------------------------------------------------------------------- 1 | # https://aquasecurity.github.io/trivy/latest/docs/references/configuration/config-file/ 2 | --- 3 | # Specify an exact list of recognized and acceptable licenses. 4 | # [A GitHub workflow](/.github/workflows/trivy.yaml) rejects pull requests that 5 | # import licenses not in this list. 6 | # 7 | # https://aquasecurity.github.io/trivy/latest/docs/scanner/license/ 8 | license: 9 | ignored: 10 | - Apache-2.0 11 | - BSD-2-Clause 12 | - BSD-3-Clause 13 | - ISC 14 | - MIT 15 | --------------------------------------------------------------------------------