# Chainsaw port of hack/e2e-apps/postgres.bats ("Create DB PostgreSQL"). # # Every `timeout N sh -ec "until kubectl get ..."` + `kubectl wait` pair from # the BATS test collapses into a single assert: chainsaw polls until the # resource exists AND matches, or the timeout expires. Failure output is a # structured diff of the assertion tree against the live object. apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: name: postgres spec: # Diagnostics collected automatically when any step fails. The BATS suite # only does this in harbor.bats, by hand. catch: - events: {} - describe: apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease name: postgres-test - podLogs: selector: cnpg.io/cluster=postgres-test tail: 50 steps: - name: create-postgres try: - apply: file: postgres.yaml - name: wait-helmrelease-ready try: - assert: timeout: 6m resource: apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: postgres-test status: # JMESPath filter: condition order in the array does not matter (conditions[?type == 'Ready']): - status: "True" - name: wait-init-job-complete try: - assert: timeout: 2m resource: apiVersion: batch/v1 kind: Job metadata: name: postgres-test-init-job status: (conditions[?type == 'Complete']): - status: "True" - name: verify-services-and-endpoints try: # Replaces three `until kubectl get svc ... | grep -q 5432` loops # TODO(chainsaw>0.2.15): the (ports[0].port) / (ports[*].port) projection form in # these Service asserts is a v0.2.15 workaround for mis-evaluated number-literal # filters (ports[?port==`5432`]); (ports[0]) also checks only the first port. # Restore the filter form on a chainsaw bump. Same workaround lives in # kafka/mariadb/harbor — see "Chainsaw v0.2.15 gotchas" in docs/agents/e2e-testing.md. - assert: resource: apiVersion: v1 kind: Service metadata: name: postgres-test-r spec: (ports[0].port): 5432 - assert: resource: apiVersion: v1 kind: Service metadata: name: postgres-test-ro spec: (ports[0].port): 5432 - assert: resource: apiVersion: v1 kind: Service metadata: name: postgres-test-rw spec: (ports[0].port): 5432 # Replaces `until kubectl get endpoints ... | grep -q '[0-9]'` loops. # The read-only endpoint is skipped, same as in the BATS test. - assert: timeout: 3m resource: apiVersion: v1 kind: Endpoints metadata: name: postgres-test-r (subsets[0].addresses[0].ip != null): true - assert: timeout: 3m resource: apiVersion: v1 kind: Endpoints metadata: name: postgres-test-rw (subsets[0].addresses[0].ip != null): true # Functional probe — the BATS test never actually talks to the database. - script: timeout: 2m content: | set -eu pod=$(kubectl -n "$NAMESPACE" get pod \ -l cnpg.io/cluster=postgres-test,cnpg.io/instanceRole=primary \ -o name | head -n1) kubectl -n "$NAMESPACE" exec "$pod" -c postgres -- \ psql -U postgres -tAc 'SELECT 1' check: ($error == null): true (contains($stdout, '1')): true # The init-job is operator-created (not applied by chainsaw), so it is # not part of automatic cleanup — delete it explicitly, as BATS does. finally: - delete: ref: apiVersion: batch/v1 kind: Job name: postgres-test-init-job # The Postgres CR itself was applied by chainsaw and is deleted (and waited # on) automatically during cleanup — no explicit teardown step needed. --- # Full barman-cloud backup -> to-copy RestoreJob round-trip, driving the # validated example scripts (examples/backups/postgres) as the harness so the # test and the documented flow can never drift. run-all.sh runs Bucket -> # source Postgres + sentinel row -> CNPG strategy + BackupClass -> ad-hoc # BackupJob (waits Succeeded) -> empty target Postgres + to-copy RestoreJob # (waits Succeeded) and asserts the sentinel round-tripped through S3 into the # restored copy — the in-cluster witness that a barman-cloud plugin backup is # both taken and restorable end to end. # # Runs in tenant-root, not the default tenant-test: the S3 client here is the # barman-cloud sidecar INSIDE the Postgres Pod, and the e2e tenant is created # isolated (hack/e2e-install-cozystack.bats) — its Cilium egress allowlist # blocks a tenant-test Pod from reaching tenant-root's seaweedfs, while a # tenant-root Pod reaches it over same-tenant egress. The harness targets the # in-cluster endpoint (S3_ENDPOINT below) instead of the BucketInfo external # ingress URL, which in CI is an unroutable placeholder, and trusts its # self-signed cert by copying the seaweedfs CA secret (seaweedfs-ca-cert, # auto-discovered from the cert-manager Certificate) into the per-app # endpointCA Secret. (The bucket suite's mc checks lean on the same # tenant-root seaweedfs, just from the test runner via port-forward.) apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: name: postgres-2-backup-roundtrip spec: namespace: tenant-root skipDelete: true catch: - events: {} - describe: apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease name: postgres-pg-src - describe: apiVersion: postgresql.cnpg.io/v1 kind: Cluster name: postgres-pg-src - describe: apiVersion: barmancloud.cnpg.io/v1 kind: ObjectStore - describe: apiVersion: backups.cozystack.io/v1alpha1 kind: BackupJob - describe: apiVersion: backups.cozystack.io/v1alpha1 kind: RestoreJob # The barman-cloud backup/WAL work runs in the cnpg Cluster Pods' sidecar; a # failed upload or TLS handshake leaves its error only in that Pod's log. - podLogs: selector: cnpg.io/cluster=postgres-pg-src tail: 200 steps: - name: run try: # The 25m budget is the whole documented flow: bucket provisioning, a # 2-replica source Postgres, the plugin base backup to S3, an empty target # app, and the purge + re-bootstrap restore (convention 6: justified # in-line). run-all.sh fails fast on terminal BackupJob/RestoreJob phases # and stalled HelmReleases rather than polling out the budget. - script: timeout: 25m content: | set -eu cd ../../.. [ -x examples/backups/postgres/run-all.sh ] || { echo "postgres backup example scripts not found at examples/backups/postgres" >&2; exit 1; } NAMESPACE="$NAMESPACE" S3_ENDPOINT="https://seaweedfs-s3.tenant-root:8333" \ examples/backups/postgres/run-all.sh check: ($error == null): true finally: # Resumes the driver-suspended HelmReleases before deleting the RestoreJob # so the apps are not stranded, then removes every resource the harness # created (chainsaw did not apply them, so they are not part of automatic # cleanup). - description: backup-flow cleanup script: timeout: 8m content: | set -eu cd ../../.. NAMESPACE="$NAMESPACE" examples/backups/postgres/cleanup.sh